diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 4a6641ba2..46ef6e129 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -135,6 +135,8 @@ namespace Microsoft.DotNet.Cli command = "help"; } + telemetryClient.TrackEvent(command, null, null); + int exitCode; Func builtIn; if (s_builtIns.TryGetValue(command, out builtIn)) @@ -150,13 +152,6 @@ namespace Microsoft.DotNet.Cli exitCode = result.ExitCode; } - telemetryClient.TrackEvent( - command, - null, - new Dictionary - { - ["ExitCode"] = exitCode - }); return exitCode; diff --git a/src/dotnet/Telemetry.cs b/src/dotnet/Telemetry.cs index dc3a457f3..e9e0383fb 100644 --- a/src/dotnet/Telemetry.cs +++ b/src/dotnet/Telemetry.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Threading.Tasks; using Microsoft.ApplicationInsights; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.InternalAbstractions; @@ -17,13 +18,18 @@ namespace Microsoft.DotNet.Cli private Dictionary _commonProperties = null; private Dictionary _commonMeasurements = null; + private Task _trackEventTask = null; + + private string _telemetryProfile; private const string InstrumentationKey = "74cc1c9e-3e6e-4d05-b3fc-dde9101d0254"; private const string TelemetryOptout = "DOTNET_CLI_TELEMETRY_OPTOUT"; + private const string TelemetryProfileEnvironmentVariable = "DOTNET_CLI_TELEMETRY_PROFILE"; private const string OSVersion = "OS Version"; private const string OSPlatform = "OS Platform"; private const string RuntimeId = "Runtime Id"; private const string ProductVersion = "Product Version"; + private const string TelemetryProfile = "Telemetry Profile"; public bool Enabled { get; } @@ -36,60 +42,73 @@ namespace Microsoft.DotNet.Cli return; } + _telemetryProfile = Environment.GetEnvironmentVariable(TelemetryProfileEnvironmentVariable); + + //initialize in task to offload to parallel thread + _trackEventTask = Task.Factory.StartNew(() => InitializeTelemetry()); + } + + public void TrackEvent(string eventName, IDictionary properties, IDictionary measurements) + { + if (!Enabled) + { + return; + } + + //continue task in existing parallel thread + _trackEventTask = _trackEventTask.ContinueWith( + x => TrackEventTask(eventName, properties, measurements) + ); + } + + private void InitializeTelemetry() + { try { - using (PerfTrace.Current.CaptureTiming()) - { - _client = new TelemetryClient(); - _client.InstrumentationKey = InstrumentationKey; - _client.Context.Session.Id = Guid.NewGuid().ToString(); - + _client = new TelemetryClient(); + _client.InstrumentationKey = InstrumentationKey; + _client.Context.Session.Id = Guid.NewGuid().ToString(); _client.Context.Device.OperatingSystem = RuntimeEnvironment.OperatingSystem; - _commonProperties = new Dictionary(); + _commonProperties = new Dictionary(); _commonProperties.Add(OSVersion, RuntimeEnvironment.OperatingSystemVersion); _commonProperties.Add(OSPlatform, RuntimeEnvironment.OperatingSystemPlatform.ToString()); _commonProperties.Add(RuntimeId, RuntimeEnvironment.GetRuntimeIdentifier()); - _commonProperties.Add(ProductVersion, Product.Version); - _commonMeasurements = new Dictionary(); - } - + _commonProperties.Add(ProductVersion, Product.Version); + _commonProperties.Add(TelemetryProfile, _telemetryProfile); + _commonMeasurements = new Dictionary(); _isInitialized = true; } catch (Exception) { - // we dont want to fail the tool if telemetry fais. We should be able to detect abnormalities from data - // at the server end + _isInitialized = false; + // we dont want to fail the tool if telemetry fails. Debug.Fail("Exception during telemetry initialization"); } } - public void TrackEvent(string eventName, IDictionary properties, IDictionary measurements) + private void TrackEventTask(string eventName, IDictionary properties, IDictionary measurements) { if (!_isInitialized) { return; } - using (PerfTrace.Current.CaptureTiming()) + try { - Dictionary eventMeasurements = GetEventMeasures(measurements); - Dictionary eventProperties = GetEventProperties(properties); + var eventProperties = GetEventProperties(properties); + var eventMeasurements = GetEventMeasures(measurements); - try - { - _client.TrackEvent(eventName, eventProperties, eventMeasurements); - _client.Flush(); - } - catch (Exception) - { - Debug.Fail("Exception during TrackEvent"); - } + _client.TrackEvent(eventName, eventProperties, eventMeasurements); + _client.Flush(); + } + catch (Exception) + { + Debug.Fail("Exception during TrackEventTask"); } } - private Dictionary GetEventMeasures(IDictionary measurements) { Dictionary eventMeasurements = new Dictionary(_commonMeasurements); @@ -128,9 +147,9 @@ namespace Microsoft.DotNet.Cli } return eventProperties; } - else + else { - return _commonProperties; + return _commonProperties; } } } diff --git a/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms.cs b/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms.cs index dd25f1dbe..765afe4b6 100644 --- a/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms.cs +++ b/test/dotnet-test.Tests/GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms.cs @@ -3,6 +3,7 @@ using System.IO; using System.Linq; +using System.Runtime.CompilerServices; using FluentAssertions; using Microsoft.DotNet.InternalAbstractions; using Microsoft.DotNet.ProjectModel; @@ -14,13 +15,13 @@ namespace Microsoft.Dotnet.Tools.Test.Tests { public class GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms : TestBase { - private readonly string _projectFilePath; - private readonly string _netCoreAppOutputPath; - private readonly string _net451OutputPath; + private string _projectFilePath; + private string _netCoreAppOutputPath; + private string _net451OutputPath; - public GivenThatWeWantToUseDotnetTestE2EInDesignTimeForMultipleTFms() + private void Setup([CallerMemberName] string callingMethod = "") { - var testInstance = TestAssetsManager.CreateTestInstance(Path.Combine("ProjectsWithTests", "MultipleFrameworkProject")); + var testInstance = TestAssetsManager.CreateTestInstance(Path.Combine("ProjectsWithTests", "MultipleFrameworkProject"), callingMethod); _projectFilePath = Path.Combine(testInstance.TestRoot, "project.json"); var contexts = ProjectContext.CreateContextForEachFramework( @@ -51,6 +52,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests [WindowsOnlyFact] public void It_discovers_tests_for_the_ProjectWithTestsWithNetCoreApp() { + Setup(); + using (var adapter = new Adapter("TestDiscovery.Start")) { adapter.Listen(); @@ -68,6 +71,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests [WindowsOnlyFact] public void It_discovers_tests_for_the_ProjectWithTestsWithNet451() { + Setup(); + using (var adapter = new Adapter("TestDiscovery.Start")) { adapter.Listen(); @@ -86,6 +91,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests [Fact] public void It_runs_tests_for_netcoreapp10() { + Setup(); + using (var adapter = new Adapter("TestExecution.GetTestRunnerProcessStartInfo")) { adapter.Listen(); @@ -105,6 +112,8 @@ namespace Microsoft.Dotnet.Tools.Test.Tests [WindowsOnlyFact] public void It_runs_tests_for_net451() { + Setup(); + using (var adapter = new Adapter("TestExecution.GetTestRunnerProcessStartInfo")) { adapter.Listen();