mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-02-10 10:12:39 -05:00
Added AzureMonitor to Microsoft.Kusto.ServiceLayer (#1208)
* Added AzureMonitor to Microsoft.Kusto.ServiceLayer. * Added Intellisense for AzureMonitor. Moved Intellisense logic from KustoIntellisenseClient to IntellisenseClientBase. * Added ServiceName as a command parameter for starting Kusto. * Added check to return null if connectionInfo is not in the connectionService. * Added support for Dashboard in MetadataService and AdminService. * Removed workspace id from databaseName for Monitor. Added logic for MetadataService and AdminService to return different information for AzureMonitor. * Moved providerName and providerDescription to DataSourceFactory. * Changed DatabaseName to include Name and Id. Changed ProviderName to LOGANALYTICS in DataSourceFactory * Fixed unit tests * Changed logic to use ServiceName instead of server to determine DataSourceType * Code review feedback and reverted changes to ObjectExplorerService. * Removed unused reference from HostLoader * Changed Parallel.Invoke to await Task.Run * Moved Kusto datasource and supporting classes to separate directory. * Removed unused datasourceFactory from ConnectionService. Added GetDatabases and GetDatabaseInfo to IDataSource and child classes * Renamed Instance variables in ObjectExplorerService. Removed unused attribute on TSqlFormatterService. Removed invalid comment in ConnectionService. * Fixed warnings in build. * Moved SizeInMB to DatabaseMetadata. Refactored ConvertToDatabaseInfo * Fixed unit test
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Kusto.ServiceLayer.Admin.Contracts;
|
||||
using Microsoft.Kusto.ServiceLayer.Connection.Contracts;
|
||||
using Microsoft.Kusto.ServiceLayer.DataSource.Intellisense;
|
||||
using Microsoft.Kusto.ServiceLayer.DataSource.Metadata;
|
||||
using Microsoft.Kusto.ServiceLayer.DataSource.Monitor.Responses;
|
||||
using Microsoft.Kusto.ServiceLayer.DataSource.Monitor.Responses.Models;
|
||||
using Microsoft.Kusto.ServiceLayer.LanguageServices;
|
||||
using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts;
|
||||
using Microsoft.Kusto.ServiceLayer.Workspace.Contracts;
|
||||
|
||||
namespace Microsoft.Kusto.ServiceLayer.DataSource.Monitor
|
||||
{
|
||||
public class MonitorDataSource : DataSourceBase
|
||||
{
|
||||
private readonly MonitorClient _monitorClient;
|
||||
private readonly IntellisenseClientBase _intellisenseClient;
|
||||
private WorkspaceResponse _metadata;
|
||||
private Dictionary<string, List<DataSourceObjectMetadata>> _nodes;
|
||||
|
||||
public override string ClusterName => _monitorClient.WorkspaceId;
|
||||
public override string DatabaseName { get; set; }
|
||||
|
||||
public MonitorDataSource(MonitorClient monitorClient, IntellisenseClientBase intellisenseClient)
|
||||
{
|
||||
_monitorClient = monitorClient;
|
||||
_intellisenseClient = intellisenseClient;
|
||||
_nodes = new Dictionary<string, List<DataSourceObjectMetadata>>();
|
||||
_metadata = _monitorClient.LoadMetadata();
|
||||
DataSourceType = DataSourceType.LogAnalytics;
|
||||
SetupTableGroups(monitorClient.WorkspaceId);
|
||||
}
|
||||
|
||||
private void SetupTableGroups(string workspaceId)
|
||||
{
|
||||
var workspace = _metadata.Workspaces.First(x => x.Id == workspaceId);
|
||||
DatabaseName = $"{workspace.Name} ({workspace.Id})";
|
||||
var metadataTableGroups = _metadata.TableGroups.ToDictionary(x => x.Id);
|
||||
|
||||
foreach (string workspaceTableGroup in workspace.TableGroups)
|
||||
{
|
||||
var tableGroup = metadataTableGroups[workspaceTableGroup];
|
||||
|
||||
var tableGroupNodeInfo =
|
||||
MetadataFactory.CreateDataSourceObjectMetadata(DataSourceMetadataType.Folder, tableGroup.Name, $"{workspace.Id}.{tableGroup.Name}");
|
||||
|
||||
_nodes.SafeAdd($"{workspace.Id}", tableGroupNodeInfo);
|
||||
|
||||
SetupTables(tableGroupNodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupTables(DataSourceObjectMetadata tableGroupNodeInfo)
|
||||
{
|
||||
var tables = GetNonEmptyTableNames();
|
||||
var metadataTables = _metadata.Tables.ToDictionary(x => x.Name);
|
||||
|
||||
foreach (string tableName in tables)
|
||||
{
|
||||
var table = metadataTables[tableName];
|
||||
|
||||
var tableNodeInfo = MetadataFactory.CreateDataSourceObjectMetadata(DataSourceMetadataType.Table, table.Name,
|
||||
$"{tableGroupNodeInfo.Urn}.{table.Name}");
|
||||
|
||||
_nodes.SafeAdd(tableGroupNodeInfo.Urn, tableNodeInfo);
|
||||
|
||||
SetupColumns(table, tableNodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetNonEmptyTableNames()
|
||||
{
|
||||
string query = "union * | summarize count() by Type";
|
||||
var results = _monitorClient.Query(query);
|
||||
return results.Tables[0].Rows.Select(x => x[0]).OrderBy(x => x);
|
||||
}
|
||||
|
||||
private void SetupColumns(TablesModel table, DataSourceObjectMetadata tableNodeInfo)
|
||||
{
|
||||
foreach (var column in table.Columns)
|
||||
{
|
||||
var columnNodeInfo = MetadataFactory.CreateDataSourceObjectMetadata(DataSourceMetadataType.Column, column.Name,
|
||||
$"{tableNodeInfo.Urn}.{column.Name}");
|
||||
|
||||
_nodes.SafeAdd(tableNodeInfo.Urn, columnNodeInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public override async Task<IDataReader> ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null)
|
||||
{
|
||||
var results = await _monitorClient.QueryAsync(query, cancellationToken);
|
||||
return results.ToDataReader();
|
||||
}
|
||||
|
||||
public override Task<IEnumerable<T>> ExecuteControlCommandAsync<T>(string command, bool throwOnError, CancellationToken cancellationToken)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata parentMetadata)
|
||||
{
|
||||
return new DiagnosticsInfo();
|
||||
}
|
||||
|
||||
public override IEnumerable<DataSourceObjectMetadata> GetChildObjects(DataSourceObjectMetadata parentMetadata, bool includeSizeDetails = false)
|
||||
{
|
||||
// columns are always leaf nodes
|
||||
if (parentMetadata.MetadataType == DataSourceMetadataType.Column)
|
||||
{
|
||||
return Enumerable.Empty<DataSourceObjectMetadata>();
|
||||
}
|
||||
|
||||
if (parentMetadata.MetadataType == DataSourceMetadataType.Cluster && includeSizeDetails)
|
||||
{
|
||||
var child = _nodes[parentMetadata.Urn].FirstOrDefault();
|
||||
return child == null ? Enumerable.Empty<DataSourceObjectMetadata>() : _nodes[child.Urn];
|
||||
}
|
||||
|
||||
return _nodes[parentMetadata.Urn].OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public override void Refresh(bool includeDatabase)
|
||||
{
|
||||
// reset the data source
|
||||
_nodes = new Dictionary<string, List<DataSourceObjectMetadata>>();
|
||||
_metadata = _monitorClient.LoadMetadata();
|
||||
SetupTableGroups(_monitorClient.WorkspaceId);
|
||||
}
|
||||
|
||||
public override void Refresh(DataSourceObjectMetadata objectMetadata)
|
||||
{
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
public override void UpdateDatabase(string databaseName)
|
||||
{
|
||||
// LogAnalytics is treating the workspace name as the database name
|
||||
var workspaceId = ParseWorkspaceId(databaseName);
|
||||
_metadata = _monitorClient.LoadMetadata(true);
|
||||
var workspace = _metadata.Workspaces.First(x => x.Id == workspaceId);
|
||||
DatabaseName = $"{workspace.Name} ({workspace.Id})";
|
||||
_intellisenseClient.UpdateDatabase(databaseName);
|
||||
}
|
||||
|
||||
private string ParseWorkspaceId(string workspace)
|
||||
{
|
||||
var regex = new Regex(@"(?<=\().+?(?=\))");
|
||||
|
||||
return regex.IsMatch(workspace)
|
||||
? regex.Match(workspace).Value
|
||||
: workspace;
|
||||
}
|
||||
|
||||
public override Task<bool> Exists()
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
public override bool Exists(DataSourceObjectMetadata objectMetadata)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string GenerateAlterFunctionScript(string functionName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string GenerateExecuteFunctionScript(string functionName)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText)
|
||||
{
|
||||
return _intellisenseClient.GetSemanticMarkers(parseInfo, scriptFile, queryText);
|
||||
}
|
||||
|
||||
public override DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false)
|
||||
{
|
||||
return _intellisenseClient.GetDefinition(queryText, index, startLine, startColumn, throwOnError);
|
||||
}
|
||||
|
||||
public override Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
|
||||
{
|
||||
return _intellisenseClient.GetHoverHelp(scriptDocumentInfo, textPosition, throwOnError);
|
||||
}
|
||||
|
||||
public override CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false)
|
||||
{
|
||||
return _intellisenseClient.GetAutoCompleteSuggestions(scriptDocumentInfo, textPosition, throwOnError);
|
||||
}
|
||||
|
||||
public override ListDatabasesResponse GetDatabases(string serverName, bool includeDetails)
|
||||
{
|
||||
return new ListDatabasesResponse
|
||||
{
|
||||
DatabaseNames = new[]
|
||||
{
|
||||
DatabaseName
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override DatabaseInfo GetDatabaseInfo(string serverName, string databaseName)
|
||||
{
|
||||
return new DatabaseInfo
|
||||
{
|
||||
Options = new Dictionary<string, object>
|
||||
{
|
||||
{"id", ClusterName},
|
||||
{"name", DatabaseName}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user