1
1
// Licensed to the .NET Foundation under one or more agreements.
2
2
// The .NET Foundation licenses this file to you under the MIT license.
3
3
4
- #nullable disable
5
-
4
+ using System . Collections . Frozen ;
6
5
using System . Diagnostics ;
7
6
using Microsoft . ApplicationInsights ;
8
7
using Microsoft . ApplicationInsights . Extensibility ;
@@ -14,27 +13,27 @@ namespace Microsoft.DotNet.Cli.Telemetry;
14
13
15
14
public class Telemetry : ITelemetry
16
15
{
17
- internal static string CurrentSessionId = null ;
16
+ internal static string ? CurrentSessionId = null ;
18
17
internal static bool DisabledForTests = false ;
19
18
private readonly int _senderCount ;
20
- private TelemetryClient _client = null ;
21
- private Dictionary < string , string > _commonProperties = null ;
22
- private Dictionary < string , double > _commonMeasurements = null ;
23
- private Task _trackEventTask = null ;
19
+ private TelemetryClient ? _client = null ;
20
+ private FrozenDictionary < string , string > ? _commonProperties = null ;
21
+ private FrozenDictionary < string , double > ? _commonMeasurements = null ;
22
+ private Task ? _trackEventTask = null ;
24
23
25
24
private const string ConnectionString = "InstrumentationKey=74cc1c9e-3e6e-4d05-b3fc-dde9101d0254" ;
26
25
27
26
public bool Enabled { get ; }
28
27
29
28
public Telemetry ( ) : this ( null ) { }
30
29
31
- public Telemetry ( IFirstTimeUseNoticeSentinel sentinel ) : this ( sentinel , null ) { }
30
+ public Telemetry ( IFirstTimeUseNoticeSentinel ? sentinel ) : this ( sentinel , null ) { }
32
31
33
32
public Telemetry (
34
- IFirstTimeUseNoticeSentinel sentinel ,
35
- string sessionId ,
33
+ IFirstTimeUseNoticeSentinel ? sentinel ,
34
+ string ? sessionId ,
36
35
bool blockThreadInitialization = false ,
37
- IEnvironmentProvider environmentProvider = null ,
36
+ IEnvironmentProvider ? environmentProvider = null ,
38
37
int senderCount = 3 )
39
38
{
40
39
@@ -78,7 +77,7 @@ internal static void EnableForTests()
78
77
DisabledForTests = false ;
79
78
}
80
79
81
- private static bool PermissionExists ( IFirstTimeUseNoticeSentinel sentinel )
80
+ private static bool PermissionExists ( IFirstTimeUseNoticeSentinel ? sentinel )
82
81
{
83
82
if ( sentinel == null )
84
83
{
@@ -97,9 +96,17 @@ public void TrackEvent(string eventName, IDictionary<string, string> properties,
97
96
}
98
97
99
98
//continue the task in different threads
100
- _trackEventTask = _trackEventTask . ContinueWith (
101
- x => TrackEventTask ( eventName , properties , measurements )
102
- ) ;
99
+ if ( _trackEventTask == null )
100
+ {
101
+ _trackEventTask = Task . Run ( ( ) => TrackEventTask ( eventName , properties , measurements ) ) ;
102
+ return ;
103
+ }
104
+ else
105
+ {
106
+ _trackEventTask = _trackEventTask . ContinueWith (
107
+ x => TrackEventTask ( eventName , properties , measurements )
108
+ ) ;
109
+ }
103
110
}
104
111
105
112
public void Flush ( )
@@ -148,7 +155,7 @@ private void InitializeTelemetry()
148
155
_client . Context . Device . OperatingSystem = CLIRuntimeEnvironment . OperatingSystem ;
149
156
150
157
_commonProperties = new TelemetryCommonProperties ( ) . GetTelemetryCommonProperties ( ) ;
151
- _commonMeasurements = [ ] ;
158
+ _commonMeasurements = FrozenDictionary < string , double > . Empty ;
152
159
}
153
160
catch ( Exception e )
154
161
{
@@ -170,39 +177,84 @@ private void TrackEventTask(
170
177
171
178
try
172
179
{
173
- Dictionary < string , string > eventProperties = GetEventProperties ( properties ) ;
174
- Dictionary < string , double > eventMeasurements = GetEventMeasures ( measurements ) ;
180
+ var eventProperties = GetEventProperties ( properties ) ;
181
+ var eventMeasurements = GetEventMeasures ( measurements ) ;
175
182
183
+ eventProperties ??= new Dictionary < string , string > ( ) ;
176
184
eventProperties . Add ( "event id" , Guid . NewGuid ( ) . ToString ( ) ) ;
177
185
178
186
_client . TrackEvent ( PrependProducerNamespace ( eventName ) , eventProperties , eventMeasurements ) ;
187
+ Activity . Current ? . AddEvent ( CreateActivityEvent ( eventName , eventProperties , eventMeasurements ) ) ;
179
188
}
180
189
catch ( Exception e )
181
190
{
182
191
Debug . Fail ( e . ToString ( ) ) ;
183
192
}
184
193
}
185
194
186
- private static string PrependProducerNamespace ( string eventName )
195
+ private static ActivityEvent CreateActivityEvent (
196
+ string eventName ,
197
+ IDictionary < string , string > ? properties ,
198
+ IDictionary < string , double > ? measurements )
187
199
{
188
- return "dotnet/cli/" + eventName ;
200
+ var tags = MakeTags ( properties , measurements ) ;
201
+ return new ActivityEvent (
202
+ PrependProducerNamespace ( eventName ) ,
203
+ tags : tags ) ;
189
204
}
190
205
191
- private Dictionary < string , double > GetEventMeasures ( IDictionary < string , double > measurements )
206
+ private static ActivityTagsCollection ? MakeTags (
207
+ IDictionary < string , string > ? properties ,
208
+ IDictionary < string , double > ? measurements )
192
209
{
193
- Dictionary < string , double > eventMeasurements = new ( _commonMeasurements ) ;
194
- if ( measurements != null )
210
+ if ( properties == null && measurements == null )
195
211
{
196
- foreach ( KeyValuePair < string , double > measurement in measurements )
197
- {
198
- eventMeasurements [ measurement . Key ] = measurement . Value ;
199
- }
212
+ return null ;
213
+ }
214
+ else if ( properties != null && measurements == null )
215
+ {
216
+ return [ .. properties . Select ( p => new KeyValuePair < string , object ? > ( p . Key , p . Value ) ) ] ;
217
+ }
218
+ else if ( properties == null && measurements != null )
219
+ {
220
+ return [ .. measurements . Select ( m => new KeyValuePair < string , object ? > ( m . Key , m . Value . ToString ( ) ) ) ] ;
221
+ }
222
+ else return [ .. properties ! . Select ( p => new KeyValuePair < string , object ? > ( p . Key , p . Value ) ) ,
223
+ .. measurements ! . Select ( m => new KeyValuePair < string , object ? > ( m . Key , m . Value . ToString ( ) ) ) ] ;
224
+ }
225
+
226
+ private static string PrependProducerNamespace ( string eventName ) => $ "dotnet/cli/{ eventName } ";
227
+
228
+ private IDictionary < string , double > ? GetEventMeasures ( IDictionary < string , double > ? measurements )
229
+ {
230
+ if ( measurements is null )
231
+ {
232
+ return _commonMeasurements ;
233
+ }
234
+ if ( _commonMeasurements == null )
235
+ {
236
+ return measurements ;
237
+ }
238
+
239
+ IDictionary < string , double > eventMeasurements = new Dictionary < string , double > ( _commonMeasurements ) ;
240
+ foreach ( KeyValuePair < string , double > measurement in measurements )
241
+ {
242
+ eventMeasurements [ measurement . Key ] = measurement . Value ;
200
243
}
201
244
return eventMeasurements ;
202
245
}
203
246
204
- private Dictionary < string , string > GetEventProperties ( IDictionary < string , string > properties )
247
+ private IDictionary < string , string > ? GetEventProperties ( IDictionary < string , string > ? properties )
205
248
{
249
+ if ( properties is null )
250
+ {
251
+ return _commonProperties ;
252
+ }
253
+ if ( _commonProperties == null )
254
+ {
255
+ return properties ;
256
+ }
257
+
206
258
var eventProperties = new Dictionary < string , string > ( _commonProperties ) ;
207
259
if ( properties != null )
208
260
{
0 commit comments