diff --git a/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs b/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs index 28a7aaa3e..1776d3ebf 100644 --- a/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs +++ b/src/Microsoft.DotNet.Cli.Utils/CommandContext.cs @@ -14,8 +14,8 @@ namespace Microsoft.DotNet.Cli.Utils public static readonly string AnsiPassThru = Prefix + "ANSI_PASS_THRU"; } - private static Lazy _verbose = new Lazy(() => GetBool(Variables.Verbose)); - private static Lazy _ansiPassThru = new Lazy(() => GetBool(Variables.AnsiPassThru)); + private static Lazy _verbose = new Lazy(() => Env.GetBool(Variables.Verbose)); + private static Lazy _ansiPassThru = new Lazy(() => Env.GetBool(Variables.AnsiPassThru)); public static bool IsVerbose() { @@ -25,29 +25,6 @@ namespace Microsoft.DotNet.Cli.Utils public static bool ShouldPassAnsiCodesThrough() { return _ansiPassThru.Value; - } - - private static bool GetBool(string name, bool defaultValue = false) - { - var str = Environment.GetEnvironmentVariable(name); - if (string.IsNullOrEmpty(str)) - { - return defaultValue; - } - - switch (str.ToLowerInvariant()) - { - case "true": - case "1": - case "yes": - return true; - case "false": - case "0": - case "no": - return false; - default: - return defaultValue; - } - } + } } } diff --git a/src/Microsoft.DotNet.Cli.Utils/Env.cs b/src/Microsoft.DotNet.Cli.Utils/Env.cs index 30a117bcc..96cfd2d1e 100644 --- a/src/Microsoft.DotNet.Cli.Utils/Env.cs +++ b/src/Microsoft.DotNet.Cli.Utils/Env.cs @@ -33,5 +33,29 @@ namespace Microsoft.DotNet.Cli.Utils { return _environment.GetCommandPathFromRootPath(rootPath, commandName, extensions); } + + public static bool GetBool(string name, bool defaultValue = false) + { + var str = Environment.GetEnvironmentVariable(name); + if (string.IsNullOrEmpty(str)) + { + return defaultValue; + } + + switch (str.ToLowerInvariant()) + { + case "true": + case "1": + case "yes": + return true; + case "false": + case "0": + case "no": + return false; + default: + return defaultValue; + } + } + } } diff --git a/src/Microsoft.DotNet.Cli.Utils/Product.cs b/src/Microsoft.DotNet.Cli.Utils/Product.cs new file mode 100644 index 000000000..8d2a8f05b --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/Product.cs @@ -0,0 +1,17 @@ +using System; +using System.Reflection; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class Product + { + public static readonly string LongName = ".NET Command Line Tools"; + public static readonly string Version = GetProductVersion(); + + private static string GetProductVersion() + { + var attr = typeof(Product).GetTypeInfo().Assembly.GetCustomAttribute(); + return attr?.InformationalVersion; + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/Telemetry.cs b/src/Microsoft.DotNet.Cli.Utils/Telemetry.cs new file mode 100644 index 000000000..2a2bab2d1 --- /dev/null +++ b/src/Microsoft.DotNet.Cli.Utils/Telemetry.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using Microsoft.ApplicationInsights; +using Microsoft.Extensions.PlatformAbstractions; + +namespace Microsoft.DotNet.Cli.Utils +{ + public class Telemetry + { + private class Variables + { + public static readonly string InstrumentationKey = "74cc1c9e-3e6e-4d05-b3fc-dde9101d0254"; + private static readonly string Prefix = "DOTNET_CLI_TELEMETRY_"; + public static readonly string Optout = Prefix + "OPTOUT"; + } + + private class Properties + { + public static readonly string OSVersion = "OS Version"; + public static readonly string OSPlatform = "OS Platform"; + public static readonly string RuntimeId = "Runtime Id"; + public static readonly string ProductVersion = "Product Version"; + } + + private static bool _isInitialized = false; + private static TelemetryClient _client = null; + + private static Dictionary _commonProperties = null; + private static Dictionary _commonMeasurements = null; + + static Telemetry() + { + if (_isInitialized) + return; + + bool Optout = Env.GetBool(Variables.Optout); + + if (Optout) + return; + + try + { + _client = new TelemetryClient(); + _client.InstrumentationKey = Variables.InstrumentationKey; + _client.Context.Session.Id = Guid.NewGuid().ToString(); + + var runtimeEnvironment = PlatformServices.Default.Runtime; + _client.Context.Device.OperatingSystem = runtimeEnvironment.OperatingSystem; + + _commonProperties = new Dictionary(); + _commonProperties.Add(Properties.OSVersion, runtimeEnvironment.OperatingSystemVersion); + _commonProperties.Add(Properties.OSPlatform, runtimeEnvironment.OperatingSystemPlatform.ToString()); + _commonProperties.Add(Properties.RuntimeId, runtimeEnvironment.GetRuntimeIdentifier()); + _commonProperties.Add(Properties.ProductVersion, Product.Version); + _commonMeasurements = new Dictionary(); + + _isInitialized = true; + } + catch (Exception) { } + } + + public static void TrackCommand(string command, IDictionary properties = null, IDictionary measurements = null) + { + if (!_isInitialized) + return; + + Dictionary eventProperties = new Dictionary(_commonProperties); + if (properties != null) + { + foreach (var p in properties) + { + if (eventProperties.ContainsKey(p.Key)) + eventProperties[p.Key] = p.Value; + else + eventProperties.Add(p.Key, p.Value); + } + } + + Dictionary eventMeasurements = new Dictionary(_commonMeasurements); + if (measurements != null) + { + foreach (var m in measurements) + { + if (eventMeasurements.ContainsKey(m.Key)) + eventMeasurements[m.Key] = m.Value; + else + eventMeasurements.Add(m.Key, m.Value); + } + } + + try + { + _client.TrackEvent(command, eventProperties, eventMeasurements); + _client.Flush(); + } + catch (Exception) { } + } + } +} diff --git a/src/Microsoft.DotNet.Cli.Utils/project.json b/src/Microsoft.DotNet.Cli.Utils/project.json index 6519d4aa7..fc6959f60 100644 --- a/src/Microsoft.DotNet.Cli.Utils/project.json +++ b/src/Microsoft.DotNet.Cli.Utils/project.json @@ -5,6 +5,7 @@ "warningsAsErrors": true }, "dependencies": { + "Microsoft.ApplicationInsights": "2.0.0-rc1", "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.Extensions.PlatformAbstractions": "1.0.0-rc2-20100", "NuGet.Versioning": "3.5.0-beta-1123", diff --git a/src/dotnet/Program.cs b/src/dotnet/Program.cs index 7d8e02cb3..6659f000f 100644 --- a/src/dotnet/Program.cs +++ b/src/dotnet/Program.cs @@ -117,22 +117,47 @@ namespace Microsoft.DotNet.Cli ["test"] = TestCommand.Run }; + int exitCode = 100; + + string arguments = string.Empty; + + Func builtIn; if (builtIns.TryGetValue(command, out builtIn)) { - return builtIn(appArgs.ToArray()); + exitCode = builtIn(appArgs.ToArray()); + + appArgs.ToList().ForEach(a => { arguments += a + " "; }); + + } + else + { + CommandResult result = Command.Create("dotnet-" + command, appArgs, FrameworkConstants.CommonFrameworks.NetStandardApp15) + .ForwardStdErr() + .ForwardStdOut() + .Execute(); + arguments = result.StartInfo.Arguments; + exitCode = result.ExitCode; } - return Command.Create("dotnet-" + command, appArgs, FrameworkConstants.CommonFrameworks.NetStandardApp15) - .ForwardStdErr() - .ForwardStdOut() - .Execute() - .ExitCode; + Telemetry.TrackCommand( + command, + new Dictionary + { + ["Arguments"] = arguments + }, + new Dictionary + { + ["ExitCode"] = exitCode + }); + + return exitCode; + } - private static void PrintVersion() +private static void PrintVersion() { - Reporter.Output.WriteLine(HelpCommand.ProductVersion); + Reporter.Output.WriteLine(Product.Version); } private static void PrintInfo() @@ -142,7 +167,7 @@ namespace Microsoft.DotNet.Cli var commitSha = GetCommitSha() ?? "N/A"; Reporter.Output.WriteLine(); Reporter.Output.WriteLine("Product Information:"); - Reporter.Output.WriteLine($" Version: {HelpCommand.ProductVersion}"); + Reporter.Output.WriteLine($" Version: {Product.Version}"); Reporter.Output.WriteLine($" Commit Sha: {commitSha}"); Reporter.Output.WriteLine(); var runtimeEnvironment = PlatformServices.Default.Runtime; diff --git a/src/dotnet/commands/dotnet-help/HelpCommand.cs b/src/dotnet/commands/dotnet-help/HelpCommand.cs index c64735f31..30ecb35d0 100644 --- a/src/dotnet/commands/dotnet-help/HelpCommand.cs +++ b/src/dotnet/commands/dotnet-help/HelpCommand.cs @@ -8,7 +8,6 @@ namespace Microsoft.DotNet.Tools.Help { public class HelpCommand { - private const string ProductLongName = ".NET Command Line Tools"; private const string UsageText = @"Usage: dotnet [common-options] [command] [arguments] Arguments: @@ -29,13 +28,6 @@ Common Commands: test Executes tests in a test project repl Launch an interactive session (read, eval, print, loop) pack Creates a NuGet package"; - public static readonly string ProductVersion = GetProductVersion(); - - private static string GetProductVersion() - { - var attr = typeof(HelpCommand).GetTypeInfo().Assembly.GetCustomAttribute(); - return attr?.InformationalVersion; - } public static int Run(string[] args) { @@ -58,10 +50,10 @@ Common Commands: public static void PrintVersionHeader() { - var versionString = string.IsNullOrEmpty(ProductVersion) ? + var versionString = string.IsNullOrEmpty(Product.Version) ? string.Empty : - $" ({ProductVersion})"; - Reporter.Output.WriteLine(ProductLongName + versionString); + $" ({Product.Version})"; + Reporter.Output.WriteLine(Product.LongName + versionString); } } }