9
9
using System . Diagnostics ;
10
10
using System . Threading ;
11
11
using System . Threading . Tasks ;
12
+ using Microsoft . AspNetCore . Razor . PooledObjects ;
12
13
using Microsoft . AspNetCore . Razor . ProjectSystem ;
14
+ using Microsoft . AspNetCore . Razor . Telemetry ;
13
15
using Microsoft . CodeAnalysis . CSharp ;
14
16
using Microsoft . CodeAnalysis . Razor . ProjectSystem ;
15
17
using Microsoft . CodeAnalysis . Razor . Workspaces ;
@@ -19,31 +21,20 @@ namespace Microsoft.CodeAnalysis.Razor;
19
21
[ Shared ]
20
22
[ Export ( typeof ( ProjectWorkspaceStateGenerator ) ) ]
21
23
[ Export ( typeof ( IProjectSnapshotChangeTrigger ) ) ]
22
- internal class DefaultProjectWorkspaceStateGenerator : ProjectWorkspaceStateGenerator , IDisposable
24
+ [ method: ImportingConstructor ]
25
+ internal class DefaultProjectWorkspaceStateGenerator ( ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher , ITelemetryReporter telemetryReporter ) : ProjectWorkspaceStateGenerator , IDisposable
23
26
{
24
27
// Internal for testing
25
- internal readonly Dictionary < ProjectKey , UpdateItem > Updates ;
28
+ internal readonly Dictionary < ProjectKey , UpdateItem > Updates = new ( ) ;
29
+
30
+ private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ?? throw new ArgumentNullException ( nameof ( projectSnapshotManagerDispatcher ) ) ;
31
+ private readonly ITelemetryReporter _telemetryReporter = telemetryReporter ?? throw new ArgumentNullException ( nameof ( telemetryReporter ) ) ;
32
+ private readonly SemaphoreSlim _semaphore = new SemaphoreSlim ( initialCount : 1 ) ;
26
33
27
- private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher ;
28
- private readonly SemaphoreSlim _semaphore ;
29
34
private ProjectSnapshotManagerBase _projectManager ;
30
35
private ITagHelperResolver _tagHelperResolver ;
31
36
private bool _disposed ;
32
37
33
- [ ImportingConstructor ]
34
- public DefaultProjectWorkspaceStateGenerator ( ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher )
35
- {
36
- if ( projectSnapshotManagerDispatcher is null )
37
- {
38
- throw new ArgumentNullException ( nameof ( projectSnapshotManagerDispatcher ) ) ;
39
- }
40
-
41
- _projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher ;
42
-
43
- _semaphore = new SemaphoreSlim ( initialCount : 1 ) ;
44
- Updates = new Dictionary < ProjectKey , UpdateItem > ( ) ;
45
- }
46
-
47
38
// Used in unit tests to ensure we can control when background work starts.
48
39
public ManualResetEventSlim BlockBackgroundWorkStart { get ; set ; }
49
40
@@ -134,6 +125,12 @@ private async Task UpdateWorkspaceStateAsync(Project workspaceProject, IProjectS
134
125
return ;
135
126
}
136
127
128
+ // Specifically not using BeginBlock because we want to capture cases where tag helper discovery never finishes.
129
+ var telemetryId = Guid . NewGuid ( ) ;
130
+ _telemetryReporter . ReportEvent ( "taghelperresolve/begin" , Severity . Normal ,
131
+ new Property ( "id" , telemetryId ) ,
132
+ new Property ( "tagHelperCount" , projectSnapshot . ProjectWorkspaceState ? . TagHelpers . Length ?? 0 ) ) ;
133
+
137
134
try
138
135
{
139
136
// Only allow a single TagHelper resolver request to process at a time in order to reduce Visual Studio memory pressure. Typically a TagHelper resolution result can be upwards of 10mb+.
@@ -173,17 +170,35 @@ private async Task UpdateWorkspaceStateAsync(Project workspaceProject, IProjectS
173
170
csharpLanguageVersion = csharpParseOptions . LanguageVersion ;
174
171
}
175
172
173
+ using var _ = StopwatchPool . GetPooledObject ( out var watch ) ;
174
+
175
+ watch . Restart ( ) ;
176
176
var tagHelpers = await _tagHelperResolver . GetTagHelpersAsync ( workspaceProject , projectSnapshot , cancellationToken ) . ConfigureAwait ( false ) ;
177
+ watch . Stop ( ) ;
178
+
179
+ _telemetryReporter . ReportEvent ( "taghelperresolve/end" , Severity . Normal ,
180
+ new Property ( "id" , telemetryId ) ,
181
+ new Property ( "ellapsedms" , watch . ElapsedMilliseconds ) ,
182
+ new Property ( "result" , "success" ) ,
183
+ new Property ( "tagHelperCount" , tagHelpers . Length ) ) ;
184
+
177
185
workspaceState = new ProjectWorkspaceState ( tagHelpers , csharpLanguageVersion ) ;
178
186
}
179
187
}
180
188
catch ( OperationCanceledException )
181
189
{
182
190
// Abort work if we get a task cancelled exception
191
+ _telemetryReporter . ReportEvent ( "taghelperresolve/end" , Severity . Normal ,
192
+ new Property ( "id" , telemetryId ) ,
193
+ new Property ( "result" , "cancel" ) ) ;
183
194
return ;
184
195
}
185
196
catch ( Exception ex )
186
197
{
198
+ _telemetryReporter . ReportEvent ( "taghelperresolve/end" , Severity . Normal ,
199
+ new Property ( "id" , telemetryId ) ,
200
+ new Property ( "result" , "error" ) ) ;
201
+
187
202
await _projectSnapshotManagerDispatcher . RunOnDispatcherThreadAsync (
188
203
( ) => _projectManager . ReportError ( ex , projectSnapshot ) ,
189
204
// Don't allow errors to be cancelled
0 commit comments