Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,7 @@ private PSModuleInfo ImportModule_LocallyViaName_WithTelemetry(ImportModuleOptio
// avoid double reporting for WinCompat modules that go through CommandDiscovery\AutoloadSpecifiedModule
if (!foundModule.IsWindowsPowerShellCompatModule)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule.Name, foundModule.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule);
#if LEGACYTELEMETRY
TelemetryAPI.ReportModuleLoad(foundModule);
#endif
Expand Down Expand Up @@ -893,7 +893,7 @@ private PSModuleInfo ImportModule_LocallyViaFQName(ImportModuleOptions importMod

if (foundModule != null)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule.Name, foundModule.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule);
SetModuleBaseForEngineModules(foundModule.Name, this.Context);
}

Expand Down Expand Up @@ -935,7 +935,7 @@ private IList<PSModuleInfo> ImportModule_RemotelyViaPsrpSession(
// Send telemetry on the imported modules
foreach (PSModuleInfo moduleInfo in remotelyImportedModules)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(usingWinCompat ? TelemetryType.WinCompatModuleLoad : TelemetryType.ModuleLoad, moduleInfo.Name, moduleInfo.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(usingWinCompat ? TelemetryType.WinCompatModuleLoad : TelemetryType.ModuleLoad, moduleInfo);
}

return remotelyImportedModules;
Expand Down Expand Up @@ -1866,7 +1866,7 @@ protected override void ProcessRecord()
// of doing Get-Module -list
foreach (PSModuleInfo module in ModuleInfo)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, module.Name, module.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, module);
RemoteDiscoveryHelper.DispatchModuleInfoProcessing(
module,
localAction: () =>
Expand Down Expand Up @@ -1926,7 +1926,7 @@ protected override void ProcessRecord()
ImportModule_RemotelyViaPsrpSession(importModuleOptions, null, FullyQualifiedName, this.PSSession);
foreach (ModuleSpecification modulespec in FullyQualifiedName)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, modulespec.Name, modulespec.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, modulespec.Name);
}
}
else if (this.ParameterSetName.Equals(ParameterSet_ViaWinCompat, StringComparison.OrdinalIgnoreCase)
Expand Down
59 changes: 53 additions & 6 deletions src/System.Management.Automation/utils/Telemetry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using System.Threading;

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Metrics;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.Extensibility.Implementation;
Expand Down Expand Up @@ -124,6 +127,9 @@ public static class ApplicationInsightsTelemetry
// Use '0.0' as the string for an anonymous module version
private const string AnonymousVersion = "0.0";

// Use 'n/a' as the string when there's no tag to report
private const string NoTag = "n/a";

// the telemetry failure string
private const string _telemetryFailure = "TELEMETRY_FAILURE";

Expand All @@ -140,9 +146,11 @@ public static class ApplicationInsightsTelemetry
private static int s_startupEventSent = 0;

/// Use a hashset for quick lookups.
/// We send telemetry only a known set of modules.
/// If it's not in the list (initialized in the static constructor), then we report anonymous.
/// We send telemetry only a known set of modules and tags.
/// If it's not in the list (initialized in the static constructor), then we report anonymous
/// or don't report anything (in the case of tags).
private static readonly HashSet<string> s_knownModules;
private static readonly HashSet<string> s_knownModuleTags;

/// <summary>Gets a value indicating whether telemetry can be sent.</summary>
public static bool CanSendTelemetry { get; private set; } = false;
Expand Down Expand Up @@ -601,6 +609,12 @@ static ApplicationInsightsTelemetry()
"xWindowsUpdate",
};

// use a hashset when looking for module names, it should be quicker than a string comparison
s_knownModuleTags = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"CrescendoBuilt",
};

s_uniqueUserIdentifier = GetUniqueIdentifier().ToString();
}
}
Expand Down Expand Up @@ -671,15 +685,49 @@ private static bool GetEnvironmentVariableAsBool(string name, bool defaultValue)
return defaultValue;
}

/// <summary>
/// Send module load telemetry as a metric.
/// For modules we send the module name (if allowed), and the version.
/// Some modules (CIM) will continue use the string alternative method.
/// </summary>
/// <param name="telemetryType">The type of telemetry that we'll be sending.</param>
/// <param name="moduleInfo">The module to report. If it is not allowed, then it is set to 'anonymous'.</param>
internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, PSModuleInfo moduleInfo)
{
if (!CanSendTelemetry)
{
return;
}

// Package up the module name, version, and known tags as a metric.
// Note that the allowed tags will be a comma separated list which will need to
// be handled in the telemetry query.
try
{
string allowedModuleName = GetModuleName(moduleInfo.Name);
string allowedModuleVersion = allowedModuleName == Anonymous ? AnonymousVersion : moduleInfo.Version?.ToString();
var allowedModuleTags = moduleInfo.Tags.Where(t => s_knownModuleTags.Contains(t)).Distinct();
string allowedModuleTagString = allowedModuleTags.Any() ? string.Join(',', allowedModuleTags) : NoTag;

s_telemetryClient.
GetMetric(new MetricIdentifier(string.Empty, telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version", "Tag")).
TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion, allowedModuleTagString);
}
catch
{
// Ignore errors.
}

}

/// <summary>
/// Send module load telemetry as a metric.
/// For modules we send the module name (if allowed), and the version.
/// Some modules (CIM) will continue use the string alternative method.
/// </summary>
/// <param name="telemetryType">The type of telemetry that we'll be sending.</param>
/// <param name="moduleName">The module name to report. If it is not allowed, then it is set to 'anonymous'.</param>
/// <param name="moduleVersion">The module version to report. The default value is the anonymous version '0.0.0.0'.</param>
internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, string moduleName, string moduleVersion = AnonymousVersion)
internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, string moduleName)
{
if (!CanSendTelemetry)
{
Expand All @@ -689,8 +737,7 @@ internal static void SendModuleTelemetryMetric(TelemetryType telemetryType, stri
try
{
string allowedModuleName = GetModuleName(moduleName);
string allowedModuleVersion = allowedModuleName == Anonymous ? AnonymousVersion : moduleVersion;
s_telemetryClient.GetMetric(telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, allowedModuleVersion);
s_telemetryClient.GetMetric(telemetryType.ToString(), "uuid", "SessionId", "ModuleName", "Version").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, allowedModuleName, AnonymousVersion);
}
catch
{
Expand Down