Skip to content

Commit e85179b

Browse files
slight rejig of CustomLogging module and adding logic from #176 back to the Microsoft.Extensions.Logging branch.
1 parent a6b77ab commit e85179b

File tree

3 files changed

+71
-40
lines changed

3 files changed

+71
-40
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1010
### Changed
1111
* [Add path to ASTCollecting](https://github.com/ionide/FSharp.Analyzers.SDK/pull/171) (thanks @nojaf!)
1212
* [Use Microsoft.Extensions.Logging instead of printf based logging infrastructure](https://github.com/ionide/FSharp.Analyzers.SDK/pull/175) (thanks @dawedawe!)
13+
* [Console finer colorized pretty printing and link to analyzer URI](https://github.com/ionide/FSharp.Analyzers.SDK/pull/177) (thanks @smoothdeveloper!)
1314

1415
## [0.21.0] - 2023-11-22
1516

src/FSharp.Analyzers.Cli/CustomLogging.fs

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,59 @@ open Microsoft.Extensions.Logging.Console
88
open Microsoft.Extensions.Logging.Abstractions
99
open Microsoft.Extensions.Options
1010

11+
module AnsiColorHelpers =
12+
let private initialConsoleColor = Console.ForegroundColor
13+
// see https://learn.microsoft.com/en-us/dotnet/core/extensions/console-log-formatter#implement-custom-color-formatting
14+
let private ansiForegroundEscapeCodeOfColorConsole color =
15+
match color with
16+
| ConsoleColor.Black -> "\x1B[30m"
17+
| ConsoleColor.DarkRed -> "\x1B[31m"
18+
| ConsoleColor.DarkGreen -> "\x1B[32m"
19+
| ConsoleColor.DarkYellow -> "\x1B[33m"
20+
| ConsoleColor.DarkBlue -> "\x1B[34m"
21+
| ConsoleColor.DarkMagenta -> "\x1B[35m"
22+
| ConsoleColor.DarkCyan -> "\x1B[36m"
23+
| ConsoleColor.Gray -> "\x1B[37m"
24+
| ConsoleColor.Red -> "\x1B[1m\x1B[31m"
25+
| ConsoleColor.Green -> "\x1B[1m\x1B[32m"
26+
| ConsoleColor.Yellow -> "\x1B[1m\x1B[33m"
27+
| ConsoleColor.Blue -> "\x1B[1m\x1B[34m"
28+
| ConsoleColor.Magenta -> "\x1B[1m\x1B[35m"
29+
| ConsoleColor.Cyan -> "\x1B[1m\x1B[36m"
30+
| ConsoleColor.White -> "\x1B[1m\x1B[37m"
31+
| _ ->
32+
#if DEBUG
33+
failwith $"didn't implement ansi code for color: {color}"
34+
#else
35+
// do not break code analyzis to wrong runtime color or such thing for release
36+
"\x1B[37m" // ConsoleColor.Gray
37+
#endif
38+
39+
let consoleColorOfLogLevel logLevel =
40+
match logLevel with
41+
| LogLevel.Error -> ConsoleColor.Red
42+
| LogLevel.Warning ->ConsoleColor.DarkYellow
43+
| LogLevel.Information -> ConsoleColor.Blue
44+
| LogLevel.Trace -> ConsoleColor.Cyan
45+
| _ -> ConsoleColor.Gray
46+
47+
let formatMessageAsAnsiColorizedString (color: ConsoleColor) (message: string) =
48+
$"{ansiForegroundEscapeCodeOfColorConsole color}{message}{ansiForegroundEscapeCodeOfColorConsole initialConsoleColor}"
49+
1150
type CustomOptions() =
1251
inherit ConsoleFormatterOptions()
1352

1453
/// if true: no LogLevel as prefix, colored output according to LogLevel
1554
/// if false: LogLevel as prefix, no colored output
1655
member val UseAnalyzersMsgStyle = false with get, set
56+
member x.UseColoredOutput = x.UseAnalyzersMsgStyle
57+
member x.UseLogLevelAsPrefix = not x.UseAnalyzersMsgStyle
1758

1859
type CustomFormatter(options: IOptionsMonitor<CustomOptions>) as this =
1960
inherit ConsoleFormatter("customName")
2061

2162
let mutable optionsReloadToken: IDisposable = null
2263
let mutable formatterOptions = options.CurrentValue
23-
let origColor = Console.ForegroundColor
24-
2564
do optionsReloadToken <- options.OnChange(fun x -> this.ReloadLoggerOptions(x))
2665

2766
member private _.ReloadLoggerOptions(opts: CustomOptions) = formatterOptions <- opts
@@ -34,14 +73,9 @@ type CustomFormatter(options: IOptionsMonitor<CustomOptions>) as this =
3473
)
3574
=
3675
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
76+
if formatterOptions.UseLogLevelAsPrefix then
4377
this.WritePrefix(textWriter, logEntry.LogLevel)
44-
textWriter.WriteLine(message)
78+
textWriter.WriteLine message
4579

4680
member private _.WritePrefix(textWriter: TextWriter, logLevel: LogLevel) =
4781
match logLevel with
@@ -53,20 +87,6 @@ type CustomFormatter(options: IOptionsMonitor<CustomOptions>) as this =
5387
| LogLevel.Critical -> textWriter.Write("critical: ")
5488
| _ -> ()
5589

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-
7090
interface IDisposable with
7191
member _.Dispose() = optionsReloadToken.Dispose()
7292

src/FSharp.Analyzers.Cli/Program.fs

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ open System.Text.RegularExpressions
66
open FSharp.Compiler.CodeAnalysis
77
open FSharp.Compiler.Text
88
open Argu
9-
open FSharp.Analyzers.SDK
109
open GlobExpressions
1110
open Microsoft.CodeAnalysis.Sarif
1211
open Microsoft.CodeAnalysis.Sarif.Writers
1312
open Microsoft.Extensions.Logging
1413
open Ionide.ProjInfo
14+
open FSharp.Analyzers.SDK
15+
open FSharp.Analyzers.Cli
1516
open FSharp.Analyzers.Cli.CustomLogging
1617

1718
type Arguments =
@@ -252,23 +253,32 @@ let printMessages (msgs: AnalyzerMessage list) =
252253

253254
let msgLogger = factory.CreateLogger("")
254255

255-
msgs
256-
|> Seq.iter (fun analyzerMessage ->
257-
let m = analyzerMessage.Message
256+
let useAnsiColorCodes = true
257+
let colorFormat color message =
258+
if useAnsiColorCodes then
259+
CustomLogging.AnsiColorHelpers.formatMessageAsAnsiColorizedString color message
260+
else
261+
message
258262

259-
msgLogger.Log(
260-
severityToLogLevel[m.Severity],
261-
"{0}({1},{2}): {3} {4} - {5}",
262-
m.Range.FileName,
263-
m.Range.StartLine,
264-
m.Range.StartColumn,
265-
(m.Severity.ToString()),
266-
m.Code,
267-
m.Message
268-
)
269-
)
270-
271-
()
263+
for analyzerMessage in msgs do
264+
let m = analyzerMessage.Message
265+
let logLevel = severityToLogLevel[m.Severity]
266+
let messageFormat, messageArgs =
267+
let baseArgs : obj array =
268+
[|
269+
m.Range.FileName
270+
m.Range.StartLine
271+
m.Range.StartColumn
272+
colorFormat (CustomLogging.AnsiColorHelpers.consoleColorOfLogLevel logLevel) (m.Severity.ToString())
273+
colorFormat (CustomLogging.AnsiColorHelpers.consoleColorOfLogLevel logLevel) m.Code
274+
m.Message
275+
|]
276+
let baseFormat = "{0}({1},{2}): {3} {4} - {5}"
277+
match analyzerMessage.HelpUri with
278+
| None -> baseFormat, baseArgs
279+
| Some uri -> baseFormat + " {6}", [|yield! baseArgs; colorFormat ConsoleColor.Cyan uri|]
280+
281+
msgLogger.Log(logLevel, messageFormat, messageArgs)
272282

273283
let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) (report: string) =
274284
try

0 commit comments

Comments
 (0)