Skip to content

Commit

Permalink
Allow logging level to be changed in rzls (#11228)
Browse files Browse the repository at this point in the history
VS Code has a specific LogOutputChannel which allows the user to easily change the logging level on an output window. To support that rzls also needs to allow dynamic logging level changes. This adds an endpoint and a level provider that changes the logging level based on an lsp message coming in.
  • Loading branch information
ryzngard authored Nov 20, 2024
1 parent 58984fe commit 7390745
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 19 deletions.
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.

using System.Threading;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;

internal class LogLevelProvider(LogLevel logLevel)
{
public LogLevel Current { get; set; } = logLevel;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.

using System.Text.Json.Serialization;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;

/// <summary>
/// Request parameters for updating the log level in the server dynamically.
/// </summary>
/// <param name="LogLevel">the int value of the <see cref="LogLevel"/> enum</param>
internal record class UpdateLogLevelParams([property: JsonPropertyName("logLevel")] int LogLevel);
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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.AspNetCore.Razor.LanguageServer.EndpointContracts;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Razor.Protocol;

namespace Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;

[RazorLanguageServerEndpoint(CustomMessageNames.RazorUpdateLogLevelName)]
internal class UpdateLogLevelEndpoint(LogLevelProvider logLevelProvider) : IRazorNotificationHandler<UpdateLogLevelParams>
{
public bool MutatesSolutionState => false;

public Task HandleNotificationAsync(UpdateLogLevelParams request, RazorRequestContext requestContext, CancellationToken cancellationToken)
{
logLevelProvider.Current = (LogLevel)request.LogLevel;
return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace Microsoft.CodeAnalysis.Razor.Logging;

internal enum LogLevel
{
Trace,
Debug,
Information,
Warning,
Error,
Critical,
None
None = 0,
Trace = 1,
Debug = 2,
Information = 3,
Warning = 4,
Error = 5,
Critical = 6,
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal static class CustomMessageNames

// VS Code only
public const string RazorNamedPipeConnectEndpointName = "razor/namedPipeConnect";
public const string RazorUpdateLogLevelName = "razor/updateLogLevel";

// VS Windows and VS Code
public const string RazorUpdateCSharpBufferEndpoint = "razor/updateCSharpBuffer";
Expand Down
8 changes: 3 additions & 5 deletions src/Razor/src/rzls/LoggerProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,15 @@
// Licensed under the MIT license. See License.txt in the project root for license information.

using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;
using Microsoft.CodeAnalysis.Razor.Logging;

namespace Microsoft.AspNetCore.Razor.LanguageServer;

internal class LoggerProvider(LogLevel logLevel, IClientConnection clientConnection) : ILoggerProvider
internal class LoggerProvider(LogLevelProvider logLevelProvider, IClientConnection clientConnection) : ILoggerProvider
{
private readonly LogLevel _logLevel = logLevel;
private readonly IClientConnection _clientConnection = clientConnection;

public ILogger CreateLogger(string categoryName)
{
return new LspLogger(categoryName, _logLevel, _clientConnection);
return new LspLogger(categoryName, logLevelProvider, clientConnection);
}
}
7 changes: 4 additions & 3 deletions src/Razor/src/rzls/LspLogger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Threading;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.VisualStudio.LanguageServer.Protocol;
using Microsoft.VisualStudio.Threading;
Expand All @@ -13,15 +14,15 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer;
/// <summary>
/// ILogger implementation that logs via the window/logMessage LSP method
/// </summary>
internal class LspLogger(string categoryName, LogLevel logLevel, IClientConnection clientConnection) : ILogger
internal class LspLogger(string categoryName, LogLevelProvider logLevelProvider, IClientConnection clientConnection) : ILogger
{
private readonly LogLevel _logLevel = logLevel;
private LogLevel LogLevel => logLevelProvider.Current;
private readonly string _categoryName = categoryName;
private readonly IClientConnection _clientConnection = clientConnection;

public bool IsEnabled(LogLevel logLevel)
{
return logLevel.IsAtLeast(_logLevel);
return logLevel.IsAtLeast(LogLevel);
}

public void Log(LogLevel logLevel, string message, Exception? exception)
Expand Down
9 changes: 7 additions & 2 deletions src/Razor/src/rzls/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.NamedPipes;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.AspNetCore.Razor.Utilities;
Expand Down Expand Up @@ -83,22 +84,26 @@ public static async Task Main(string[] args)
// Have to create a logger factory to give to the server, but can't create any logger providers until we have
// a server.
var loggerFactory = new LoggerFactory([]);
var logLevelProvider = new LogLevelProvider(logLevel);

using var host = RazorLanguageServerHost.Create(
Console.OpenStandardInput(),
Console.OpenStandardOutput(),
loggerFactory,
telemetryContext?.TelemetryReporter ?? NoOpTelemetryReporter.Instance,
featureOptions: languageServerFeatureOptions,
configureServices: static services =>
configureServices: services =>
{
services.AddSingleton<IRazorProjectInfoDriver, NamedPipeBasedRazorProjectInfoDriver>();
services.AddHandler<RazorNamedPipeConnectEndpoint>();

services.AddSingleton(logLevelProvider);
services.AddHandler<UpdateLogLevelEndpoint>();
});

// Now we have a server, and hence a connection, we have somewhere to log
var clientConnection = host.GetRequiredService<IClientConnection>();
var loggerProvider = new LoggerProvider(logLevel, clientConnection);
var loggerProvider = new LoggerProvider(logLevelProvider, clientConnection);
loggerFactory.AddLoggerProvider(loggerProvider);

loggerFactory.GetOrCreateLogger("RZLS").LogInformation($"Razor Language Server started successfully.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Extensions;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.Logging;
using Microsoft.AspNetCore.Razor.LanguageServer.Hosting.NamedPipes;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.AspNetCore.Razor.Telemetry;
Expand Down Expand Up @@ -124,8 +124,10 @@ private RazorLanguageServerHost CreateLanguageServerHost(Stream input, Stream ou
{
s.AddSingleton<IRazorProjectInfoDriver, TestProjectInfoDriver>();

// VS Code only handler is added by rzls, but add here for testing purposes
// VS Code only handlers are added by rzls, but add here for testing purposes
s.AddHandler<RazorNamedPipeConnectEndpoint>();
s.AddSingleton(new LogLevelProvider(CodeAnalysis.Razor.Logging.LogLevel.None));
s.AddHandler<UpdateLogLevelEndpoint>();
});
}

Expand Down

0 comments on commit 7390745

Please sign in to comment.