Add telemetry to check for specific tags when importing a module (#20371) (#20540)

This commit is contained in:
Aditya Patwardhan
2023-10-19 15:34:22 -07:00
committed by GitHub
parent dd56ad65ad
commit a7d7526f6e
2 changed files with 58 additions and 11 deletions
@@ -619,7 +619,7 @@ namespace Microsoft.PowerShell.Commands
// 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
@@ -893,7 +893,7 @@ namespace Microsoft.PowerShell.Commands
if (foundModule != null)
{
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule.Name, foundModule.Version?.ToString());
ApplicationInsightsTelemetry.SendModuleTelemetryMetric(TelemetryType.ModuleLoad, foundModule);
SetModuleBaseForEngineModules(foundModule.Name, this.Context);
}
@@ -935,7 +935,7 @@ namespace Microsoft.PowerShell.Commands
// 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;
@@ -1866,7 +1866,7 @@ namespace Microsoft.PowerShell.Commands
// 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: () =>
@@ -1926,7 +1926,7 @@ namespace Microsoft.PowerShell.Commands
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)
@@ -5,11 +5,14 @@ using System;
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;
@@ -124,6 +127,9 @@ namespace Microsoft.PowerShell.Telemetry
// 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";
@@ -140,9 +146,11 @@ namespace Microsoft.PowerShell.Telemetry
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;
@@ -601,6 +609,12 @@ namespace Microsoft.PowerShell.Telemetry
"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();
}
}
@@ -671,6 +685,41 @@ namespace Microsoft.PowerShell.Telemetry
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.
@@ -678,8 +727,7 @@ namespace Microsoft.PowerShell.Telemetry
/// </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)
{
@@ -689,8 +737,7 @@ namespace Microsoft.PowerShell.Telemetry
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
{