|
| 1 | +module FSharp.Analyzers.Cli.CustomLogging |
| 2 | + |
| 3 | +open System |
| 4 | +open System.IO |
| 5 | +open System.Runtime.CompilerServices |
| 6 | +open Microsoft.Extensions.Logging |
| 7 | +open Microsoft.Extensions.Logging.Console |
| 8 | +open Microsoft.Extensions.Logging.Abstractions |
| 9 | +open Microsoft.Extensions.Options |
| 10 | + |
| 11 | +type CustomOptions() = |
| 12 | + inherit ConsoleFormatterOptions() |
| 13 | + |
| 14 | + /// if true: no LogLevel as prefix, colored output according to LogLevel |
| 15 | + /// if false: LogLevel as prefix, no colored output |
| 16 | + member val UseAnalyzersMsgStyle = false with get, set |
| 17 | + |
| 18 | +type CustomFormatter(options: IOptionsMonitor<CustomOptions>) as this = |
| 19 | + inherit ConsoleFormatter("customName") |
| 20 | + |
| 21 | + let mutable optionsReloadToken: IDisposable = null |
| 22 | + let mutable formatterOptions = options.CurrentValue |
| 23 | + let origColor = Console.ForegroundColor |
| 24 | + |
| 25 | + do optionsReloadToken <- options.OnChange(fun x -> this.ReloadLoggerOptions(x)) |
| 26 | + |
| 27 | + member private _.ReloadLoggerOptions(opts: CustomOptions) = formatterOptions <- opts |
| 28 | + |
| 29 | + override this.Write<'TState> |
| 30 | + ( |
| 31 | + logEntry: inref<LogEntry<'TState>>, |
| 32 | + _scopeProvider: IExternalScopeProvider, |
| 33 | + textWriter: TextWriter |
| 34 | + ) |
| 35 | + = |
| 36 | + let message = logEntry.Formatter.Invoke(logEntry.State, logEntry.Exception) |
| 37 | + |
| 38 | + if formatterOptions.UseAnalyzersMsgStyle then |
| 39 | + this.SetColor(textWriter, logEntry.LogLevel) |
| 40 | + textWriter.WriteLine(message) |
| 41 | + this.ResetColor() |
| 42 | + else |
| 43 | + this.WritePrefix(textWriter, logEntry.LogLevel) |
| 44 | + textWriter.WriteLine(message) |
| 45 | + |
| 46 | + member private _.WritePrefix(textWriter: TextWriter, logLevel: LogLevel) = |
| 47 | + match logLevel with |
| 48 | + | LogLevel.Trace -> textWriter.Write("trace: ") |
| 49 | + | LogLevel.Debug -> textWriter.Write("debug: ") |
| 50 | + | LogLevel.Information -> textWriter.Write("info: ") |
| 51 | + | LogLevel.Warning -> textWriter.Write("warn: ") |
| 52 | + | LogLevel.Error -> textWriter.Write("error: ") |
| 53 | + | LogLevel.Critical -> textWriter.Write("critical: ") |
| 54 | + | _ -> () |
| 55 | + |
| 56 | + // see https://learn.microsoft.com/en-us/dotnet/core/extensions/console-log-formatter |
| 57 | + member private _.SetColor(textWriter: TextWriter, logLevel: LogLevel) = |
| 58 | + let color = |
| 59 | + match logLevel with |
| 60 | + | LogLevel.Error -> "\x1B[1m\x1B[31m" // ConsoleColor.Red |
| 61 | + | LogLevel.Warning -> "\x1B[33m" // ConsoleColor.DarkYellow |
| 62 | + | LogLevel.Information -> "\x1B[1m\x1B[34m" // ConsoleColor.Blue |
| 63 | + | LogLevel.Trace -> "\x1B[1m\x1B[36m" // ConsoleColor.Cyan |
| 64 | + | _ -> "\x1B[37m" // ConsoleColor.Gray |
| 65 | + |
| 66 | + textWriter.Write(color) |
| 67 | + |
| 68 | + member private _.ResetColor() = Console.ForegroundColor <- origColor |
| 69 | + |
| 70 | + interface IDisposable with |
| 71 | + member _.Dispose() = optionsReloadToken.Dispose() |
| 72 | + |
| 73 | +[<Extension>] |
| 74 | +type ConsoleLoggerExtensions = |
| 75 | + |
| 76 | + [<Extension>] |
| 77 | + static member AddCustomFormatter(builder: ILoggingBuilder, configure: Action<CustomOptions>) : ILoggingBuilder = |
| 78 | + builder |
| 79 | + .AddConsole(fun options -> options.FormatterName <- "customName") |
| 80 | + .AddConsoleFormatter<CustomFormatter, CustomOptions>(configure) |
0 commit comments