Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bring telemetry back for semantic tokens in cohosting #10121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -12,5 +13,6 @@ internal interface IOutOfProcSemanticTokensService
ValueTask<int[]?> GetSemanticTokensDataAsync(
TextDocument razorDocument,
LinePositionSpan span,
Guid correlationId,
CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -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.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.ExternalAccess.Razor;
Expand All @@ -15,5 +16,6 @@ internal interface IRemoteSemanticTokensService
DocumentId razorDocumentId,
LinePositionSpan span,
bool colorBackground,
Guid correlationId,
CancellationToken cancellationToken);
}
12 changes: 12 additions & 0 deletions src/Razor/src/Microsoft.CodeAnalysis.Remote.Razor/Constants.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.Remote.Razor;

internal static class Constants
{
/// <summary>
/// The name we use for the "server" in cohosting, which is not really an LSP server, but we use it for telemetry to distinguish events
/// </summary>
public const string ExternalAccessServerName = "Razor.ExternalAccess";
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost.Handlers;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.SemanticTokens;
Expand All @@ -19,12 +20,15 @@ namespace Microsoft.CodeAnalysis.Remote.Razor.SemanticTokens;

[Export(typeof(ICSharpSemanticTokensProvider)), Shared]
[method: ImportingConstructor]
internal class RemoteCSharpSemanticTokensProvider(IFilePathService filePathService) : ICSharpSemanticTokensProvider
internal class RemoteCSharpSemanticTokensProvider(IFilePathService filePathService, ITelemetryReporter telemetryReporter) : ICSharpSemanticTokensProvider
{
private readonly IFilePathService _filePathService = filePathService;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;

public async Task<int[]?> GetCSharpSemanticTokensResponseAsync(VersionedDocumentContext documentContext, ImmutableArray<LinePositionSpan> csharpRanges, Guid correlationId, CancellationToken cancellationToken)
{
using var _ = _telemetryReporter.TrackLspRequest(nameof(SemanticTokensRange.GetSemanticTokensAsync), Constants.ExternalAccessServerName, correlationId);

// We have a razor document, lets find the generated C# document
var generatedDocument = GetGeneratedDocument(documentContext);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ internal sealed class RemoteSemanticTokensService(
private readonly IRazorSemanticTokensInfoService _razorSemanticTokensInfoService = razorSemanticTokensInfoService;
private readonly DocumentSnapshotFactory _documentSnapshotFactory = documentSnapshotFactory;

public ValueTask<int[]?> GetSemanticTokensDataAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, LinePositionSpan span, bool colorBackground, CancellationToken cancellationToken)
public ValueTask<int[]?> GetSemanticTokensDataAsync(RazorPinnedSolutionInfoWrapper solutionInfo, DocumentId razorDocumentId, LinePositionSpan span, bool colorBackground, Guid correlationId, CancellationToken cancellationToken)
=> RazorBrokeredServiceImplementation.RunServiceAsync(
solutionInfo,
ServiceBrokerClient,
solution => GetSemanticTokensDataAsync(solution, razorDocumentId, span, colorBackground, cancellationToken),
solution => GetSemanticTokensDataAsync(solution, razorDocumentId, span, colorBackground, correlationId, cancellationToken),
cancellationToken);

private async ValueTask<int[]?> GetSemanticTokensDataAsync(Solution solution, DocumentId razorDocumentId, LinePositionSpan span, bool colorBackground, CancellationToken cancellationToken)
private async ValueTask<int[]?> GetSemanticTokensDataAsync(Solution solution, DocumentId razorDocumentId, LinePositionSpan span, bool colorBackground, Guid correlationId, CancellationToken cancellationToken)
{
var razorDocument = solution.GetAdditionalDocument(razorDocumentId);
if (razorDocument is null)
Expand All @@ -42,7 +42,7 @@ internal sealed class RemoteSemanticTokensService(
var documentContext = Create(razorDocument);

// TODO: Telemetry?
return await _razorSemanticTokensInfoService.GetSemanticTokensAsync(documentContext, span, colorBackground, Guid.Empty, cancellationToken).ConfigureAwait(false);
return await _razorSemanticTokensInfoService.GetSemanticTokensAsync(documentContext, span, colorBackground, correlationId, cancellationToken).ConfigureAwait(false);
}

public VersionedDocumentContext Create(TextDocument textDocument)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// 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.Composition;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.ExternalAccess.Razor.Cohost;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.SemanticTokens;
Expand All @@ -25,11 +27,13 @@ namespace Microsoft.VisualStudio.LanguageServerClient.Razor.Cohost;
internal sealed class CohostSemanticTokensRangeEndpoint(
IOutOfProcSemanticTokensService semanticTokensInfoService,
ISemanticTokensLegendService semanticTokensLegendService,
ITelemetryReporter telemetryReporter,
IRazorLoggerFactory loggerFactory)
: AbstractRazorCohostDocumentRequestHandler<SemanticTokensRangeParams, SemanticTokens?>, ICapabilitiesProvider
{
private readonly IOutOfProcSemanticTokensService _semanticTokensInfoService = semanticTokensInfoService;
private readonly ISemanticTokensLegendService _semanticTokensLegendService = semanticTokensLegendService;
private readonly ITelemetryReporter _telemetryReporter = telemetryReporter;
private readonly ILogger _logger = loggerFactory.CreateLogger<CohostSemanticTokensRangeEndpoint>();

protected override bool MutatesSolutionState => false;
Expand All @@ -45,7 +49,10 @@ public void ApplyCapabilities(VSInternalServerCapabilities serverCapabilities, V

protected override async Task<SemanticTokens?> HandleRequestAsync(SemanticTokensRangeParams request, RazorCohostRequestContext context, CancellationToken cancellationToken)
{
var data = await _semanticTokensInfoService.GetSemanticTokensDataAsync(context.TextDocument.AssumeNotNull(), request.Range.ToLinePositionSpan(), cancellationToken);
var correlationId = Guid.NewGuid();
using var _ = _telemetryReporter.TrackLspRequest(Methods.TextDocumentSemanticTokensRangeName, RazorLSPConstants.CohostLanguageServerName, correlationId);

var data = await _semanticTokensInfoService.GetSemanticTokensDataAsync(context.TextDocument.AssumeNotNull(), request.Range.ToLinePositionSpan(), correlationId, cancellationToken);

if (data is null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ internal static class RazorLSPConstants

public const string RazorLanguageServerName = "Razor Language Server Client";

public const string CohostLanguageServerName = "Cohosted Razor Language Server Client";

public const string HtmlLanguageServerName = "HtmlDelegationLanguageServerClient";

public const string CSHTMLFileExtension = ".cshtml";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal class OutOfProcSemanticTokensService(IRemoteClientProvider remoteClient
private readonly IClientSettingsManager _clientSettingsManager = clientSettingsManager;
private readonly ILogger _logger = loggerFactory.CreateLogger<OutOfProcSemanticTokensService>();

public async ValueTask<int[]?> GetSemanticTokensDataAsync(TextDocument razorDocument, LinePositionSpan span, CancellationToken cancellationToken)
public async ValueTask<int[]?> GetSemanticTokensDataAsync(TextDocument razorDocument, LinePositionSpan span, Guid correlationId, CancellationToken cancellationToken)
{
// We're being overly defensive here because the OOP host can return null for the client/session/operation
// when it's disconnected (user stops the process).
Expand All @@ -43,7 +43,7 @@ internal class OutOfProcSemanticTokensService(IRemoteClientProvider remoteClient

var data = await remoteClient.TryInvokeAsync<IRemoteSemanticTokensService, int[]?>(
razorDocument.Project.Solution,
(service, solutionInfo, cancellationToken) => service.GetSemanticTokensDataAsync(solutionInfo, razorDocument.Id, span, colorBackground, cancellationToken),
(service, solutionInfo, cancellationToken) => service.GetSemanticTokensDataAsync(solutionInfo, razorDocument.Id, span, colorBackground, correlationId, cancellationToken),
cancellationToken).ConfigureAwait(false);

if (!data.HasValue)
Expand Down