Skip to content
This repository has been archived by the owner on Apr 20, 2023. It is now read-only.

Commit

Permalink
Merge pull request #2145 from dotnet/lakshanf/issue2066/telemetry
Browse files Browse the repository at this point in the history
Lakshanf/issue2066/telemetry
  • Loading branch information
eerhardt committed Apr 6, 2016
2 parents fa01c9a + 0d067be commit 965547b
Show file tree
Hide file tree
Showing 13 changed files with 259 additions and 48 deletions.
29 changes: 3 additions & 26 deletions src/Microsoft.DotNet.Cli.Utils/CommandContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ public static class Variables
public static readonly string AnsiPassThru = Prefix + "ANSI_PASS_THRU";
}

private static Lazy<bool> _verbose = new Lazy<bool>(() => GetBool(Variables.Verbose));
private static Lazy<bool> _ansiPassThru = new Lazy<bool>(() => GetBool(Variables.AnsiPassThru));
private static Lazy<bool> _verbose = new Lazy<bool>(() => Env.GetEnvironmentVariableAsBool(Variables.Verbose));
private static Lazy<bool> _ansiPassThru = new Lazy<bool>(() => Env.GetEnvironmentVariableAsBool(Variables.AnsiPassThru));

public static bool IsVerbose()
{
Expand All @@ -25,29 +25,6 @@ public static bool IsVerbose()
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;
}
}
}
}
}
5 changes: 5 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/Env.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,10 @@ public static string GetCommandPathFromRootPath(string rootPath, string commandN
{
return _environment.GetCommandPathFromRootPath(rootPath, commandName, extensions);
}

public static bool GetEnvironmentVariableAsBool(string name, bool defaultValue = false)
{
return _environment.GetEnvironmentVariableAsBool(name, defaultValue);
}
}
}
24 changes: 24 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/EnvironmentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,5 +93,29 @@ public string GetCommandPathFromRootPath(string rootPath, string commandName, IE

return GetCommandPathFromRootPath(rootPath, commandName, extensionsArr);
}

public bool GetEnvironmentVariableAsBool(string name, bool defaultValue)
{
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;
}
}

}
}
2 changes: 2 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/IEnvironmentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ public interface IEnvironmentProvider
string GetCommandPathFromRootPath(string rootPath, string commandName, params string[] extensions);

string GetCommandPathFromRootPath(string rootPath, string commandName, IEnumerable<string> extensions);

bool GetEnvironmentVariableAsBool(string name, bool defaultValue);
}
}
13 changes: 13 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/ITelemetry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;

namespace Microsoft.DotNet.Cli.Utils
{
public interface ITelemetry
{
void TrackEvent(string eventName, IDictionary<string, string> properties, IDictionary<string, double> measurements);
}
}
17 changes: 17 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/Product.cs
Original file line number Diff line number Diff line change
@@ -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<AssemblyInformationalVersionAttribute>();
return attr?.InformationalVersion;
}
}
}
125 changes: 125 additions & 0 deletions src/Microsoft.DotNet.Cli.Utils/Telemetry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using Microsoft.ApplicationInsights;
using Microsoft.Extensions.PlatformAbstractions;
using System.Diagnostics;

namespace Microsoft.DotNet.Cli.Utils
{
public class Telemetry : ITelemetry
{
private bool _isInitialized = false;
private TelemetryClient _client = null;

private Dictionary<string, string> _commonProperties = null;
private Dictionary<string, double> _commonMeasurements = null;

private const string InstrumentationKey = "74cc1c9e-3e6e-4d05-b3fc-dde9101d0254";
private const string TelemetryOptout = "DOTNET_CLI_TELEMETRY_OPTOUT";
private const string OSVersion = "OS Version";
private const string OSPlatform = "OS Platform";
private const string RuntimeId = "Runtime Id";
private const string ProductVersion = "Product Version";

public Telemetry()
{
bool optout = Env.GetEnvironmentVariableAsBool(TelemetryOptout);

if (optout)
{
return;
}

try
{
_client = new TelemetryClient();
_client.InstrumentationKey = InstrumentationKey;
_client.Context.Session.Id = Guid.NewGuid().ToString();

var runtimeEnvironment = PlatformServices.Default.Runtime;
_client.Context.Device.OperatingSystem = runtimeEnvironment.OperatingSystem;

_commonProperties = new Dictionary<string, string>();
_commonProperties.Add(OSVersion, runtimeEnvironment.OperatingSystemVersion);
_commonProperties.Add(OSPlatform, runtimeEnvironment.OperatingSystemPlatform.ToString());
_commonProperties.Add(RuntimeId, runtimeEnvironment.GetRuntimeIdentifier());
_commonProperties.Add(ProductVersion, Product.Version);
_commonMeasurements = new Dictionary<string, double>();

_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
Debug.Fail("Exception during telemetry initialization");
}
}

public void TrackEvent(string eventName, IDictionary<string, string> properties, IDictionary<string, double> measurements)
{
if (!_isInitialized)
{
return;
}

Dictionary<string, double> eventMeasurements = GetEventMeasures(measurements);
Dictionary<string, string> eventProperties = GetEventProperties(properties);

try
{
_client.TrackEvent(eventName, eventProperties, eventMeasurements);
_client.Flush();
}
catch (Exception)
{
Debug.Fail("Exception during TrackEvent");
}
}


private Dictionary<string, double> GetEventMeasures(IDictionary<string, double> measurements)
{
Dictionary<string, double> eventMeasurements = new Dictionary<string, double>(_commonMeasurements);
if (measurements != null)
{
foreach (var measurement in measurements)
{
if (eventMeasurements.ContainsKey(measurement.Key))
{
eventMeasurements[measurement.Key] = measurement.Value;
}
else
{
eventMeasurements.Add(measurement.Key, measurement.Value);
}
}
}
return eventMeasurements;
}

private Dictionary<string, string> GetEventProperties(IDictionary<string, string> properties)
{
if (properties != null)
{
var eventProperties = new Dictionary<string, string>(_commonProperties);
foreach (var property in properties)
{
if (eventProperties.ContainsKey(property.Key))
{
eventProperties[property.Key] = property.Value;
}
else
{
eventProperties.Add(property.Key, property.Value);
}
}
return eventProperties;
}
else
{
return _commonProperties;
}
}
}
}
1 change: 1 addition & 0 deletions src/Microsoft.DotNet.Cli.Utils/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -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-1130",
Expand Down
35 changes: 24 additions & 11 deletions src/dotnet/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,13 @@ namespace Microsoft.DotNet.Cli
{
public class Program
{

public static int Main(string[] args)
{
DebugHelper.HandleDebugSwitch(ref args);

try
{
return ProcessArgs(args);
return Program.ProcessArgs(args, new Telemetry());
}
catch (CommandUnknownException e)
{
Expand All @@ -44,7 +43,7 @@ public static int Main(string[] args)

}

private static int ProcessArgs(string[] args)
internal static int ProcessArgs(string[] args, ITelemetry telemetryClient)
{
// CommandLineApplication is a bit restrictive, so we parse things ourselves here. Individual apps should use CLA.

Expand Down Expand Up @@ -117,22 +116,36 @@ private static int ProcessArgs(string[] args)
["test"] = TestCommand.Run
};

int exitCode;
Func<string[], int> builtIn;
if (builtIns.TryGetValue(command, out builtIn))
{
return builtIn(appArgs.ToArray());
exitCode = builtIn(appArgs.ToArray());
}
else
{
CommandResult result = Command.Create("dotnet-" + command, appArgs, FrameworkConstants.CommonFrameworks.NetStandardApp15)
.ForwardStdErr()
.ForwardStdOut()
.Execute();
exitCode = result.ExitCode;
}

return Command.Create("dotnet-" + command, appArgs, FrameworkConstants.CommonFrameworks.NetStandardApp15)
.ForwardStdErr()
.ForwardStdOut()
.Execute()
.ExitCode;
telemetryClient.TrackEvent(
command,
null,
new Dictionary<string, double>
{
["ExitCode"] = exitCode
});

return exitCode;

}

private static void PrintVersion()
{
Reporter.Output.WriteLine(HelpCommand.ProductVersion);
Reporter.Output.WriteLine(Product.Version);
}

private static void PrintInfo()
Expand All @@ -142,7 +155,7 @@ private static void PrintInfo()
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;
Expand Down
3 changes: 3 additions & 0 deletions src/dotnet/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("dotnet.Tests")]
14 changes: 3 additions & 11 deletions src/dotnet/commands/dotnet-help/HelpCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -29,13 +28,6 @@ public class HelpCommand
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<AssemblyInformationalVersionAttribute>();
return attr?.InformationalVersion;
}

public static int Run(string[] args)
{
Expand All @@ -58,10 +50,10 @@ public static void PrintHelp()

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);
}
}
}
Loading

0 comments on commit 965547b

Please sign in to comment.