Skip to content

Commit

Permalink
Wire up HostLogger
Browse files Browse the repository at this point in the history
  • Loading branch information
JustinGrote committed Nov 14, 2024
1 parent b9bd92e commit e766e07
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ protected override void BeginProcessing()
protected override void EndProcessing()
{
_logger.Log(PsesLogLevel.Diagnostic, "Beginning EndProcessing block");

try
{
// First try to remove PSReadLine to decomplicate startup
Expand Down
13 changes: 3 additions & 10 deletions src/PowerShellEditorServices/Logging/HostLoggerAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,16 @@ namespace Microsoft.PowerShell.EditorServices.Logging
/// <summary>
/// Adapter class to allow logging events sent by the host to be recorded by PSES' logging infrastructure.
/// </summary>
internal class HostLoggerAdapter : IObserver<(int logLevel, string message)>
internal class HostLoggerAdapter(ILogger logger) : IObserver<(int logLevel, string message)>
{
private readonly ILogger _logger;
public void OnError(Exception error) => logger.LogError(error, "Error in host logger");

/// <summary>
/// Create a new host logger adapter.
/// </summary>
/// <param name="loggerFactory">Factory to create logger instances with.</param>
public HostLoggerAdapter(ILoggerFactory loggerFactory) => _logger = loggerFactory.CreateLogger("HostLogs");
public void OnNext((int logLevel, string message) value) => logger.Log((LogLevel)value.logLevel, value.message);

public void OnCompleted()
{
// Nothing to do; we simply don't send more log messages
}

public void OnError(Exception error) => _logger.LogError(error, "Error in host logger");

public void OnNext((int logLevel, string message) value) => _logger.Log((LogLevel)value.logLevel, value.message);
}
}
23 changes: 16 additions & 7 deletions src/PowerShellEditorServices/Server/PsesLanguageServer.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.PowerShell.EditorServices.Handlers;
using Microsoft.PowerShell.EditorServices.Hosting;
using Microsoft.PowerShell.EditorServices.Logging;
using Microsoft.PowerShell.EditorServices.Services;
using Microsoft.PowerShell.EditorServices.Services.Extension;
using Microsoft.PowerShell.EditorServices.Services.PowerShell.Host;
using Newtonsoft.Json.Linq;
using OmniSharp.Extensions.JsonRpc;
using OmniSharp.Extensions.LanguageServer.Protocol.General;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Server;

Expand All @@ -26,14 +29,15 @@ namespace Microsoft.PowerShell.EditorServices.Server
/// </summary>
internal class PsesLanguageServer
{
internal HostLogger LoggerFactory { get; }
internal HostLogger HostLogger { get; }
internal ILanguageServer LanguageServer { get; private set; }
private readonly LogLevel _minimumLogLevel;
private readonly Stream _inputStream;
private readonly Stream _outputStream;
private readonly HostStartupInfo _hostDetails;
private readonly TaskCompletionSource<bool> _serverStart;
private PsesInternalHost _psesHost;
private IDisposable hostLoggerSubscription;

/// <summary>
/// Create a new language server instance.
Expand All @@ -43,18 +47,18 @@ internal class PsesLanguageServer
/// cref="EditorServicesServerFactory.CreateLanguageServer"/>. It is essentially a
/// singleton. The factory hides the logger.
/// </remarks>
/// <param name="factory">Factory to create loggers with.</param>
/// <param name="hostLogger">The host logger to hand off for monitoring.</param>
/// <param name="inputStream">Protocol transport input stream.</param>
/// <param name="outputStream">Protocol transport output stream.</param>
/// <param name="hostStartupInfo">Host configuration to instantiate the server and services
/// with.</param>
public PsesLanguageServer(
HostLogger factory,
HostLogger hostLogger,
Stream inputStream,
Stream outputStream,
HostStartupInfo hostStartupInfo)
{
LoggerFactory = factory;
HostLogger = hostLogger;
_minimumLogLevel = (LogLevel)hostStartupInfo.LogLevel;
_inputStream = inputStream;
_outputStream = outputStream;
Expand Down Expand Up @@ -86,9 +90,7 @@ public async Task StartAsync()
.ConfigureLogging(builder => builder
.ClearProviders()
.AddLanguageProtocolLogging()
// TODO: AddHostLogger which registers the host logger provider above as a LoggingProvider (MEL version of a "sink")
.SetMinimumLevel(_minimumLogLevel))
// TODO: Consider replacing all WithHandler with AddSingleton
.WithHandler<PsesWorkspaceSymbolsHandler>()
.WithHandler<PsesTextDocumentHandler>()
.WithHandler<GetVersionHandler>()
Expand Down Expand Up @@ -127,6 +129,11 @@ public async Task StartAsync()
.OnInitialize(
(languageServer, initializeParams, cancellationToken) =>
{
// Wire up the HostLogger to the LanguageServer's logger once we are initialized, so that any messages still logged to the HostLogger get sent across the LSP channel. There is no more logging to disk at this point.
hostLoggerSubscription = HostLogger.Subscribe(new HostLoggerAdapter(
languageServer.Services.GetService<ILogger<HostLogger>>()
));

// Set the workspace path from the parameters.
WorkspaceService workspaceService = languageServer.Services.GetService<WorkspaceService>();
if (initializeParams.WorkspaceFolders is not null)
Expand Down Expand Up @@ -161,7 +168,9 @@ public async Task StartAsync()

_psesHost = languageServer.Services.GetService<PsesInternalHost>();
return _psesHost.TryStartAsync(hostStartOptions, cancellationToken);
});
}
)
.OnShutdown(_ => hostLoggerSubscription.Dispose());
}).ConfigureAwait(false);

_serverStart.SetResult(true);
Expand Down

0 comments on commit e766e07

Please sign in to comment.