diff --git a/CHANGELOG.md b/CHANGELOG.md index b05ea793..efb9c158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +* Rework logging to be based on Serilog + - PR by @tcx4c70 in https://github.com/razzmatazz/csharp-language-server/pull/134 * More refactoring by @tcx4c70 - PR by @tcx4c70 in https://github.com/razzmatazz/csharp-language-server/pull/102 * Change package management to CPM diff --git a/Directory.Packages.props b/Directory.Packages.props index 3c0aa524..dc687824 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -35,5 +35,8 @@ + + + diff --git a/src/CSharpLanguageServer/CSharpLanguageServer.fsproj b/src/CSharpLanguageServer/CSharpLanguageServer.fsproj index 0aa60462..41950127 100644 --- a/src/CSharpLanguageServer/CSharpLanguageServer.fsproj +++ b/src/CSharpLanguageServer/CSharpLanguageServer.fsproj @@ -75,5 +75,8 @@ + + + diff --git a/src/CSharpLanguageServer/Handlers/CodeAction.fs b/src/CSharpLanguageServer/Handlers/CodeAction.fs index 64bee74f..33fe058b 100644 --- a/src/CSharpLanguageServer/Handlers/CodeAction.fs +++ b/src/CSharpLanguageServer/Handlers/CodeAction.fs @@ -12,9 +12,12 @@ open Microsoft.CodeAnalysis.Text open CSharpLanguageServer open CSharpLanguageServer.State open CSharpLanguageServer.RoslynHelpers +open CSharpLanguageServer.Logging [] module CodeAction = + let private logger = LogProvider.getLoggerByName "CodeAction" + type CSharpCodeActionResolutionData = { TextDocumentUri: string Range: Range diff --git a/src/CSharpLanguageServer/Handlers/Rename.fs b/src/CSharpLanguageServer/Handlers/Rename.fs index 334a884c..670579e1 100644 --- a/src/CSharpLanguageServer/Handlers/Rename.fs +++ b/src/CSharpLanguageServer/Handlers/Rename.fs @@ -21,9 +21,12 @@ open Microsoft.CodeAnalysis.Classification open CSharpLanguageServer open CSharpLanguageServer.State open CSharpLanguageServer.RoslynHelpers +open CSharpLanguageServer.Logging [] module Rename = + let private logger = LogProvider.getLoggerByName "CodeAction" + let provider (clientCapabilities: ClientCapabilities option) : U2 option = let clientSupportsRenameOptions = clientCapabilities diff --git a/src/CSharpLanguageServer/Program.fs b/src/CSharpLanguageServer/Program.fs index 384c7a53..fa730479 100644 --- a/src/CSharpLanguageServer/Program.fs +++ b/src/CSharpLanguageServer/Program.fs @@ -1,9 +1,15 @@ module CSharpLanguageServer.Program open Argu +open System open System.Reflection open CSharpLanguageServer.Types open CSharpLanguageServer.Lsp +open Serilog +open Serilog.Core +open Serilog.Events + +open CSharpLanguageServer.Logging [] let entry args = @@ -16,20 +22,37 @@ let entry args = (Assembly.GetExecutingAssembly().GetName().Version |> string) exit 0) - let parseLogLevel (s: string) = - match s.ToLowerInvariant() with - | "error" -> Ionide.LanguageServerProtocol.Types.MessageType.Error - | "warning" -> Ionide.LanguageServerProtocol.Types.MessageType.Warning - | "info" -> Ionide.LanguageServerProtocol.Types.MessageType.Info - | "log" -> Ionide.LanguageServerProtocol.Types.MessageType.Log - | _ -> Ionide.LanguageServerProtocol.Types.MessageType.Log + let logLevelArg = + serverArgs.TryGetResult(<@ Options.CLIArguments.LogLevel @>) + |> Option.defaultValue "log" + + let logLevel = + match logLevelArg with + | "error" -> LogEventLevel.Error + | "warning" -> LogEventLevel.Warning + | "info" -> LogEventLevel.Information + | "log" -> LogEventLevel.Verbose + | _ -> LogEventLevel.Information + + let logConfig = + LoggerConfiguration() + .MinimumLevel.ControlledBy(LoggingLevelSwitch(logLevel)) + .Enrich.FromLogContext() + .WriteTo.Async(fun conf -> + conf.Console( + outputTemplate = + "[{Timestamp:HH:mm:ss.fff} {Level:u3}] [{SourceContext}] {Message:lj}{NewLine}{Exception}", + // Redirect all logs to stderr since stdout is used to communicate with client. + standardErrorFromLevel = Nullable<_>(LogEventLevel.Verbose), + theme = Serilog.Sinks.SystemConsole.Themes.AnsiConsoleTheme.Code + ) + |> ignore) + + Log.Logger <- logConfig.CreateLogger() - // default the verbosity to warning let settings: ServerSettings = { SolutionPath = serverArgs.TryGetResult(<@ Options.CLIArguments.Solution @>) - LogLevel = serverArgs.TryGetResult(<@ Options.CLIArguments.LogLevel @>) - |> Option.defaultValue "log" - |> parseLogLevel + LogLevel = logLevelArg } Server.start CSharpLanguageServer.Server.setupServerHandlers diff --git a/src/CSharpLanguageServer/Server.fs b/src/CSharpLanguageServer/Server.fs index 59a53c31..92827456 100644 --- a/src/CSharpLanguageServer/Server.fs +++ b/src/CSharpLanguageServer/Server.fs @@ -25,6 +25,7 @@ open Ionide.LanguageServerProtocol.Server open Ionide.LanguageServerProtocol.Types open CSharpLanguageServer +open CSharpLanguageServer.Logging open CSharpLanguageServer.RoslynHelpers open CSharpLanguageServer.State open CSharpLanguageServer.Lsp @@ -50,6 +51,8 @@ let getDotnetCliVersion () : string = "(could not launch `dotnet --version`)" let setupServerHandlers settings (lspClient: LspClient) = + let logger = LogProvider.getLoggerByName "Server" + let success = LspResult.success let mutable logMessageCurrent: AsyncLogFn = fun _ -> async { return() } let logMessageInvoke m = logMessageCurrent(m) @@ -101,13 +104,18 @@ let setupServerHandlers settings (lspClient: LspClient) = do stateActor.Post(PeriodicTimerTick)), null, dueTime=1000, period=250)) - let logMessageWithLevel l message = async { - let messageParams = { Type = l ; Message = "csharp-ls: " + message } + // TODO: setup Serilog Sink instead + let logMessage message = async { + let messageParams = { Type = MessageType.Log ; Message = "csharp-ls: " + message } do! lspClient.WindowShowMessage messageParams + logger.trace (Log.setMessage message) } - let logMessage = logMessageWithLevel MessageType.Log - let infoMessage = logMessageWithLevel MessageType.Info + let infoMessage message = async { + let messageParams = { Type = MessageType.Info ; Message = "csharp-ls: " + message } + do! lspClient.WindowShowMessage messageParams + logger.info (Log.setMessage message) + } let handleInitialize (scope: ServerRequestScope) (p: InitializeParams): AsyncLspResult = async { do! infoMessage (sprintf "initializing, csharp-ls version %s; cwd: \"%s\"" diff --git a/src/CSharpLanguageServer/Types.fs b/src/CSharpLanguageServer/Types.fs index a6288e50..dc42f741 100644 --- a/src/CSharpLanguageServer/Types.fs +++ b/src/CSharpLanguageServer/Types.fs @@ -5,11 +5,11 @@ open Ionide.LanguageServerProtocol.Types type ServerSettings = { SolutionPath: string option - LogLevel: MessageType } + LogLevel: string } static member Default: ServerSettings = { SolutionPath = None - LogLevel = MessageType.Log } + LogLevel = "log" } type CSharpMetadataInformation = { ProjectName: string