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

Fix some more unnecessary NFW reporting #75403

Merged
merged 1 commit into from
Oct 8, 2024
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
Expand Up @@ -5,6 +5,7 @@
using Microsoft.CodeAnalysis.LanguageServer.LanguageServer;
using Microsoft.Extensions.Logging;
using Roslyn.LanguageServer.Protocol;
using StreamJsonRpc;

namespace Microsoft.CodeAnalysis.LanguageServer.Logging;

Expand Down Expand Up @@ -59,20 +60,28 @@ public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Except
if (message != null && logLevel != LogLevel.None)
{
message = $"[{_categoryName}] {message}";
var _ = server.GetRequiredLspService<IClientLanguageServerManager>().SendNotificationAsync(Methods.WindowLogMessageName, new LogMessageParams()
try
{
Message = message,
MessageType = logLevel switch
var _ = server.GetRequiredLspService<IClientLanguageServerManager>().SendNotificationAsync(Methods.WindowLogMessageName, new LogMessageParams()
{
LogLevel.Trace => MessageType.Log,
LogLevel.Debug => MessageType.Log,
LogLevel.Information => MessageType.Info,
LogLevel.Warning => MessageType.Warning,
LogLevel.Error => MessageType.Error,
LogLevel.Critical => MessageType.Error,
_ => throw new InvalidOperationException($"Unexpected logLevel argument {logLevel}"),
}
}, CancellationToken.None);
Message = message,
MessageType = logLevel switch
{
LogLevel.Trace => MessageType.Log,
LogLevel.Debug => MessageType.Log,
LogLevel.Information => MessageType.Info,
LogLevel.Warning => MessageType.Warning,
LogLevel.Error => MessageType.Error,
LogLevel.Critical => MessageType.Error,
_ => throw new InvalidOperationException($"Unexpected logLevel argument {logLevel}"),
}
}, CancellationToken.None);
}
catch (Exception ex) when (ex is ObjectDisposedException or ConnectionLostException)
{
// It is entirely possible that we're shutting down and the connection is lost while we're trying to send a log notification
// as this runs outside of the guaranteed ordering in the queue. We can safely ignore this exception.
}
}
}
}
13 changes: 12 additions & 1 deletion src/LanguageServer/Protocol/RoslynRequestExecutionQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,18 @@ public override async Task WrapStartRequestTaskAsync(Task nonMutatingRequestTask
else
{
// The caller has asked us to not rethrow, so record a NFW and swallow.
await nonMutatingRequestTask.ReportNonFatalErrorAsync().ConfigureAwait(false);
try
{
await nonMutatingRequestTask.ConfigureAwait(false);
}
catch (StreamJsonRpc.LocalRpcException localRpcException) when (localRpcException.ErrorCode == LspErrorCodes.ContentModified)
{
// Content modified exceptions are expected and should not be reported as NFWs.
}
catch (Exception ex) when (FatalError.ReportAndCatchUnlessCanceled(ex, ErrorSeverity.Critical))
{
// Swallow the exception so it does not bubble up into the queue.
}
}
}

Expand Down
33 changes: 33 additions & 0 deletions src/LanguageServer/ProtocolUnitTests/HandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,39 @@ await provider.WaitAllDispatcherOperationAndTasksAsync(
Assert.True(didReport);
}

[Theory, CombinatorialData]
public async Task NonMutatingHandlerExceptionNFWIsNotReportedForLocalRpcException(bool mutatingLspWorkspace)
{
await using var server = await CreateTestLspServerAsync("", mutatingLspWorkspace);

var request = new TestRequestWithDocument(new TextDocumentIdentifier
{
Uri = ProtocolConversions.CreateAbsoluteUri(@"C:\test.cs")
});

var didReport = false;
FatalError.OverwriteHandler((exception, severity, dumps) =>
{
if (exception.Message == nameof(HandlerTests) || exception.InnerException.Message == nameof(HandlerTests))
{
didReport = true;
}
});

var response = Task.FromException<TestConfigurableResponse>(new StreamJsonRpc.LocalRpcException(nameof(HandlerTests)) { ErrorCode = LspErrorCodes.ContentModified });
TestConfigurableDocumentHandler.ConfigureHandler(server, mutatesSolutionState: false, requiresLspSolution: true, response);

await Assert.ThrowsAnyAsync<Exception>(async ()
=> await server.ExecuteRequestAsync<TestRequestWithDocument, TestConfigurableResponse>(TestConfigurableDocumentHandler.MethodName, request, CancellationToken.None));

var provider = server.TestWorkspace.ExportProvider.GetExportedValue<AsynchronousOperationListenerProvider>();
await provider.WaitAllDispatcherOperationAndTasksAsync(
server.TestWorkspace,
FeatureAttribute.LanguageServer);

Assert.False(didReport);
}

[Theory, CombinatorialData]
public async Task MutatingHandlerExceptionNFWIsReported(bool mutatingLspWorkspace)
{
Expand Down
Loading