Skip to content
Closed
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
14 changes: 9 additions & 5 deletions src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,29 +187,29 @@ internal static int Start(string bannerText, string helpText)
// First check for and handle PowerShell running in a server mode.
if (s_cpp.ServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("ServerMode");
PSTelemetry.SendPSCoreStartupTelemetryInBackground("ServerMode");
ProfileOptimization.StartProfile("StartupProfileData-ServerMode");
System.Management.Automation.Remoting.Server.OutOfProcessMediator.Run(s_cpp.InitialCommand, s_cpp.WorkingDirectory);
exitCode = 0;
}
else if (s_cpp.NamedPipeServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("NamedPipe");
PSTelemetry.SendPSCoreStartupTelemetryInBackground("NamedPipe");
ProfileOptimization.StartProfile("StartupProfileData-NamedPipeServerMode");
System.Management.Automation.Remoting.RemoteSessionNamedPipeServer.RunServerMode(
s_cpp.ConfigurationName);
exitCode = 0;
}
else if (s_cpp.SSHServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SSHServer");
PSTelemetry.SendPSCoreStartupTelemetryInBackground("SSHServer");
ProfileOptimization.StartProfile("StartupProfileData-SSHServerMode");
System.Management.Automation.Remoting.Server.SSHProcessMediator.Run(s_cpp.InitialCommand);
exitCode = 0;
}
else if (s_cpp.SocketServerMode)
{
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("SocketServerMode");
PSTelemetry.SendPSCoreStartupTelemetryInBackground("SocketServerMode");
ProfileOptimization.StartProfile("StartupProfileData-SocketServerMode");
System.Management.Automation.Remoting.Server.HyperVSocketMediator.Run(s_cpp.InitialCommand,
s_cpp.ConfigurationName);
Expand Down Expand Up @@ -243,20 +243,24 @@ internal static int Start(string bannerText, string helpText)
PSHost.IsStdOutputRedirected = Console.IsOutputRedirected;

// Send startup telemetry for ConsoleHost startup
ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry("Normal");
PSTelemetry.SendPSCoreStartupTelemetryInBackground("Normal");

exitCode = s_theConsoleHost.Run(s_cpp, false);
}
}
finally
{
PSTelemetry.ContinueSendTelemetry();

if (s_theConsoleHost != null)
{
#if LEGACYTELEMETRY
TelemetryAPI.ReportExitTelemetry(s_theConsoleHost);
#endif
s_theConsoleHost.Dispose();
}

PSTelemetry.EnsureSendTelemetry();
}

unchecked
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,13 @@ private static ReadOnlyBag<string> ProcessEnabledFeatures(string[] enabledFeatur
if (IsModuleFeatureName(name))
{
list.Add(name);
ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.ExperimentalModuleFeatureActivation, name);
}
else if (IsEngineFeatureName(name))
{
if (EngineExperimentalFeatureMap.TryGetValue(name, out ExperimentalFeature feature))
{
feature.Enabled = true;
list.Add(name);
ApplicationInsightsTelemetry.SendTelemetryMetric(TelemetryType.ExperimentalEngineFeatureActivation, name);
}
else
{
Expand Down
91 changes: 91 additions & 0 deletions src/System.Management.Automation/utils/Telemetry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
Expand Down Expand Up @@ -681,11 +682,43 @@ internal static void SendPSCoreStartupTelemetry(string mode)
try
{
s_telemetryClient.TrackEvent("ConsoleHostStartup", properties, null);

SendExperimentalFeatureStartupTelemetry();
}
catch
{
// do nothing, telemetry cannot be sent
}

}

/// <summary>
/// Send telemetry about enabled experimental features.
/// </summary>
private static void SendExperimentalFeatureStartupTelemetry()
{
if (!CanSendTelemetry)
{
return;
}

if (ExperimentalFeature.EnabledExperimentalFeatureNames is not null)
{
foreach (string name in ExperimentalFeature.EnabledExperimentalFeatureNames)
{
if (ExperimentalFeature.IsModuleFeatureName(name))
{
s_telemetryClient.GetMetric(TelemetryType.ExperimentalModuleFeatureActivation.ToString(), "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, name);
}
else if (ExperimentalFeature.IsEngineFeatureName(name))
{
if (ExperimentalFeature.EngineExperimentalFeatureMap.TryGetValue(name, out ExperimentalFeature feature))
{
s_telemetryClient.GetMetric(TelemetryType.ExperimentalEngineFeatureActivation.ToString(), "uuid", "SessionId", "Detail").TrackValue(metricValue: 1.0, s_uniqueUserIdentifier, s_sessionId, feature.Name);
}
}
}
}
}

/// <summary>
Expand Down Expand Up @@ -826,5 +859,63 @@ private static Guid GetUniqueIdentifier()
CanSendTelemetry = false;
return id;
}

internal static void Flush()
{
s_telemetryClient?.Flush();
}
}

/// <summary>
/// Send up telemetry lazy.
/// </summary>
/// <remarks>
/// This class allows to delay the initialization of the ApplicationInsightsTelemetry static class at startup.
/// </remarks>
internal static class PSTelemetry
{
// Used to terminate Task.Delay() early
// if a script has been executed fast and PowerShell is ready to exit.
private static CancellationTokenSource s_cts = new();
private static Task s_sendPSCoreStartupTelemetryInBackground;

internal static void ContinueSendTelemetry()
{
// Tertinate Task.Delay().
s_cts.Cancel();
}

internal static void EnsureSendTelemetry()
{
s_sendPSCoreStartupTelemetryInBackground?.Wait();

// Ensure all telemetry has been sent before PowerShell exit.
ApplicationInsightsTelemetry.Flush();
}

internal static void SendPSCoreStartupTelemetryInBackground(string mode)
{
s_sendPSCoreStartupTelemetryInBackground = Task.Run(SendPSCoreStartupTelemetry(mode));
}

// The dedicated method allows deferring ApplicationInsightsTelemetry static class initialization.
private static Action SendPSCoreStartupTelemetry(string mode)
{
return async () =>
{
try
{
// On slow systems the delay postpones ApplicationInsightsTelemetry static class initialization
// so that do more useful work first.
await Task.Delay(500, s_cts.Token).ConfigureAwait(true);
}
catch
{
// Ignore TaskCanceledException.
}

ApplicationInsightsTelemetry.SendPSCoreStartupTelemetry(mode);
};
}
}
}