mirror of
https://github.com/PowerShell/PowerShell.git
synced 2024-11-27 03:46:23 +08:00
Add telemetry to track the use of features (#24247)
This commit is contained in:
parent
9303de597d
commit
4fdc02b698
@ -9,6 +9,7 @@ using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using Microsoft.PowerShell.Telemetry;
|
||||
|
||||
namespace System.Management.Automation
|
||||
{
|
||||
@ -607,16 +608,19 @@ namespace System.Management.Automation
|
||||
[UnmanagedCallersOnly]
|
||||
public static int LoadAssemblyFromNativeMemory(IntPtr data, int size)
|
||||
{
|
||||
int result = 0;
|
||||
try
|
||||
{
|
||||
using var stream = new UnmanagedMemoryStream((byte*)data, size);
|
||||
AssemblyLoadContext.Default.LoadFromStream(stream);
|
||||
return 0;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return -1;
|
||||
result = -1;
|
||||
}
|
||||
|
||||
ApplicationInsightsTelemetry.SendUseTelemetry("PowerShellUnsafeAssemblyLoad", result == 0 ? "1" : "0");
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,8 +44,6 @@ namespace System.Management.Automation.Internal
|
||||
| FileAttributes.Offline
|
||||
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
|
||||
| (FileAttributes)FILE_ATTRIBUTE_RECALL_ON_OPEN;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -9,6 +9,7 @@ using System.Management.Automation.Internal;
|
||||
using System.Management.Automation.Language;
|
||||
using System.Management.Automation.Runspaces;
|
||||
using System.Threading;
|
||||
using Microsoft.PowerShell.Telemetry;
|
||||
|
||||
namespace System.Management.Automation.Subsystem.Feedback
|
||||
{
|
||||
@ -289,6 +290,7 @@ namespace System.Management.Automation.Subsystem.Feedback
|
||||
|
||||
if (results.Count > 0)
|
||||
{
|
||||
ApplicationInsightsTelemetry.SendUseTelemetry("FuzzyMatching", "CommandNotFound");
|
||||
return new FeedbackItem(
|
||||
SuggestionStrings.Suggestion_CommandNotFound,
|
||||
new List<string>(results),
|
||||
|
@ -7,6 +7,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Management.Automation.Internal;
|
||||
using Microsoft.PowerShell.Telemetry;
|
||||
|
||||
namespace System.Management.Automation.Subsystem
|
||||
{
|
||||
@ -96,6 +97,7 @@ namespace System.Management.Automation.Subsystem
|
||||
internal void RegisterImplementation(ISubsystem impl)
|
||||
{
|
||||
AddImplementation(impl);
|
||||
ApplicationInsightsTelemetry.SendUseTelemetry(ApplicationInsightsTelemetry.s_subsystemRegistration, impl.Name);
|
||||
}
|
||||
|
||||
internal ISubsystem UnregisterImplementation(Guid id)
|
||||
|
@ -83,6 +83,13 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
/// Remote session creation.
|
||||
/// </summary>
|
||||
RemoteSessionOpen,
|
||||
|
||||
/// <summary>
|
||||
/// Send telemetry for a stable feature when used.
|
||||
/// By making a distinction between this and experimental feature use, it will make
|
||||
/// queries much easier.
|
||||
/// </summary>
|
||||
FeatureUse,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -110,6 +117,9 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
/// </summary>
|
||||
public static class ApplicationInsightsTelemetry
|
||||
{
|
||||
// The string for SubsystermRegistration
|
||||
internal const string s_subsystemRegistration = "Subsystem.Registration";
|
||||
|
||||
// If this env var is true, yes, or 1, telemetry will NOT be sent.
|
||||
private const string _telemetryOptoutEnvVar = "POWERSHELL_TELEMETRY_OPTOUT";
|
||||
|
||||
@ -152,6 +162,8 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
private static readonly HashSet<string> s_knownModules;
|
||||
private static readonly HashSet<string> s_knownModuleTags;
|
||||
|
||||
private static readonly HashSet<string> s_knownSubsystemNames;
|
||||
|
||||
/// <summary>Gets a value indicating whether telemetry can be sent.</summary>
|
||||
public static bool CanSendTelemetry { get; private set; } = false;
|
||||
|
||||
@ -620,6 +632,13 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
};
|
||||
|
||||
s_uniqueUserIdentifier = GetUniqueIdentifier().ToString();
|
||||
s_knownSubsystemNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
"Completion",
|
||||
"general",
|
||||
"Windows Package Manager - WinGet",
|
||||
"Az Predictor"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -754,7 +773,8 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
/// </summary>
|
||||
/// <param name="metricId">The type of telemetry that we'll be sending.</param>
|
||||
/// <param name="data">The specific details about the telemetry.</param>
|
||||
internal static void SendTelemetryMetric(TelemetryType metricId, string data)
|
||||
/// <param name="value">The count of instances for the telemetry payload.</param>
|
||||
internal static void SendTelemetryMetric(TelemetryType metricId, string data, double value = 1.0)
|
||||
{
|
||||
if (!CanSendTelemetry)
|
||||
{
|
||||
@ -776,12 +796,13 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
case TelemetryType.ExperimentalEngineFeatureActivation:
|
||||
case TelemetryType.ExperimentalEngineFeatureDeactivation:
|
||||
case TelemetryType.ExperimentalFeatureUse:
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, data);
|
||||
case TelemetryType.FeatureUse:
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, data);
|
||||
break;
|
||||
case TelemetryType.ExperimentalModuleFeatureActivation:
|
||||
case TelemetryType.ExperimentalModuleFeatureDeactivation:
|
||||
string experimentalFeatureName = GetExperimentalFeatureName(data);
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);
|
||||
s_telemetryClient.GetMetric(metricName, "uuid", "SessionId", "Detail").TrackValue(metricValue: value, s_uniqueUserIdentifier, s_sessionId, experimentalFeatureName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -792,6 +813,35 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send additional information about an feature as it is used.
|
||||
/// </summary>
|
||||
/// <param name="featureName">The name of the feature.</param>
|
||||
/// <param name="detail">The details about the feature use.</param>
|
||||
/// <param name="value">The value to report when sending the payload.</param>
|
||||
internal static void SendUseTelemetry(string featureName, string detail, double value = 1.0)
|
||||
{
|
||||
if (!CanSendTelemetry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// keep payload small
|
||||
if (featureName is null || detail is null || featureName.Length > 33 || detail.Length > 33)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.Compare(featureName, s_subsystemRegistration, true) == 0)
|
||||
{
|
||||
ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, GetSubsystemName(detail)), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.FeatureUse, string.Join(":", featureName, detail), value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send additional information about an experimental feature as it is used.
|
||||
/// </summary>
|
||||
@ -822,7 +872,18 @@ namespace Microsoft.PowerShell.Telemetry
|
||||
return Anonymous;
|
||||
}
|
||||
|
||||
// Get the module name. If we can report it, we'll return the name, otherwise, we'll return "anonymous"
|
||||
// Get the module name. If we can report it, we'll return the name, otherwise, we'll return the string "anonymous"
|
||||
private static string GetSubsystemName(string subsystemNameToValidate)
|
||||
{
|
||||
if (s_knownSubsystemNames.Contains(subsystemNameToValidate))
|
||||
{
|
||||
return subsystemNameToValidate;
|
||||
}
|
||||
|
||||
return Anonymous;
|
||||
}
|
||||
|
||||
// Get the module name. If we can report it, we'll return the name, otherwise, we'll return anonymous.
|
||||
private static string GetModuleName(string moduleNameToValidate)
|
||||
{
|
||||
if (s_knownModules.Contains(moduleNameToValidate))
|
||||
|
Loading…
Reference in New Issue
Block a user