Skip to content

Commit fbb614f

Browse files
committed
Log telemetry for tag helper discovery
1 parent 1be8083 commit fbb614f

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/DefaultProjectWorkspaceStateGenerator.cs

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
using System.Diagnostics;
1010
using System.Threading;
1111
using System.Threading.Tasks;
12+
using Microsoft.AspNetCore.Razor.PooledObjects;
1213
using Microsoft.AspNetCore.Razor.ProjectSystem;
14+
using Microsoft.AspNetCore.Razor.Telemetry;
1315
using Microsoft.CodeAnalysis.CSharp;
1416
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
1517
using Microsoft.CodeAnalysis.Razor.Workspaces;
@@ -19,31 +21,20 @@ namespace Microsoft.CodeAnalysis.Razor;
1921
[Shared]
2022
[Export(typeof(ProjectWorkspaceStateGenerator))]
2123
[Export(typeof(IProjectSnapshotChangeTrigger))]
22-
internal class DefaultProjectWorkspaceStateGenerator : ProjectWorkspaceStateGenerator, IDisposable
24+
[method: ImportingConstructor]
25+
internal class DefaultProjectWorkspaceStateGenerator(ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher, ITelemetryReporter telemetryReporter) : ProjectWorkspaceStateGenerator, IDisposable
2326
{
2427
// 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);
2633

27-
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
28-
private readonly SemaphoreSlim _semaphore;
2934
private ProjectSnapshotManagerBase _projectManager;
3035
private ITagHelperResolver _tagHelperResolver;
3136
private bool _disposed;
3237

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-
4738
// Used in unit tests to ensure we can control when background work starts.
4839
public ManualResetEventSlim BlockBackgroundWorkStart { get; set; }
4940

@@ -134,6 +125,12 @@ private async Task UpdateWorkspaceStateAsync(Project workspaceProject, IProjectS
134125
return;
135126
}
136127

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+
137134
try
138135
{
139136
// 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
173170
csharpLanguageVersion = csharpParseOptions.LanguageVersion;
174171
}
175172

173+
using var _ = StopwatchPool.GetPooledObject(out var watch);
174+
175+
watch.Restart();
176176
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+
177185
workspaceState = new ProjectWorkspaceState(tagHelpers, csharpLanguageVersion);
178186
}
179187
}
180188
catch (OperationCanceledException)
181189
{
182190
// 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"));
183194
return;
184195
}
185196
catch (Exception ex)
186197
{
198+
_telemetryReporter.ReportEvent("taghelperresolve/end", Severity.Normal,
199+
new Property("id", telemetryId),
200+
new Property("result", "error"));
201+
187202
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
188203
() => _projectManager.ReportError(ex, projectSnapshot),
189204
// Don't allow errors to be cancelled

src/Razor/test/Microsoft.VisualStudio.Editor.Razor.Test/DefaultProjectWorkspaceStateGeneratorTest.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Threading.Tasks;
1212
using Microsoft.AspNetCore.Razor.Language;
1313
using Microsoft.AspNetCore.Razor.ProjectSystem;
14+
using Microsoft.AspNetCore.Razor.Telemetry;
1415
using Microsoft.CodeAnalysis.Host;
1516
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
1617
using Xunit;
@@ -58,7 +59,7 @@ public DefaultProjectWorkspaceStateGeneratorTest(ITestOutputHelper testOutput)
5859
public void Dispose_MakesUpdateNoop()
5960
{
6061
// Arrange
61-
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher))
62+
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
6263
{
6364
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
6465

@@ -75,7 +76,7 @@ public void Dispose_MakesUpdateNoop()
7576
public void Update_StartsUpdateTask()
7677
{
7778
// Arrange
78-
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher))
79+
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
7980
{
8081
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
8182

@@ -92,7 +93,7 @@ public void Update_StartsUpdateTask()
9293
public void Update_SoftCancelsIncompleteTaskForSameProject()
9394
{
9495
// Arrange
95-
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher))
96+
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
9697
{
9798
stateGenerator.BlockBackgroundWorkStart = new ManualResetEventSlim(initialState: false);
9899
stateGenerator.Update(_workspaceProject, _projectSnapshot, DisposalToken);
@@ -110,7 +111,7 @@ public void Update_SoftCancelsIncompleteTaskForSameProject()
110111
public async Task Update_NullWorkspaceProject_ClearsProjectWorkspaceState()
111112
{
112113
// Arrange
113-
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher))
114+
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
114115
{
115116
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
116117
var projectManager = new TestProjectSnapshotManager(_workspace, Dispatcher);
@@ -134,7 +135,7 @@ public async Task Update_NullWorkspaceProject_ClearsProjectWorkspaceState()
134135
public async Task Update_ResolvesTagHelpersAndUpdatesWorkspaceState()
135136
{
136137
// Arrange
137-
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher))
138+
using (var stateGenerator = new DefaultProjectWorkspaceStateGenerator(Dispatcher, NoOpTelemetryReporter.Instance))
138139
{
139140
stateGenerator.NotifyBackgroundWorkCompleted = new ManualResetEventSlim(initialState: false);
140141
var projectManager = new TestProjectSnapshotManager(_workspace, Dispatcher);

0 commit comments

Comments
 (0)