mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-17 12:45:47 +00:00
Update telemetry collecting with a few changes (#17304)
This commit is contained in:
1 parent
c40066d5f2
commit
65d8f11aeb
6 files changed
+233
-76
No files matched your search
@@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Management.Automation;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -94,8 +95,15 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
// private const string _psCoreTelemetryKey = "ee4b2115-d347-47b0-adb6-b19c2c763808"; // Production
|
||||
private const string _psCoreTelemetryKey = "d26a5ef4-d608-452c-a6b8-a4a55935f70d"; // V7 Preview 3
|
||||
|
||||
// In the event there is a problem in creating the node identifier file, use the default identifier.
|
||||
// This can happen if we are running in a system which has a read-only filesystem.
|
||||
private static readonly Guid _defaultNodeIdentifier = new Guid("2f998828-3f4a-4741-bf50-d11c6be42f50");
|
||||
|
||||
// Use "anonymous" as the string to return when you can't report a name
|
||||
private const string _anonymous = "anonymous";
|
||||
private const string Anonymous = "anonymous";
|
||||
|
||||
// Use '0.0' as the string for an anonymous module version
|
||||
private const string AnonymousVersion = "0.0";
|
||||
|
||||
// the telemetry failure string
|
||||
private const string _telemetryFailure = "TELEMETRY_FAILURE";
|
||||
@@ -240,6 +248,7 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
"Az.StorageTable",
|
||||
"Az.StreamAnalytics",
|
||||
"Az.Subscription",
|
||||
"Az.Tools.Predictor",
|
||||
"Az.TrafficManager",
|
||||
"Az.Websites",
|
||||
"Azs.Azurebridge.Admin",
|
||||
@@ -642,6 +651,28 @@ 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="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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore errors.
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send telemetry as a metric.
|
||||
/// </summary>
|
||||
@@ -654,7 +685,9 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
return;
|
||||
}
|
||||
|
||||
SendPSCoreStartupTelemetry("hosted");
|
||||
// These should be handled by SendModuleTelemetryMetric.
|
||||
Debug.Assert(metricId != TelemetryType.ModuleLoad, "ModuleLoad should be handled by SendModuleTelemetryMetric.");
|
||||
Debug.Assert(metricId != TelemetryType.WinCompatModuleLoad, "WinCompatModuleLoad should be handled by SendModuleTelemetryMetric.");
|
||||
|
||||
string metricName = metricId.ToString();
|
||||
try
|
||||
@@ -671,11 +704,6 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
string experimentalFeatureName = GetExperimentalFeatureName(data);
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);
|
||||
break;
|
||||
case TelemetryType.ModuleLoad:
|
||||
case TelemetryType.WinCompatModuleLoad:
|
||||
string moduleName = GetModuleName(data); // This will return anonymous if the modulename is not on the report list
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, moduleName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
@@ -697,7 +725,7 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
return featureNameToValidate;
|
||||
}
|
||||
|
||||
return _anonymous;
|
||||
return Anonymous;
|
||||
}
|
||||
|
||||
// Get the module name. If we can report it, we'll return the name, otherwise, we'll return "anonymous"
|
||||
@@ -708,7 +736,7 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
return moduleNameToValidate;
|
||||
}
|
||||
|
||||
return _anonymous;
|
||||
return Anonymous;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -716,7 +744,8 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
/// This is done only once during for the console host.
|
||||
/// </summary>
|
||||
/// <param name="mode">The "mode" of the startup.</param>
|
||||
internal static void SendPSCoreStartupTelemetry(string mode)
|
||||
/// <param name="parametersUsed">The parameter bitmap used when starting.</param>
|
||||
internal static void SendPSCoreStartupTelemetry(string mode, double parametersUsed)
|
||||
{
|
||||
// Check if we already sent startup telemetry
|
||||
if (Interlocked.CompareExchange(ref s_startupEventSent, 1, 0) == 1)
|
||||
@@ -729,22 +758,30 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the payload which reports the startup information of OS and shell details.
|
||||
var properties = new Dictionary<string, string>();
|
||||
|
||||
// The variable POWERSHELL_DISTRIBUTION_CHANNEL is set in our docker images.
|
||||
// This allows us to track the actual docker OS as OSDescription provides only "linuxkit"
|
||||
// which has limited usefulness
|
||||
// This is the payload for the parameter data which is sent as a metric.
|
||||
var parameters = new Dictionary<string, double>();
|
||||
|
||||
// The variable POWERSHELL_DISTRIBUTION_CHANNEL is set in our docker images and
|
||||
// by various other environments. This allows us to track the actual docker OS as
|
||||
// OSDescription provides only "linuxkit" which has limited usefulness.
|
||||
var channel = Environment.GetEnvironmentVariable("POWERSHELL_DISTRIBUTION_CHANNEL");
|
||||
|
||||
// Construct the payload for the OS and shell details.
|
||||
properties.Add("SessionId", s_sessionId);
|
||||
properties.Add("UUID", s_uniqueUserIdentifier);
|
||||
properties.Add("GitCommitID", PSVersionInfo.GitCommitId);
|
||||
properties.Add("OSDescription", RuntimeInformation.OSDescription);
|
||||
properties.Add("OSChannel", string.IsNullOrEmpty(channel) ? "unknown" : channel);
|
||||
properties.Add("StartMode", string.IsNullOrEmpty(mode) ? "unknown" : mode);
|
||||
|
||||
// Construct the payload for the parameters used.
|
||||
parameters.Add("Param", parametersUsed);
|
||||
try
|
||||
{
|
||||
s_telemetryClient.TrackEvent("ConsoleHostStartup", properties, null);
|
||||
s_telemetryClient.TrackEvent("ConsoleHostStartup", properties, parameters);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -798,50 +835,53 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
/// Try to create a unique identifier and persist it to the telemetry.uuid file.
|
||||
/// </summary>
|
||||
/// <param name="telemetryFilePath">The path to the persisted telemetry.uuid file.</param>
|
||||
/// <param name="id">The created identifier.</param>
|
||||
/// <returns>
|
||||
/// The method returns a bool indicating success or failure of creating the id.
|
||||
/// The method node id.
|
||||
/// </returns>
|
||||
private static bool TryCreateUniqueIdentifierAndFile(string telemetryFilePath, out Guid id)
|
||||
private static Guid CreateUniqueIdentifierAndFile(string telemetryFilePath)
|
||||
{
|
||||
// one last attempt to retrieve before creating incase we have a lot of simultaneous entry into the mutex.
|
||||
id = Guid.Empty;
|
||||
Guid id = Guid.Empty;
|
||||
if (TryGetIdentifier(telemetryFilePath, out id))
|
||||
{
|
||||
return true;
|
||||
return id;
|
||||
}
|
||||
|
||||
// The directory may not exist, so attempt to create it
|
||||
// CreateDirectory will simply return the directory if exists
|
||||
bool attemptFileCreation = true;
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(telemetryFilePath));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// send a telemetry indicating a problem with the cache dir
|
||||
// it's likely something is seriously wrong so we should at least report it.
|
||||
// We don't want to provide reasons here, that's not the point, but we
|
||||
// would like to know if we're having a generalized problem which we can trace statistically
|
||||
CanSendTelemetry = false;
|
||||
s_telemetryClient.GetMetric(_telemetryFailure, "Detail").TrackValue(1, "cachedir");
|
||||
return false;
|
||||
// There was a problem in creating the directory for the file, do not attempt to create the file.
|
||||
// We don't send telemetry here because there are valid reasons for the directory to not exist
|
||||
// and not be able to be created.
|
||||
attemptFileCreation = false;
|
||||
}
|
||||
|
||||
// Create and save the new identifier, and if there's a problem, disable telemetry
|
||||
try
|
||||
// If we were able to create the directory, try to create the file,
|
||||
// if this fails we will send telemetry to indicate this and then use the default identifier.
|
||||
if (attemptFileCreation)
|
||||
{
|
||||
id = Guid.NewGuid();
|
||||
File.WriteAllBytes(telemetryFilePath, id.ToByteArray());
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// another bit of telemetry to notify us about a problem with saving the unique id.
|
||||
s_telemetryClient.GetMetric(_telemetryFailure, "Detail").TrackValue(1, "saveuuid");
|
||||
try
|
||||
{
|
||||
id = Guid.NewGuid();
|
||||
File.WriteAllBytes(telemetryFilePath, id.ToByteArray());
|
||||
return id;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// another bit of telemetry to notify us about a problem with saving the unique id.
|
||||
s_telemetryClient.GetMetric(_telemetryFailure, "Detail").TrackValue(1, "saveuuid");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// all attempts to create an identifier have failed, so use the default node id.
|
||||
id = _defaultNodeIdentifier;
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -865,15 +905,12 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
// simultaneous shell starts without the persisted file which attempt to create the file.
|
||||
try
|
||||
{
|
||||
// TryCreateUniqueIdentifierAndFile shouldn't throw, but the mutex might
|
||||
// CreateUniqueIdentifierAndFile shouldn't throw, but the mutex might
|
||||
using var m = new Mutex(true, "CreateUniqueUserId");
|
||||
m.WaitOne();
|
||||
try
|
||||
{
|
||||
if (TryCreateUniqueIdentifierAndFile(uuidPath, out id))
|
||||
{
|
||||
return id;
|
||||
}
|
||||
return CreateUniqueIdentifierAndFile(uuidPath);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user