From a37093a773ab92d646768005be1b834a217c66a8 Mon Sep 17 00:00:00 2001 From: Leila Lali Date: Tue, 11 Apr 2023 14:22:05 -0700 Subject: [PATCH] Enabling DacFx telemetry (#1993) * Enabling DacFx telemetry --- .../DacFx/DacFxService.cs | 65 +++++++++++++++++-- .../DacFx/DacFxUtils.cs | 5 +- .../HostLoader.cs | 2 +- .../SqlContext/SqlToolsSettings.cs | 18 +++++ .../SqlContext/TelemetryLevel.cs | 15 +++++ .../SqlContext/TelemetrySettingsValues.cs | 18 +++++ .../TableDesigner/TableDesignerService.cs | 2 +- 7 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetryLevel.cs create mode 100644 src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetrySettingsValues.cs diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs index 10976b22..375f5c8e 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxService.cs @@ -3,19 +3,21 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. // -#nullable disable using System; using System.Collections.Concurrent; +using System.Diagnostics; using System.Threading.Tasks; using Microsoft.SqlServer.Dac; +using Microsoft.SqlServer.Dac.Model; using Microsoft.SqlTools.Hosting.Protocol; using Microsoft.SqlTools.ServiceLayer.Connection; using Microsoft.SqlTools.ServiceLayer.DacFx.Contracts; using Microsoft.SqlTools.ServiceLayer.Hosting; +using Microsoft.SqlTools.ServiceLayer.SqlContext; using Microsoft.SqlTools.ServiceLayer.TaskServices; -using Microsoft.SqlServer.Dac.Model; -using DacTableDesigner = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner.TableDesigner; using Microsoft.SqlTools.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; +using DacTableDesigner = Microsoft.Data.Tools.Sql.DesignServices.TableDesigner.TableDesigner; namespace Microsoft.SqlTools.ServiceLayer.DacFx { @@ -27,6 +29,9 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx private static ConnectionService connectionService = null; private SqlTaskManager sqlTaskManagerInstance = null; private static readonly Lazy instance = new Lazy(() => new DacFxService()); + private static Version? serviceVersion = LoadServiceVersion(); + private const string TelemetryDefaultApplicationName = "sqltoolsservice"; + private string telemetryApplicationName = TelemetryDefaultApplicationName; private readonly Lazy> operations = new Lazy>(() => new ConcurrentDictionary()); /// @@ -47,7 +52,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx /// Initializes the service instance /// /// - public void InitializeService(ServiceHost serviceHost) + public void InitializeService(ServiceHost serviceHost, ServiceLayerCommandOptions commandOptions) { serviceHost.SetRequestHandler(ExportRequest.Type, this.HandleExportRequest, true); serviceHost.SetRequestHandler(ImportRequest.Type, this.HandleImportRequest, true); @@ -62,6 +67,15 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx serviceHost.SetRequestHandler(GenerateTSqlModelRequest.Type, this.HandleGenerateTSqlModelRequest, true); serviceHost.SetRequestHandler(GetObjectsFromTSqlModelRequest.Type, this.HandleGetObjectsFromTSqlModelRequest, true); serviceHost.SetRequestHandler(SavePublishProfileRequest.Type, this.HandleSavePublishProfileRequest, true); + Workspace.WorkspaceService.Instance.RegisterConfigChangeCallback(UpdateSettings); + telemetryApplicationName = string.IsNullOrEmpty(commandOptions?.ApplicationName) ? TelemetryDefaultApplicationName : commandOptions.ApplicationName; + } + + internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) + { + // Update telemetry status in DacFx service + UpdateTelemetryStatus(newSettings.TelemetrySettings.Telemetry != TelemetryLevel.Off); + return Task.CompletedTask; } /// @@ -341,7 +355,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx profile.Save(parameters.ProfilePath); } }, requestContext); - + return; } @@ -416,5 +430,46 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx { operation.Execute(taskExecutionMode); } + + /// + /// Changes telemetry status + /// + private void UpdateTelemetryStatus(bool telemetryEnabled) + { + try + { + if (telemetryEnabled) + { + DacServices.EnableTelemetry(telemetryApplicationName, serviceVersion); + } + else + { + DacServices.DisableTelemetry(); + } + + } + catch (Exception ex) + { + Logger.Warning($"Failed to update DacFx telemetry status. telemetry enable: {telemetryEnabled}, error: {ex.Message}"); + } + } + + private static Version? LoadServiceVersion() + { + try + { + string fileVersion = FileVersionInfo.GetVersionInfo(System.Reflection.Assembly.GetExecutingAssembly().Location).FileVersion; + if (Version.TryParse(fileVersion, out Version version)) + { + return version; + } + return null; + } + catch (Exception ex) + { + Logger.Warning($"Failed to load assembly version: error: {ex.Message}"); + return null; + } + } } } diff --git a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxUtils.cs b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxUtils.cs index ff623fc6..b40a8f4c 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxUtils.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/DacFx/DacFxUtils.cs @@ -20,10 +20,11 @@ namespace Microsoft.SqlTools.ServiceLayer.DacFx /// /// /// DacDeployOptions finalExcludeObjects = new List { }; var val = deployOptionsProp.GetValue(deploymentOptions); - string[] excludeObjectTypeOptionsArray = (string[])val.GetType().GetProperty("Value").GetValue(val); + string[] excludeObjectTypeOptionsArray = (string[])val?.GetType()?.GetProperty("Value")?.GetValue(val); if (excludeObjectTypeOptionsArray != null) { diff --git a/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs index 1bc46184..540f2877 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/HostLoader.cs @@ -133,7 +133,7 @@ namespace Microsoft.SqlTools.ServiceLayer SecurityService.Instance.InitializeService(serviceHost); serviceProvider.RegisterSingleService(SecurityService.Instance); - DacFxService.Instance.InitializeService(serviceHost); + DacFxService.Instance.InitializeService(serviceHost, commandOptions); serviceProvider.RegisterSingleService(DacFxService.Instance); CmsService.Instance.InitializeService(serviceHost); diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs index 58fcef9f..b7c0eed0 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/SqlToolsSettings.cs @@ -17,6 +17,7 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext private ISqlToolsSettingsValues sqlTools = null; private SqlToolsSettingsValues mssqlTools = null; private SqlToolsSettingsValues allSqlTools = null; + private TelemetrySettingsValues telemetrySettings = null; public ISqlToolsSettingsValues SqlTools { @@ -65,6 +66,23 @@ namespace Microsoft.SqlTools.ServiceLayer.SqlContext } } + /// + /// Gets or sets the underlying settings value object + /// + [JsonProperty("telemetry")] + public TelemetrySettingsValues TelemetrySettings + { + get + { + this.telemetrySettings ??= new TelemetrySettingsValues(); + return this.telemetrySettings; + } + set + { + this.telemetrySettings = value; + } + } + /// /// Query execution settings forwarding property /// diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetryLevel.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetryLevel.cs new file mode 100644 index 00000000..b8ec3844 --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetryLevel.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.SqlTools.ServiceLayer.SqlContext +{ + public enum TelemetryLevel + { + All, + Error, + Crash, + Off + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetrySettingsValues.cs b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetrySettingsValues.cs new file mode 100644 index 00000000..d527fc6c --- /dev/null +++ b/src/Microsoft.SqlTools.ServiceLayer/SqlContext/TelemetrySettingsValues.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Newtonsoft.Json; + +namespace Microsoft.SqlTools.ServiceLayer.SqlContext +{ + public class TelemetrySettingsValues + { + /// + /// Gets or sets the telemetry level setting + /// + [JsonProperty("telemetryLevel")] + public TelemetryLevel Telemetry { get; set; } + } +} diff --git a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs index 63a4953e..84b5b133 100644 --- a/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs +++ b/src/Microsoft.SqlTools.ServiceLayer/TableDesigner/TableDesignerService.cs @@ -72,7 +72,7 @@ namespace Microsoft.SqlTools.ServiceLayer.TableDesigner internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) { - Settings.PreloadDatabaseModel = newSettings.MssqlTools.TableDesigner.PreloadDatabaseModel; + Settings.PreloadDatabaseModel = newSettings.MssqlTools.TableDesigner != null ? newSettings.MssqlTools.TableDesigner.PreloadDatabaseModel : false; return Task.FromResult(0); }