From cfad35a3326c0304b79a5dc700357bb6e03aa482 Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Fri, 25 Oct 2024 12:14:28 -0700 Subject: [PATCH 1/5] Reduce the amount of telemetry emitted --- .../CodeActions/CodeActionEndpoint.cs | 3 ++- .../Completion/RazorCompletionEndpoint.cs | 3 ++- .../DocumentPullDiagnosticsEndpoint.cs | 7 ++--- .../MapCode/MapCodeEndpoint.cs | 3 ++- .../Semantic/SemanticTokensRangeEndpoint.cs | 3 ++- .../Telemetry/ITelemetryReporter.cs | 4 +-- .../Telemetry/NoOpTelemetryReporter.cs | 4 +-- .../Telemetry/TelemetryScope.cs | 25 +++++++++++------- .../Telemetry/TelemetryThresholds.cs | 26 +++++++++++++++++++ .../RemoteCSharpSemanticTokensProvider.cs | 6 ++++- .../CohostSemanticTokensRangeEndpoint.cs | 3 ++- .../RazorCustomMessageTarget_CodeActions.cs | 3 ++- .../RazorCustomMessageTarget_Completion.cs | 3 ++- .../RazorCustomMessageTarget_Diagnostics.cs | 3 ++- .../RazorCustomMessageTarget_MapCode.cs | 4 ++- ...RazorCustomMessageTarget_SemanticTokens.cs | 4 ++- .../Telemetry/TelemetryReporter.cs | 12 +++------ .../RazorCustomMessageTargetTest.cs | 10 +++---- .../Telemetry/TelemetryReporterTests.cs | 23 +++++----------- 19 files changed, 92 insertions(+), 57 deletions(-) create mode 100644 src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index 2a2c86bcab2..fcfe08bc6ac 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -8,6 +8,7 @@ using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.CodeActions; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.CodeActions; @@ -57,7 +58,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSCodeActionParams reque } var correlationId = Guid.NewGuid(); - using var __ = _telemetryReporter.TrackLspRequest(LspEndpointName, LanguageServerConstants.RazorLanguageServerName, correlationId); + using var __ = _telemetryReporter.TrackLspRequest(LspEndpointName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CodeActionRazorTelemetryThresholdMS), correlationId); cancellationToken.ThrowIfCancellationRequested(); return await _codeActionsService.GetCodeActionsAsync(request, documentContext, _supportsCodeActionResolve, correlationId, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs index 298e83b4bb7..f49976eb7ab 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Razor.LanguageServer.EndpointContracts; using Microsoft.AspNetCore.Razor.Telemetry; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -77,7 +78,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(CompletionParams request } var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentCompletionName, LanguageServerConstants.RazorLanguageServerName, correlationId); + using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentCompletionName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CompletionRazorTelemetryThresholdMS), correlationId); var completionList = await _completionListProvider.GetCompletionListAsync( hostDocumentIndex, completionContext, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs index ae6dbff95e5..1993c5f4f36 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs @@ -19,6 +19,7 @@ using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Diagnostics; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Diagnostics; @@ -30,7 +31,7 @@ internal class DocumentPullDiagnosticsEndpoint : IRazorRequestHandler _lastReporedProjectTagHelperCount = ImmutableDictionary.Empty; + private ImmutableDictionary _lastReportedProjectTagHelperCount = ImmutableDictionary.Empty; public DocumentPullDiagnosticsEndpoint( LanguageServerFeatureOptions languageServerFeatureOptions, @@ -71,7 +72,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno } var correlationId = Guid.NewGuid(); - using var __ = _telemetryReporter?.TrackLspRequest(VSInternalMethods.DocumentPullDiagnosticName, LanguageServerConstants.RazorLanguageServerName, correlationId); + using var __ = _telemetryReporter?.TrackLspRequest(VSInternalMethods.DocumentPullDiagnosticName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.DiagnosticsRazorTelemetryThresholdMS), correlationId); var documentContext = context.DocumentContext; if (documentContext is null) { @@ -202,7 +203,7 @@ private async ValueTask ReportRZ10012TelemetryAsync(DocumentContext documentCont var shouldReport = false; ImmutableInterlocked.AddOrUpdate( - ref _lastReporedProjectTagHelperCount, + ref _lastReportedProjectTagHelperCount, documentContext.Project.Key, (k) => { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index 029ddb93535..ee1e331f560 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -21,6 +21,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Location = Microsoft.VisualStudio.LanguageServer.Protocol.Location; @@ -70,7 +71,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } var mapCodeCorrelationId = mapperParams.MapCodeCorrelationId ?? Guid.NewGuid(); - using var ts = _telemetryReporter.TrackLspRequest(VSInternalMethods.WorkspaceMapCodeName, LanguageServerConstants.RazorLanguageServerName, mapCodeCorrelationId); + using var ts = _telemetryReporter.TrackLspRequest(VSInternalMethods.WorkspaceMapCodeName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.MapCodeRazorTelemetryThresholdMS), mapCodeCorrelationId); return await HandleMappingsAsync(mapperParams.Mappings, mapCodeCorrelationId, cancellationToken).ConfigureAwait(false); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs index c75e1b44112..420c52a522a 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.Telemetry; using Microsoft.CodeAnalysis.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.Protocol; namespace Microsoft.AspNetCore.Razor.LanguageServer.Semantic; @@ -49,7 +50,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParam var colorBackground = _razorLSPOptionsMonitor.CurrentValue.ColorBackground; var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, LanguageServerConstants.RazorLanguageServerName, correlationId); + using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), correlationId); var data = await _semanticTokensInfoService.GetSemanticTokensAsync(documentContext, request.Range.ToLinePositionSpan(), colorBackground, correlationId, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs index c10db6823d3..5a2cd8a1c1b 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs @@ -11,9 +11,9 @@ internal interface ITelemetryReporter TelemetryScope BeginBlock(string name, Severity severity, Property property); TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2); TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3); - TelemetryScope BeginBlock(string name, Severity severity, params Property[] properties); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties); - TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, Guid correlationId); + TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, TimeSpan minTimeToReport, Guid correlationId); void ReportEvent(string name, Severity severity); void ReportEvent(string name, Severity severity, Property property); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs index 3ad1fa031b3..7e3758c32bb 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs @@ -25,7 +25,7 @@ public TelemetryScope BeginBlock(string name, Severity severity, Property proper public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3) => TelemetryScope.Null; - public TelemetryScope BeginBlock(string name, Severity severity, params Property[] properties) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties) => TelemetryScope.Null; public void ReportEvent(string name, Severity severity) @@ -52,7 +52,7 @@ public void ReportFault(Exception exception, string? message, params object?[] @ { } - public TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, Guid correlationId) + public TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, TimeSpan minTimeToReport, Guid correlationId) => TelemetryScope.Null; public void ReportRequestTiming(string name, string? language, TimeSpan queuedDuration, TimeSpan requestDuration, TelemetryResult result) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs index 641048d44ee..981200faca9 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs @@ -16,6 +16,7 @@ internal sealed class TelemetryScope : IDisposable private readonly Severity _severity; private readonly Property[] _properties; private readonly Stopwatch _stopwatch; + private readonly TimeSpan _minTimeToReport; private bool _disposed; private TelemetryScope() @@ -32,6 +33,7 @@ private TelemetryScope() private TelemetryScope( ITelemetryReporter reporter, string name, + TimeSpan minTimeToReport, Severity severity, Property[] properties) { @@ -45,6 +47,7 @@ private TelemetryScope( _properties = properties; _stopwatch = StopwatchPool.Default.Get(); + _minTimeToReport = minTimeToReport; _stopwatch.Restart(); } @@ -59,10 +62,14 @@ public void Dispose() _stopwatch.Stop(); - // We know that we were created with an array of at least length one. - _properties[^1] = new("eventscope.ellapsedms", _stopwatch.ElapsedMilliseconds); + var elapsed = _stopwatch.Elapsed; + if (elapsed >= _minTimeToReport) + { + // We know that we were created with an array of at least length one. + _properties[^1] = new("eventscope.ellapsedms", _stopwatch.ElapsedMilliseconds); - _reporter.ReportEvent(_name, _severity, _properties); + _reporter.ReportEvent(_name, _severity, _properties); + } StopwatchPool.Default.Return(_stopwatch); } @@ -71,7 +78,7 @@ public static TelemetryScope Create(ITelemetryReporter reporter, string name, Se { var array = new Property[1]; - return new(reporter, name, severity, array); + return new(reporter, name, TimeSpan.Zero, severity, array); } public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property) @@ -79,7 +86,7 @@ public static TelemetryScope Create(ITelemetryReporter reporter, string name, Se var array = new Property[2]; array[0] = property; - return new(reporter, name, severity, array); + return new(reporter, name, TimeSpan.Zero, severity, array); } public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2) @@ -88,7 +95,7 @@ public static TelemetryScope Create(ITelemetryReporter reporter, string name, Se array[0] = property1; array[1] = property2; - return new(reporter, name, severity, array); + return new(reporter, name, TimeSpan.Zero, severity, array); } public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2, Property property3) @@ -98,15 +105,15 @@ public static TelemetryScope Create(ITelemetryReporter reporter, string name, Se array[1] = property2; array[2] = property3; - return new(reporter, name, severity, array); + return new(reporter, name, TimeSpan.Zero, severity, array); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property[] properties) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, Property[] properties) { var array = new Property[properties.Length + 1]; Array.Copy(properties, array, properties.Length); - return new(reporter, name, severity, array); + return new(reporter, name, minTimeToReport, severity, array); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs new file mode 100644 index 00000000000..3bbaf21f5b3 --- /dev/null +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +namespace Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; + +/// +/// A set of constants used to reduce the telemetry emitted to the set that help us understand +/// which LSP is taking the most time in the case that the overall call is lengthy. +/// +internal class TelemetryThresholds +{ + internal const int CodeActionRazorTelemetryThresholdMS = 2000; + internal const int CodeActionSubLSPTelemetryThresholdMS = 1000; + + internal const int CompletionRazorTelemetryThresholdMS = 4000; + internal const int CompletionSubLSPTelemetryThresholdMS = 2000; + + internal const int DiagnosticsRazorTelemetryThresholdMS = 4000; + internal const int DiagnosticsSubLSPTelemetryThresholdMS = 2000; + + internal const int MapCodeRazorTelemetryThresholdMS = 2000; + internal const int MapCodeSubLSPTelemetryThresholdMS = 1000; + + internal const int SemanticTokensRazorTelemetryThresholdMS = 2000; + internal const int SemanticTokensSubLSPTelemetryThresholdMS = 1000; +} diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs index fd1fe4a78d2..d89862d2b92 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Razor.SemanticTokens; using Microsoft.CodeAnalysis.Razor.Workspaces; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.CodeAnalysis.Remote.Razor.ProjectSystem; using Microsoft.CodeAnalysis.Text; @@ -26,7 +27,10 @@ internal class RemoteCSharpSemanticTokensProvider(IFilePathService filePathServi public async Task GetCSharpSemanticTokensResponseAsync(DocumentContext documentContext, ImmutableArray csharpRanges, Guid correlationId, CancellationToken cancellationToken) { - using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync), Constants.ExternalAccessServerName, correlationId); + using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync), + Constants.ExternalAccessServerName, + TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), + correlationId); // We have a razor document, lets find the generated C# document Debug.Assert(documentContext is RemoteDocumentContext, "This method only works on document snapshots created in the OOP process"); diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs index 811c9ea4b98..7f88bab206c 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs @@ -14,6 +14,7 @@ using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost; using Microsoft.CodeAnalysis.Razor.Remote; using Microsoft.CodeAnalysis.Razor.SemanticTokens; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.Settings; @@ -79,7 +80,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie var colorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground; var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, RazorLSPConstants.CohostLanguageServerName, correlationId); + using var _ = _telemetryReporter.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, RazorLSPConstants.CohostLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), correlationId); var tokens = await _remoteServiceInvoker.TryInvokeAsync( razorDocument.Project.Solution, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs index e8f5cd0af35..886306645c8 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs @@ -8,6 +8,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.CodeActions; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Threading; @@ -56,7 +57,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer; var lspMethodName = Methods.TextDocumentCodeActionName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, codeActionParams.CorrelationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CodeActionSubLSPTelemetryThresholdMS), codeActionParams.CorrelationId); var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync>( textBuffer, lspMethodName, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs index 8a85d553cdf..7046dc672cb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs @@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Razor.PooledObjects; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Completion; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using Microsoft.VisualStudio.Razor.Snippets; @@ -121,7 +122,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer; var lspMethodName = Methods.TextDocumentCompletion.Name; ReinvocationResponse? response; - using (_telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, request.CorrelationId)) + using (_telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CompletionSubLSPTelemetryThresholdMS), request.CorrelationId)) { response = await _requestInvoker.ReinvokeRequestOnServerAsync( textBuffer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs index 3329cf7980e..1f658e47bbf 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Protocol.Diagnostics; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.ContainedLanguage; using Microsoft.VisualStudio.LanguageServer.Protocol; using StreamJsonRpc; @@ -78,7 +79,7 @@ internal partial class RazorCustomMessageTarget }; var lspMethodName = VSInternalMethods.DocumentPullDiagnosticName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, delegatedLanguageServerName, correlationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, delegatedLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.DiagnosticsSubLSPTelemetryThresholdMS), correlationId); var response = await _requestInvoker.ReinvokeRequestOnServerAsync( virtualDocument.Snapshot.TextBuffer, lspMethodName, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs index 6588cdc5d95..90fa1bc7eb7 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs @@ -1,9 +1,11 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.Protocol; using StreamJsonRpc; @@ -39,7 +41,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = delegationDetails.Value.TextBuffer; var lspMethodName = VSInternalMethods.WorkspaceMapCodeName; var languageServerName = delegationDetails.Value.LanguageServerName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, request.MapCodeCorrelationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.MapCodeSubLSPTelemetryThresholdMS), request.MapCodeCorrelationId); var response = await _requestInvoker.ReinvokeRequestOnServerAsync( textBuffer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs index d21608c4108..2c4b1a21d72 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; using System.Diagnostics; using System.Linq; using System.Threading; @@ -8,6 +9,7 @@ using Microsoft.CodeAnalysis.Razor.Logging; using Microsoft.CodeAnalysis.Razor.Protocol; using Microsoft.CodeAnalysis.Razor.Workspaces.Protocol.SemanticTokens; +using Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; using Microsoft.VisualStudio.LanguageServer.Protocol; using StreamJsonRpc; @@ -84,7 +86,7 @@ internal partial class RazorCustomMessageTarget var languageServerName = RazorLSPConstants.RazorCSharpLanguageServerName; SemanticTokens? response; - using (var disposable = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, semanticTokensParams.CorrelationId)) + using (var disposable = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensSubLSPTelemetryThresholdMS), semanticTokensParams.CorrelationId)) { try { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs index a7637298b55..db69d268aa4 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs @@ -260,22 +260,18 @@ public TelemetryScope BeginBlock(string name, Severity severity, Property proper public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3) => TelemetryScope.Create(this, name, severity, property1, property2, property3); - public TelemetryScope BeginBlock(string name, Severity severity, params Property[] properties) - => TelemetryScope.Create(this, name, severity, properties); + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties) + => TelemetryScope.Create(this, name, severity, minTimeToReport, properties); - public TelemetryScope TrackLspRequest(string lspMethodName, string languageServerName, Guid correlationId) + public TelemetryScope TrackLspRequest(string lspMethodName, string languageServerName, TimeSpan minTimeToReport, Guid correlationId) { if (correlationId == Guid.Empty) { return TelemetryScope.Null; } - ReportEvent("BeginLspRequest", Severity.Normal, - new("eventscope.method", lspMethodName), - new("eventscope.languageservername", languageServerName), - new("eventscope.correlationid", correlationId)); - return BeginBlock("TrackLspRequest", Severity.Normal, + minTimeToReport, new("eventscope.method", lspMethodName), new("eventscope.languageservername", languageServerName), new("eventscope.correlationid", correlationId)); diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index 99132c4935c..d3633ab8d1b 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -266,7 +266,7 @@ async IAsyncEnumerable> var documentSynchronizer = GetDocumentSynchronizer(GetCSharpSnapshot()); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( @@ -520,8 +520,8 @@ public async Task ProvideSemanticTokensAsync_ContainsRange_ReturnsSemanticTokens It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( @@ -598,8 +598,8 @@ public async Task ProvideSemanticTokensAsync_EmptyRange_ReturnsNoSemanticTokens( It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1),It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Telemetry/TelemetryReporterTests.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Telemetry/TelemetryReporterTests.cs index 2eeab073a0e..f718a5d4c8f 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Telemetry/TelemetryReporterTests.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/Telemetry/TelemetryReporterTests.cs @@ -168,7 +168,7 @@ public void Block_OneArgument() public void Block_TwoArguments() { using var reporter = new TestTelemetryReporter(LoggerFactory); - using (reporter.BeginBlock("EventName", Severity.Normal, new("P1", false), new("P2", "test"))) + using (reporter.BeginBlock("EventName", Severity.Normal, TimeSpan.Zero, new("P1", false), new("P2", "test"))) { } @@ -192,6 +192,7 @@ public void Block_ThreeArguments() var p3Value = Guid.NewGuid(); using (reporter.BeginBlock("EventName", Severity.Normal, + TimeSpan.Zero, new("P1", false), new("P2", "test"), new("P3", p3Value))) @@ -222,6 +223,7 @@ public void Block_FourArguments() var p3Value = Guid.NewGuid(); using (reporter.BeginBlock("EventName", Severity.Normal, + TimeSpan.Zero, new("P1", false), new("P2", "test"), new("P3", p3Value), @@ -296,7 +298,7 @@ public void TrackLspRequest() { using var reporter = new TestTelemetryReporter(LoggerFactory); var correlationId = Guid.NewGuid(); - using (reporter.TrackLspRequest("MethodName", "ServerName", correlationId)) + using (reporter.TrackLspRequest("MethodName", "ServerName", TimeSpan.Zero, correlationId)) { } @@ -304,29 +306,16 @@ public void TrackLspRequest() e1 => { Assert.Equal(TelemetrySeverity.Normal, e1.Severity); - Assert.Equal("dotnet/razor/beginlsprequest", e1.Name); + Assert.Equal("dotnet/razor/tracklsprequest", e1.Name); Assert.True(e1.HasProperties); + Assert.True(e1.Properties["dotnet.razor.eventscope.ellapsedms"] is long); Assert.Equal("MethodName", e1.Properties["dotnet.razor.eventscope.method"]); Assert.Equal("ServerName", e1.Properties["dotnet.razor.eventscope.languageservername"]); var correlationProperty = e1.Properties["dotnet.razor.eventscope.correlationid"] as TelemetryComplexProperty; Assert.NotNull(correlationProperty); Assert.Equal(correlationId, correlationProperty.Value); - }, - e2 => - { - Assert.Equal(TelemetrySeverity.Normal, e2.Severity); - Assert.Equal("dotnet/razor/tracklsprequest", e2.Name); - Assert.True(e2.HasProperties); - - Assert.True(e2.Properties["dotnet.razor.eventscope.ellapsedms"] is long); - Assert.Equal("MethodName", e2.Properties["dotnet.razor.eventscope.method"]); - Assert.Equal("ServerName", e2.Properties["dotnet.razor.eventscope.languageservername"]); - - var correlationProperty = e2.Properties["dotnet.razor.eventscope.correlationid"] as TelemetryComplexProperty; - Assert.NotNull(correlationProperty); - Assert.Equal(correlationId, correlationProperty.Value); }); } From c4576c9afb0392e42e000bd7a31d1d6f6700c4e0 Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Fri, 25 Oct 2024 15:41:01 -0700 Subject: [PATCH 2/5] Accept code review feedback --- .../CodeActions/CodeActionEndpoint.cs | 2 +- .../Completion/RazorCompletionEndpoint.cs | 2 +- .../DocumentPullDiagnosticsEndpoint.cs | 2 +- .../MapCode/MapCodeEndpoint.cs | 2 +- .../Semantic/SemanticTokensRangeEndpoint.cs | 2 +- .../Telemetry/ITelemetryReporter.cs | 10 ++++---- .../Telemetry/ITelemetryReporterExtensions.cs | 16 +++++++++++++ .../Telemetry/NoOpTelemetryReporter.cs | 10 ++++---- .../Telemetry/TelemetryScope.cs | 23 +++++++++--------- .../Telemetry/TelemetryThresholds.cs | 24 ++++++++++--------- .../RemoteCSharpSemanticTokensProvider.cs | 2 +- .../CohostSemanticTokensRangeEndpoint.cs | 2 +- .../RazorCustomMessageTarget_CodeActions.cs | 2 +- .../RazorCustomMessageTarget_Completion.cs | 2 +- .../RazorCustomMessageTarget_Diagnostics.cs | 2 +- .../RazorCustomMessageTarget_MapCode.cs | 3 +-- ...RazorCustomMessageTarget_SemanticTokens.cs | 3 +-- .../Telemetry/TelemetryReporter.cs | 20 ++++++++-------- .../Telemetry/VSTelemetryReporter.cs | 4 ++-- .../RazorCustomMessageTargetTest.cs | 8 +++---- 20 files changed, 78 insertions(+), 63 deletions(-) create mode 100644 src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs index fcfe08bc6ac..d7c781c8f1e 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/CodeActions/CodeActionEndpoint.cs @@ -58,7 +58,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSCodeActionParams reque } var correlationId = Guid.NewGuid(); - using var __ = _telemetryReporter.TrackLspRequest(LspEndpointName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CodeActionRazorTelemetryThresholdMS), correlationId); + using var __ = _telemetryReporter.TrackLspRequest(LspEndpointName, LanguageServerConstants.RazorLanguageServerName, TelemetryThresholds.CodeActionRazorTelemetryThreshold, correlationId); cancellationToken.ThrowIfCancellationRequested(); return await _codeActionsService.GetCodeActionsAsync(request, documentContext, _supportsCodeActionResolve, correlationId, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs index f49976eb7ab..5c29cd9a222 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Completion/RazorCompletionEndpoint.cs @@ -78,7 +78,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(CompletionParams request } var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentCompletionName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CompletionRazorTelemetryThresholdMS), correlationId); + using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentCompletionName, LanguageServerConstants.RazorLanguageServerName, TelemetryThresholds.CompletionRazorTelemetryThreshold, correlationId); var completionList = await _completionListProvider.GetCompletionListAsync( hostDocumentIndex, completionContext, diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs index 1993c5f4f36..ad2838c9a73 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Diagnostics/DocumentPullDiagnosticsEndpoint.cs @@ -72,7 +72,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(VSInternalDocumentDiagno } var correlationId = Guid.NewGuid(); - using var __ = _telemetryReporter?.TrackLspRequest(VSInternalMethods.DocumentPullDiagnosticName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.DiagnosticsRazorTelemetryThresholdMS), correlationId); + using var __ = _telemetryReporter?.TrackLspRequest(VSInternalMethods.DocumentPullDiagnosticName, LanguageServerConstants.RazorLanguageServerName, TelemetryThresholds.DiagnosticsRazorTelemetryThreshold, correlationId); var documentContext = context.DocumentContext; if (documentContext is null) { diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs index ee1e331f560..628052c6f19 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/MapCode/MapCodeEndpoint.cs @@ -71,7 +71,7 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V } var mapCodeCorrelationId = mapperParams.MapCodeCorrelationId ?? Guid.NewGuid(); - using var ts = _telemetryReporter.TrackLspRequest(VSInternalMethods.WorkspaceMapCodeName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.MapCodeRazorTelemetryThresholdMS), mapCodeCorrelationId); + using var ts = _telemetryReporter.TrackLspRequest(VSInternalMethods.WorkspaceMapCodeName, LanguageServerConstants.RazorLanguageServerName, TelemetryThresholds.MapCodeRazorTelemetryThreshold, mapCodeCorrelationId); return await HandleMappingsAsync(mapperParams.Mappings, mapCodeCorrelationId, cancellationToken).ConfigureAwait(false); } diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs index 420c52a522a..5f3e72b28dc 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.LanguageServer/Semantic/SemanticTokensRangeEndpoint.cs @@ -50,7 +50,7 @@ public TextDocumentIdentifier GetTextDocumentIdentifier(SemanticTokensRangeParam var colorBackground = _razorLSPOptionsMonitor.CurrentValue.ColorBackground; var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, LanguageServerConstants.RazorLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), correlationId); + using var _ = _telemetryReporter?.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, LanguageServerConstants.RazorLanguageServerName, TelemetryThresholds.SemanticTokensRazorTelemetryThreshold, correlationId); var data = await _semanticTokensInfoService.GetSemanticTokensAsync(documentContext, request.Range.ToLinePositionSpan(), colorBackground, correlationId, cancellationToken).ConfigureAwait(false); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs index 5a2cd8a1c1b..613d071914f 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporter.cs @@ -7,11 +7,11 @@ namespace Microsoft.AspNetCore.Razor.Telemetry; internal interface ITelemetryReporter { - TelemetryScope BeginBlock(string name, Severity severity); - TelemetryScope BeginBlock(string name, Severity severity, Property property); - TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2); - TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3); - TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2, Property property3); + TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params ReadOnlySpan properties); TelemetryScope TrackLspRequest(string lspMethodName, string lspServerName, TimeSpan minTimeToReport, Guid correlationId); diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs new file mode 100644 index 00000000000..dc41f1755e0 --- /dev/null +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT license. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Razor.Telemetry; + +internal static class ITelemetryReporterExtensions +{ + // These extensions effectively make TimeSpan an optional parameter on BeginBlock + internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity) { return self.BeginBlock(name, severity, TimeSpan.Zero); } + internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property) { return self.BeginBlock(name, severity, TimeSpan.Zero, property); } + internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property1, Property property2) { return self.BeginBlock(name, severity, TimeSpan.Zero, property1, property2); } + internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property1, Property property2, Property property3) { return self.BeginBlock(name, severity, TimeSpan.Zero, property1, property2 , property3); } + internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, params ReadOnlySpan properties) { return self.BeginBlock(name, severity, TimeSpan.Zero, properties); } +} diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs index 7e3758c32bb..d88f044ab0d 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/NoOpTelemetryReporter.cs @@ -13,19 +13,19 @@ private NoOpTelemetryReporter() { } - public TelemetryScope BeginBlock(string name, Severity severity) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport) => TelemetryScope.Null; - public TelemetryScope BeginBlock(string name, Severity severity, Property property) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property) => TelemetryScope.Null; - public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2) => TelemetryScope.Null; - public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2, Property property3) => TelemetryScope.Null; - public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params ReadOnlySpan properties) => TelemetryScope.Null; public void ReportEvent(string name, Severity severity) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs index 981200faca9..26edd0b2103 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs @@ -74,46 +74,45 @@ public void Dispose() StopwatchPool.Default.Return(_stopwatch); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport) { var array = new Property[1]; - return new(reporter, name, TimeSpan.Zero, severity, array); + return new(reporter, name, minTimeToReport, severity, array); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, Property property) { var array = new Property[2]; array[0] = property; - return new(reporter, name, TimeSpan.Zero, severity, array); + return new(reporter, name, minTimeToReport, severity, array); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2) { var array = new Property[3]; array[0] = property1; array[1] = property2; - return new(reporter, name, TimeSpan.Zero, severity, array); + return new(reporter, name, minTimeToReport, severity, array); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2, Property property3) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2, Property property3) { var array = new Property[4]; array[0] = property1; array[1] = property2; array[2] = property3; - return new(reporter, name, TimeSpan.Zero, severity, array); + return new(reporter, name, minTimeToReport, severity, array); } - public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, Property[] properties) + public static TelemetryScope Create(ITelemetryReporter reporter, string name, Severity severity, TimeSpan minTimeToReport, ReadOnlySpan properties) { var array = new Property[properties.Length + 1]; - - Array.Copy(properties, array, properties.Length); - + properties.CopyTo(array); + return new(reporter, name, minTimeToReport, severity, array); } } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs index 3bbaf21f5b3..636dc392c83 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Razor.Workspaces/Telemetry/TelemetryThresholds.cs @@ -1,26 +1,28 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. +using System; + namespace Microsoft.CodeAnalysis.Razor.Workspaces.Telemetry; /// /// A set of constants used to reduce the telemetry emitted to the set that help us understand /// which LSP is taking the most time in the case that the overall call is lengthy. /// -internal class TelemetryThresholds +internal static class TelemetryThresholds { - internal const int CodeActionRazorTelemetryThresholdMS = 2000; - internal const int CodeActionSubLSPTelemetryThresholdMS = 1000; + internal static readonly TimeSpan CodeActionRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000); + internal static readonly TimeSpan CodeActionSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000); - internal const int CompletionRazorTelemetryThresholdMS = 4000; - internal const int CompletionSubLSPTelemetryThresholdMS = 2000; + internal static readonly TimeSpan CompletionRazorTelemetryThreshold = TimeSpan.FromMilliseconds(4000); + internal static readonly TimeSpan CompletionSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(2000); - internal const int DiagnosticsRazorTelemetryThresholdMS = 4000; - internal const int DiagnosticsSubLSPTelemetryThresholdMS = 2000; + internal static readonly TimeSpan DiagnosticsRazorTelemetryThreshold = TimeSpan.FromMilliseconds(4000); + internal static readonly TimeSpan DiagnosticsSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(2000); - internal const int MapCodeRazorTelemetryThresholdMS = 2000; - internal const int MapCodeSubLSPTelemetryThresholdMS = 1000; + internal static readonly TimeSpan MapCodeRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000); + internal static readonly TimeSpan MapCodeSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000); - internal const int SemanticTokensRazorTelemetryThresholdMS = 2000; - internal const int SemanticTokensSubLSPTelemetryThresholdMS = 1000; + internal static readonly TimeSpan SemanticTokensRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000); + internal static readonly TimeSpan SemanticTokensSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000); } diff --git a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs index d89862d2b92..f797efb1be6 100644 --- a/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs +++ b/src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/SemanticTokens/RemoteCSharpSemanticTokensProvider.cs @@ -29,7 +29,7 @@ internal class RemoteCSharpSemanticTokensProvider(IFilePathService filePathServi { using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync), Constants.ExternalAccessServerName, - TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), + TelemetryThresholds.SemanticTokensRazorTelemetryThreshold, correlationId); // We have a razor document, lets find the generated C# document diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs index 7f88bab206c..a2fe70bd472 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Cohost/CohostSemanticTokensRangeEndpoint.cs @@ -80,7 +80,7 @@ public ImmutableArray GetRegistrations(VSInternalClientCapabilitie var colorBackground = _clientSettingsManager.GetClientSettings().AdvancedSettings.ColorBackground; var correlationId = Guid.NewGuid(); - using var _ = _telemetryReporter.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, RazorLSPConstants.CohostLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensRazorTelemetryThresholdMS), correlationId); + using var _ = _telemetryReporter.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, RazorLSPConstants.CohostLanguageServerName, TelemetryThresholds.SemanticTokensRazorTelemetryThreshold, correlationId); var tokens = await _remoteServiceInvoker.TryInvokeAsync( razorDocument.Project.Solution, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs index 886306645c8..49510c508eb 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_CodeActions.cs @@ -57,7 +57,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer; var lspMethodName = Methods.TextDocumentCodeActionName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CodeActionSubLSPTelemetryThresholdMS), codeActionParams.CorrelationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TelemetryThresholds.CodeActionSubLSPTelemetryThreshold, codeActionParams.CorrelationId); var requests = _requestInvoker.ReinvokeRequestOnMultipleServersAsync>( textBuffer, lspMethodName, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs index 7046dc672cb..0bd1655150d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Completion.cs @@ -122,7 +122,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = virtualDocumentSnapshot.Snapshot.TextBuffer; var lspMethodName = Methods.TextDocumentCompletion.Name; ReinvocationResponse? response; - using (_telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.CompletionSubLSPTelemetryThresholdMS), request.CorrelationId)) + using (_telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TelemetryThresholds.CompletionSubLSPTelemetryThreshold, request.CorrelationId)) { response = await _requestInvoker.ReinvokeRequestOnServerAsync( textBuffer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs index 1f658e47bbf..cfdbc4b3b1d 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_Diagnostics.cs @@ -79,7 +79,7 @@ internal partial class RazorCustomMessageTarget }; var lspMethodName = VSInternalMethods.DocumentPullDiagnosticName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, delegatedLanguageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.DiagnosticsSubLSPTelemetryThresholdMS), correlationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, delegatedLanguageServerName, TelemetryThresholds.DiagnosticsSubLSPTelemetryThreshold, correlationId); var response = await _requestInvoker.ReinvokeRequestOnServerAsync( virtualDocument.Snapshot.TextBuffer, lspMethodName, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs index 90fa1bc7eb7..0499515498b 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_MapCode.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Razor.Protocol; @@ -41,7 +40,7 @@ internal partial class RazorCustomMessageTarget var textBuffer = delegationDetails.Value.TextBuffer; var lspMethodName = VSInternalMethods.WorkspaceMapCodeName; var languageServerName = delegationDetails.Value.LanguageServerName; - using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.MapCodeSubLSPTelemetryThresholdMS), request.MapCodeCorrelationId); + using var _ = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TelemetryThresholds.MapCodeSubLSPTelemetryThreshold, request.MapCodeCorrelationId); var response = await _requestInvoker.ReinvokeRequestOnServerAsync( textBuffer, diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs index 2c4b1a21d72..9cabff2fb78 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/LanguageClient/Endpoints/RazorCustomMessageTarget_SemanticTokens.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT license. See License.txt in the project root for license information. -using System; using System.Diagnostics; using System.Linq; using System.Threading; @@ -86,7 +85,7 @@ internal partial class RazorCustomMessageTarget var languageServerName = RazorLSPConstants.RazorCSharpLanguageServerName; SemanticTokens? response; - using (var disposable = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TimeSpan.FromMilliseconds(TelemetryThresholds.SemanticTokensSubLSPTelemetryThresholdMS), semanticTokensParams.CorrelationId)) + using (var disposable = _telemetryReporter.TrackLspRequest(lspMethodName, languageServerName, TelemetryThresholds.SemanticTokensSubLSPTelemetryThreshold, semanticTokensParams.CorrelationId)) { try { diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs index db69d268aa4..af902d253f9 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/TelemetryReporter.cs @@ -237,7 +237,7 @@ protected virtual void Report(TelemetryEvent telemetryEvent) } } - protected virtual bool HandleException(Exception exception, string? message, params object?[] @params) + protected virtual bool HandleException(Exception exception, string? message, params ReadOnlySpan @params) => false; protected virtual void LogTrace(string message) @@ -248,19 +248,19 @@ protected virtual void LogError(Exception exception, string message) { } - public TelemetryScope BeginBlock(string name, Severity severity) - => TelemetryScope.Create(this, name, severity); + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport) + => TelemetryScope.Create(this, name, severity, minTimeToReport); - public TelemetryScope BeginBlock(string name, Severity severity, Property property) - => TelemetryScope.Create(this, name, severity, property); + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property) + => TelemetryScope.Create(this, name, severity, minTimeToReport, property); - public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2) - => TelemetryScope.Create(this, name, severity, property1, property2); + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2) + => TelemetryScope.Create(this, name, severity, minTimeToReport, property1, property2); - public TelemetryScope BeginBlock(string name, Severity severity, Property property1, Property property2, Property property3) - => TelemetryScope.Create(this, name, severity, property1, property2, property3); + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, Property property1, Property property2, Property property3) + => TelemetryScope.Create(this, name, severity, minTimeToReport, property1, property2, property3); - public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params Property[] properties) + public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params ReadOnlySpan properties) => TelemetryScope.Create(this, name, severity, minTimeToReport, properties); public TelemetryScope TrackLspRequest(string lspMethodName, string languageServerName, TimeSpan minTimeToReport, Guid correlationId) diff --git a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/VSTelemetryReporter.cs b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/VSTelemetryReporter.cs index 9983997d9f5..f3df00677be 100644 --- a/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/VSTelemetryReporter.cs +++ b/src/Razor/src/Microsoft.VisualStudio.LanguageServices.Razor/Telemetry/VSTelemetryReporter.cs @@ -21,7 +21,7 @@ public void Dispose() Flush(); } - protected override bool HandleException(Exception exception, string? message, params object?[] @params) + protected override bool HandleException(Exception exception, string? message, params ReadOnlySpan @params) { if (exception is RemoteInvocationException remoteInvocationException) { @@ -34,7 +34,7 @@ protected override bool HandleException(Exception exception, string? message, pa return false; } - private bool ReportRemoteInvocationException(RemoteInvocationException remoteInvocationException, object?[] @params) + private bool ReportRemoteInvocationException(RemoteInvocationException remoteInvocationException, ReadOnlySpan @params) { if (remoteInvocationException.InnerException is Exception innerException) { diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index d3633ab8d1b..4796ba76847 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -520,8 +520,8 @@ public async Task ProvideSemanticTokensAsync_ContainsRange_ReturnsSemanticTokens It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( @@ -598,8 +598,8 @@ public async Task ProvideSemanticTokensAsync_EmptyRange_ReturnsNoSemanticTokens( It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1),It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( From 3aa876be158720dd4a8395f1946e9d0f7fb41f72 Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Mon, 28 Oct 2024 08:49:52 -0700 Subject: [PATCH 3/5] Accept code review feedback (2) --- .../Telemetry/ITelemetryReporterExtensions.cs | 19 +++++++++++----- .../RazorCustomMessageTargetTest.cs | 22 ++++++++++++++----- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs index dc41f1755e0..fb21f9c2328 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/ITelemetryReporterExtensions.cs @@ -8,9 +8,18 @@ namespace Microsoft.AspNetCore.Razor.Telemetry; internal static class ITelemetryReporterExtensions { // These extensions effectively make TimeSpan an optional parameter on BeginBlock - internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity) { return self.BeginBlock(name, severity, TimeSpan.Zero); } - internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property) { return self.BeginBlock(name, severity, TimeSpan.Zero, property); } - internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property1, Property property2) { return self.BeginBlock(name, severity, TimeSpan.Zero, property1, property2); } - internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, Property property1, Property property2, Property property3) { return self.BeginBlock(name, severity, TimeSpan.Zero, property1, property2 , property3); } - internal static TelemetryScope BeginBlock(this ITelemetryReporter self, string name, Severity severity, params ReadOnlySpan properties) { return self.BeginBlock(name, severity, TimeSpan.Zero, properties); } + public static TelemetryScope BeginBlock(this ITelemetryReporter reporter, string name, Severity severity) + => reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero); + + public static TelemetryScope BeginBlock(this ITelemetryReporter reporter, string name, Severity severity, Property property) + => reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero, property); + + public static TelemetryScope BeginBlock(this ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2) + => reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero, property1, property2); + + public static TelemetryScope BeginBlock(this ITelemetryReporter reporter, string name, Severity severity, Property property1, Property property2, Property property3) + => reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero, property1, property2, property3); + + public static TelemetryScope BeginBlock(this ITelemetryReporter reporter, string name, Severity severity, params ReadOnlySpan properties) + => reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero, properties); } diff --git a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs index 4796ba76847..ff972ab7869 100644 --- a/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs +++ b/src/Razor/test/Microsoft.VisualStudio.LanguageServices.Razor.Test/LanguageClient/RazorCustomMessageTargetTest.cs @@ -266,7 +266,9 @@ async IAsyncEnumerable> var documentSynchronizer = GetDocumentSynchronizer(GetCSharpSnapshot()); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), TimeSpan.FromSeconds(1), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s1, s2, ts, g) => Assert.NotEqual(TimeSpan.Zero, ts)) + .Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( @@ -520,8 +522,13 @@ public async Task ProvideSemanticTokensAsync_ContainsRange_ReturnsSemanticTokens It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s1, s2, ts, g) => Assert.NotEqual(TimeSpan.Zero, ts)) + .Returns(TelemetryScope.Null); + + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s1, s2, ts, g) => Assert.NotEqual(TimeSpan.Zero, ts)) + .Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( @@ -598,8 +605,13 @@ public async Task ProvideSemanticTokensAsync_EmptyRange_ReturnsNoSemanticTokens( It.IsAny())) .ReturnsAsync(new DefaultLSPDocumentSynchronizer.SynchronizedResult(true, csharpVirtualDocument)); var telemetryReporter = new Mock(MockBehavior.Strict); - telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); - telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())).Returns(TelemetryScope.Null); + telemetryReporter.Setup(r => r.BeginBlock(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s, sev, ts, p) => Assert.NotEqual(TimeSpan.Zero, ts)) + .Returns(TelemetryScope.Null); + + telemetryReporter.Setup(r => r.TrackLspRequest(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((s1, s2, ts, g) => Assert.NotEqual(TimeSpan.Zero, ts)) + .Returns(TelemetryScope.Null); var csharpVirtualDocumentAddListener = new CSharpVirtualDocumentAddListener(LoggerFactory); var target = new RazorCustomMessageTarget( From b5703f9a99adda191e79d49896a92564ff81045c Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Mon, 28 Oct 2024 09:45:50 -0700 Subject: [PATCH 4/5] Change TelemetryScope to NonCopyable struct; if the default constructor is used, _reporter is null so no "report" happens on Dispose. If the _reporter check were removed from Dispose, multiple unittests would fail. --- .../Telemetry/TelemetryScope.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs index 26edd0b2103..b3a3c731ff7 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs @@ -4,10 +4,12 @@ using System; using System.Diagnostics; using Microsoft.AspNetCore.Razor.PooledObjects; +using Microsoft.AspNetCore.Razor.Utilities; namespace Microsoft.AspNetCore.Razor.Telemetry; -internal sealed class TelemetryScope : IDisposable +[NonCopyable] +internal struct TelemetryScope : IDisposable { public static readonly TelemetryScope Null = new(); @@ -19,9 +21,9 @@ internal sealed class TelemetryScope : IDisposable private readonly TimeSpan _minTimeToReport; private bool _disposed; - private TelemetryScope() + public TelemetryScope() { - // This constructor is only called to initialize the Null instance + // This constructor should be called only to initialize the Null instance // above. Rather than make _name, _properties, and _stopwatch // nullable, we use a ! to initialize them to null for this case only. _reporter = null; From c021a559fdfea97e115432fcf11bfd17509ccf9b Mon Sep 17 00:00:00 2001 From: Phil Allen Date: Mon, 28 Oct 2024 12:26:20 -0700 Subject: [PATCH 5/5] Undo telemetry-scope-as-struct changes --- .../Telemetry/TelemetryScope.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs index b3a3c731ff7..26edd0b2103 100644 --- a/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs +++ b/src/Razor/src/Microsoft.AspNetCore.Razor.ProjectEngineHost/Telemetry/TelemetryScope.cs @@ -4,12 +4,10 @@ using System; using System.Diagnostics; using Microsoft.AspNetCore.Razor.PooledObjects; -using Microsoft.AspNetCore.Razor.Utilities; namespace Microsoft.AspNetCore.Razor.Telemetry; -[NonCopyable] -internal struct TelemetryScope : IDisposable +internal sealed class TelemetryScope : IDisposable { public static readonly TelemetryScope Null = new(); @@ -21,9 +19,9 @@ internal struct TelemetryScope : IDisposable private readonly TimeSpan _minTimeToReport; private bool _disposed; - public TelemetryScope() + private TelemetryScope() { - // This constructor should be called only to initialize the Null instance + // This constructor is only called to initialize the Null instance // above. Rather than make _name, _properties, and _stopwatch // nullable, we use a ! to initialize them to null for this case only. _reporter = null;