diff --git a/Directory.Packages.props b/Directory.Packages.props
index 104dedfd9eaf..abe2e9e23b4c 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -108,6 +108,7 @@
+
diff --git a/eng/Versions.props b/eng/Versions.props
index 99e97cedaae8..1b71e21ebfc6 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -119,6 +119,7 @@
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
+ 10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
10.0.0-preview.7.25359.101
diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs
new file mode 100644
index 000000000000..9f4665572436
--- /dev/null
+++ b/src/Cli/Microsoft.DotNet.Cli.Utils/Activities.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+
+namespace Microsoft.DotNet.Cli.Utils;
+
+///
+/// Contains helpers for working with Activities in the .NET CLI.
+///
+public static class Activities
+{
+
+ ///
+ /// The main entrypoint for creating Activities in the .NET CLI.
+ /// All activities created in the CLI should use this , to allow
+ /// consumers to easily filter and trace CLI activities.
+ ///
+ public static ActivitySource Source { get; } = new("dotnet-cli", Product.Version);
+}
diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
index f6acb60ea0a1..1b2058d17744 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
+++ b/src/Cli/Microsoft.DotNet.Cli.Utils/ForwardingAppImplementation.cs
@@ -19,7 +19,7 @@ internal class ForwardingAppImplementation
private readonly string? _depsFile;
private readonly string? _runtimeConfig;
private readonly string? _additionalProbingPath;
- private Dictionary _environmentVariables;
+ private Dictionary _environmentVariables;
private readonly string[] _allArgs;
@@ -29,7 +29,7 @@ public ForwardingAppImplementation(
string? depsFile = null,
string? runtimeConfig = null,
string? additionalProbingPath = null,
- Dictionary? environmentVariables = null)
+ Dictionary? environmentVariables = null)
{
_forwardApplicationPath = forwardApplicationPath;
_argsToForward = argsToForward;
@@ -86,7 +86,7 @@ public ProcessStartInfo GetProcessStartInfo()
return processInfo;
}
- public ForwardingAppImplementation WithEnvironmentVariable(string name, string value)
+ public ForwardingAppImplementation WithEnvironmentVariable(string name, string? value)
{
_environmentVariables.Add(name, value);
diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
index 2e95365623a0..64e6fea0ccf9 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
+++ b/src/Cli/Microsoft.DotNet.Cli.Utils/MSBuildForwardingAppWithoutLogging.cs
@@ -39,7 +39,7 @@ public static string MSBuildVersion
// True if, given current state of the class, MSBuild would be executed in its own process.
public bool ExecuteMSBuildOutOfProc => _forwardingApp != null;
- private readonly Dictionary _msbuildRequiredEnvironmentVariables = GetMSBuildRequiredEnvironmentVariables();
+ private readonly Dictionary _msbuildRequiredEnvironmentVariables = GetMSBuildRequiredEnvironmentVariables();
private readonly List _msbuildRequiredParameters = [ "-maxcpucount", "--verbosity:m" ];
@@ -112,7 +112,7 @@ private static string EmitProperty(KeyValuePair property, string
: $"--{label}:{property.Key}={property.Value}";
}
- public void EnvironmentVariable(string name, string value)
+ public void EnvironmentVariable(string name, string? value)
{
if (_forwardingApp != null)
{
@@ -153,7 +153,7 @@ public int ExecuteInProc(string[] arguments)
Dictionary savedEnvironmentVariables = [];
try
{
- foreach (KeyValuePair kvp in _msbuildRequiredEnvironmentVariables)
+ foreach (KeyValuePair kvp in _msbuildRequiredEnvironmentVariables)
{
savedEnvironmentVariables[kvp.Key] = Environment.GetEnvironmentVariable(kvp.Key);
Environment.SetEnvironmentVariable(kvp.Key, kvp.Value);
@@ -218,7 +218,7 @@ private static string GetDotnetPath()
return new Muxer().MuxerPath;
}
- internal static Dictionary GetMSBuildRequiredEnvironmentVariables()
+ internal static Dictionary GetMSBuildRequiredEnvironmentVariables()
{
return new()
{
diff --git a/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj b/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
index 115f5dd125ec..3c0f616409d4 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
+++ b/src/Cli/Microsoft.DotNet.Cli.Utils/Microsoft.DotNet.Cli.Utils.csproj
@@ -54,6 +54,7 @@
+
diff --git a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
index f3ef9d93a44f..67c2a47f1051 100644
--- a/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
+++ b/src/Cli/dotnet/Commands/MSBuild/MSBuildForwardingApp.cs
@@ -59,7 +59,7 @@ public MSBuildForwardingApp(MSBuildArgs msBuildArgs, string? msbuildPath = null,
public IEnumerable MSBuildArguments { get { return _forwardingAppWithoutLogging.GetAllArguments(); } }
- public void EnvironmentVariable(string name, string value)
+ public void EnvironmentVariable(string name, string? value)
{
_forwardingAppWithoutLogging.EnvironmentVariable(name, value);
}
diff --git a/src/Cli/dotnet/Telemetry/Telemetry.cs b/src/Cli/dotnet/Telemetry/Telemetry.cs
index 28851da921b1..f908d01e7fe0 100644
--- a/src/Cli/dotnet/Telemetry/Telemetry.cs
+++ b/src/Cli/dotnet/Telemetry/Telemetry.cs
@@ -1,8 +1,7 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-#nullable disable
-
+using System.Collections.Frozen;
using System.Diagnostics;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;
@@ -14,13 +13,13 @@ namespace Microsoft.DotNet.Cli.Telemetry;
public class Telemetry : ITelemetry
{
- internal static string CurrentSessionId = null;
+ internal static string? CurrentSessionId = null;
internal static bool DisabledForTests = false;
private readonly int _senderCount;
- private TelemetryClient _client = null;
- private Dictionary _commonProperties = null;
- private Dictionary _commonMeasurements = null;
- private Task _trackEventTask = null;
+ private TelemetryClient? _client = null;
+ private FrozenDictionary? _commonProperties = null;
+ private FrozenDictionary? _commonMeasurements = null;
+ private Task? _trackEventTask = null;
private const string ConnectionString = "InstrumentationKey=74cc1c9e-3e6e-4d05-b3fc-dde9101d0254";
@@ -28,13 +27,13 @@ public class Telemetry : ITelemetry
public Telemetry() : this(null) { }
- public Telemetry(IFirstTimeUseNoticeSentinel sentinel) : this(sentinel, null) { }
+ public Telemetry(IFirstTimeUseNoticeSentinel? sentinel) : this(sentinel, null) { }
public Telemetry(
- IFirstTimeUseNoticeSentinel sentinel,
- string sessionId,
+ IFirstTimeUseNoticeSentinel? sentinel,
+ string? sessionId,
bool blockThreadInitialization = false,
- IEnvironmentProvider environmentProvider = null,
+ IEnvironmentProvider? environmentProvider = null,
int senderCount = 3)
{
@@ -78,7 +77,7 @@ internal static void EnableForTests()
DisabledForTests = false;
}
- private static bool PermissionExists(IFirstTimeUseNoticeSentinel sentinel)
+ private static bool PermissionExists(IFirstTimeUseNoticeSentinel? sentinel)
{
if (sentinel == null)
{
@@ -97,9 +96,17 @@ public void TrackEvent(string eventName, IDictionary properties,
}
//continue the task in different threads
- _trackEventTask = _trackEventTask.ContinueWith(
- x => TrackEventTask(eventName, properties, measurements)
- );
+ if (_trackEventTask == null)
+ {
+ _trackEventTask = Task.Run(() => TrackEventTask(eventName, properties, measurements));
+ return;
+ }
+ else
+ {
+ _trackEventTask = _trackEventTask.ContinueWith(
+ x => TrackEventTask(eventName, properties, measurements)
+ );
+ }
}
public void Flush()
@@ -148,7 +155,7 @@ private void InitializeTelemetry()
_client.Context.Device.OperatingSystem = CLIRuntimeEnvironment.OperatingSystem;
_commonProperties = new TelemetryCommonProperties().GetTelemetryCommonProperties();
- _commonMeasurements = [];
+ _commonMeasurements = FrozenDictionary.Empty;
}
catch (Exception e)
{
@@ -170,12 +177,14 @@ private void TrackEventTask(
try
{
- Dictionary eventProperties = GetEventProperties(properties);
- Dictionary eventMeasurements = GetEventMeasures(measurements);
+ var eventProperties = GetEventProperties(properties);
+ var eventMeasurements = GetEventMeasures(measurements);
+ eventProperties ??= new Dictionary();
eventProperties.Add("event id", Guid.NewGuid().ToString());
_client.TrackEvent(PrependProducerNamespace(eventName), eventProperties, eventMeasurements);
+ Activity.Current?.AddEvent(CreateActivityEvent(eventName, eventProperties, eventMeasurements));
}
catch (Exception e)
{
@@ -183,26 +192,69 @@ private void TrackEventTask(
}
}
- private static string PrependProducerNamespace(string eventName)
+ private static ActivityEvent CreateActivityEvent(
+ string eventName,
+ IDictionary? properties,
+ IDictionary? measurements)
{
- return "dotnet/cli/" + eventName;
+ var tags = MakeTags(properties, measurements);
+ return new ActivityEvent(
+ PrependProducerNamespace(eventName),
+ tags: tags);
}
- private Dictionary GetEventMeasures(IDictionary measurements)
+ private static ActivityTagsCollection? MakeTags(
+ IDictionary? properties,
+ IDictionary? measurements)
{
- Dictionary eventMeasurements = new(_commonMeasurements);
- if (measurements != null)
+ if (properties == null && measurements == null)
{
- foreach (KeyValuePair measurement in measurements)
- {
- eventMeasurements[measurement.Key] = measurement.Value;
- }
+ return null;
+ }
+ else if (properties != null && measurements == null)
+ {
+ return [.. properties.Select(p => new KeyValuePair(p.Key, p.Value))];
+ }
+ else if (properties == null && measurements != null)
+ {
+ return [.. measurements.Select(m => new KeyValuePair(m.Key, m.Value.ToString()))];
+ }
+ else return [ .. properties!.Select(p => new KeyValuePair(p.Key, p.Value)),
+ .. measurements!.Select(m => new KeyValuePair(m.Key, m.Value.ToString())) ];
+ }
+
+ private static string PrependProducerNamespace(string eventName) => $"dotnet/cli/{eventName}";
+
+ private IDictionary? GetEventMeasures(IDictionary? measurements)
+ {
+ if (measurements is null)
+ {
+ return _commonMeasurements;
+ }
+ if (_commonMeasurements == null)
+ {
+ return measurements;
+ }
+
+ IDictionary eventMeasurements = new Dictionary(_commonMeasurements);
+ foreach (KeyValuePair measurement in measurements)
+ {
+ eventMeasurements[measurement.Key] = measurement.Value;
}
return eventMeasurements;
}
- private Dictionary GetEventProperties(IDictionary properties)
+ private IDictionary? GetEventProperties(IDictionary? properties)
{
+ if (properties is null)
+ {
+ return _commonProperties;
+ }
+ if (_commonProperties == null)
+ {
+ return properties;
+ }
+
var eventProperties = new Dictionary(_commonProperties);
if (properties != null)
{
diff --git a/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs b/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
index 88b2c2152100..9f58d488a12c 100644
--- a/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
+++ b/src/Cli/dotnet/Telemetry/TelemetryCommonProperties.cs
@@ -3,6 +3,7 @@
#nullable disable
+using System.Collections.Frozen;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.Configurer;
using RuntimeEnvironment = Microsoft.DotNet.Cli.Utils.RuntimeEnvironment;
@@ -52,7 +53,7 @@ internal class TelemetryCommonProperties(
private const string MachineIdCacheKey = "MachineId";
private const string IsDockerContainerCacheKey = "IsDockerContainer";
- public Dictionary GetTelemetryCommonProperties()
+ public FrozenDictionary GetTelemetryCommonProperties()
{
return new Dictionary
{
@@ -82,7 +83,7 @@ public Dictionary GetTelemetryCommonProperties()
{ProductType, ExternalTelemetryProperties.GetProductType()},
{LibcRelease, ExternalTelemetryProperties.GetLibcRelease()},
{LibcVersion, ExternalTelemetryProperties.GetLibcVersion()}
- };
+ }.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
}
private string GetMachineId()