Skip to content

Commit

Permalink
Reduce the amount of telemetry emitted (dotnet#11094)
Browse files Browse the repository at this point in the history
* Reduce the amount of telemetry emitted

* Accept code review feedback

* Accept code review feedback (2)

* 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.

* Undo telemetry-scope-as-struct changes
  • Loading branch information
phil-allen-msft authored Oct 28, 2024
1 parent 45b65b3 commit ad74439
Show file tree
Hide file tree
Showing 21 changed files with 154 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, TelemetryThresholds.CodeActionRazorTelemetryThreshold, correlationId);
cancellationToken.ThrowIfCancellationRequested();

return await _codeActionsService.GetCodeActionsAsync(request, documentContext, _supportsCodeActionResolve, correlationId, cancellationToken).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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, TelemetryThresholds.CompletionRazorTelemetryThreshold, correlationId);
var completionList = await _completionListProvider.GetCompletionListAsync(
hostDocumentIndex,
completionContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,7 +31,7 @@ internal class DocumentPullDiagnosticsEndpoint : IRazorRequestHandler<VSInternal
private readonly IClientConnection _clientConnection;
private readonly RazorTranslateDiagnosticsService _translateDiagnosticsService;
private readonly ITelemetryReporter? _telemetryReporter;
private ImmutableDictionary<ProjectKey, int> _lastReporedProjectTagHelperCount = ImmutableDictionary<ProjectKey, int>.Empty;
private ImmutableDictionary<ProjectKey, int> _lastReportedProjectTagHelperCount = ImmutableDictionary<ProjectKey, int>.Empty;

public DocumentPullDiagnosticsEndpoint(
LanguageServerFeatureOptions languageServerFeatureOptions,
Expand Down Expand Up @@ -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, TelemetryThresholds.DiagnosticsRazorTelemetryThreshold, correlationId);
var documentContext = context.DocumentContext;
if (documentContext is null)
{
Expand Down Expand Up @@ -202,7 +203,7 @@ private async ValueTask ReportRZ10012TelemetryAsync(DocumentContext documentCont
var shouldReport = false;

ImmutableInterlocked.AddOrUpdate(
ref _lastReporedProjectTagHelperCount,
ref _lastReportedProjectTagHelperCount,
documentContext.Project.Key,
(k) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, TelemetryThresholds.MapCodeRazorTelemetryThreshold, mapCodeCorrelationId);

return await HandleMappingsAsync(mapperParams.Mappings, mapCodeCorrelationId, cancellationToken).ConfigureAwait(false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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, TelemetryThresholds.SemanticTokensRazorTelemetryThreshold, correlationId);

var data = await _semanticTokensInfoService.GetSemanticTokensAsync(documentContext, request.Range.ToLinePositionSpan(), colorBackground, correlationId, cancellationToken).ConfigureAwait(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ 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, 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<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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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
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<Property> properties)
=> reporter.BeginBlock(name, severity, minTimeToReport: TimeSpan.Zero, properties);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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, params Property[] properties)
public TelemetryScope BeginBlock(string name, Severity severity, TimeSpan minTimeToReport, params ReadOnlySpan<Property> properties)
=> TelemetryScope.Null;

public void ReportEvent(string name, Severity severity)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -32,6 +33,7 @@ private TelemetryScope()
private TelemetryScope(
ITelemetryReporter reporter,
string name,
TimeSpan minTimeToReport,
Severity severity,
Property[] properties)
{
Expand All @@ -45,6 +47,7 @@ private TelemetryScope(
_properties = properties;

_stopwatch = StopwatchPool.Default.Get();
_minTimeToReport = minTimeToReport;
_stopwatch.Restart();
}

Expand All @@ -59,54 +62,57 @@ 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);
}

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, 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, 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, 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, severity, array);
return new(reporter, name, minTimeToReport, 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, ReadOnlySpan<Property> properties)
{
var array = new Property[properties.Length + 1];

Array.Copy(properties, array, properties.Length);

return new(reporter, name, severity, array);
properties.CopyTo(array);

return new(reporter, name, minTimeToReport, severity, array);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +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;

/// <summary>
/// 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.
/// </summary>
internal static class TelemetryThresholds
{
internal static readonly TimeSpan CodeActionRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000);
internal static readonly TimeSpan CodeActionSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000);

internal static readonly TimeSpan CompletionRazorTelemetryThreshold = TimeSpan.FromMilliseconds(4000);
internal static readonly TimeSpan CompletionSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(2000);

internal static readonly TimeSpan DiagnosticsRazorTelemetryThreshold = TimeSpan.FromMilliseconds(4000);
internal static readonly TimeSpan DiagnosticsSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(2000);

internal static readonly TimeSpan MapCodeRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000);
internal static readonly TimeSpan MapCodeSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000);

internal static readonly TimeSpan SemanticTokensRazorTelemetryThreshold = TimeSpan.FromMilliseconds(2000);
internal static readonly TimeSpan SemanticTokensSubLSPTelemetryThreshold = TimeSpan.FromMilliseconds(1000);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -26,7 +27,10 @@ internal class RemoteCSharpSemanticTokensProvider(IFilePathService filePathServi

public async Task<int[]?> GetCSharpSemanticTokensResponseAsync(DocumentContext documentContext, ImmutableArray<LinePositionSpan> csharpRanges, Guid correlationId, CancellationToken cancellationToken)
{
using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync), Constants.ExternalAccessServerName, correlationId);
using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync),
Constants.ExternalAccessServerName,
TelemetryThresholds.SemanticTokensRazorTelemetryThreshold,
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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -79,7 +80,7 @@ public ImmutableArray<Registration> 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, TelemetryThresholds.SemanticTokensRazorTelemetryThreshold, correlationId);

var tokens = await _remoteServiceInvoker.TryInvokeAsync<IRemoteSemanticTokensService, int[]?>(
razorDocument.Project.Solution,
Expand Down
Loading

0 comments on commit ad74439

Please sign in to comment.