From b1ccb4a0e19e0331703518c4750f354c9def5092 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 11:20:55 +0100 Subject: [PATCH 1/8] first stab at using ILogger --- Directory.Packages.props | 2 + README.md | 2 +- build.fsx | 2 +- docs/content/Getting Started Using.md | 6 +- docs/content/Getting Started Writing.fsx | 2 +- docs/content/Programmatic access.fsx | 1 + docs/index.md | 2 +- .../FSharp.Analyzers.Cli.fsproj | 2 + src/FSharp.Analyzers.Cli/Logging.fs | 50 ++++++ src/FSharp.Analyzers.Cli/Program.fs | 155 +++++++++--------- .../Properties/launchSettings.json | 2 +- .../FSharp.Analyzers.SDK.Testing.fs | 12 +- .../FSharp.Analyzers.SDK.Testing.fsproj | 1 + .../FSharp.Analyzers.SDK.Client.fs | 33 ++-- .../FSharp.Analyzers.SDK.Client.fsi | 9 +- .../FSharp.Analyzers.SDK.fs | 5 +- .../FSharp.Analyzers.SDK.fsi | 3 +- .../FSharp.Analyzers.SDK.fsproj | 1 + src/FSharp.Analyzers.SDK/TASTCollecting.fs | 7 +- src/FSharp.Analyzers.SDK/TASTCollecting.fsi | 4 + 20 files changed, 186 insertions(+), 115 deletions(-) create mode 100644 src/FSharp.Analyzers.Cli/Logging.fs diff --git a/Directory.Packages.props b/Directory.Packages.props index 2aeb53c..c9eee85 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -19,6 +19,8 @@ + + diff --git a/README.md b/README.md index ae9634f..f5932f5 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ F# analyzers are live, real-time, project based plugins that enables to diagnose 2. Run the console application: ```shell -dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbose +dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbosity d ``` You can also set up a run configuration of FSharp.Analyzers.Cli in your favorite IDE using similar arguments. This also allows you to debug FSharp.Analyzers.Cli. diff --git a/build.fsx b/build.fsx index e8d3a57..17f13d4 100644 --- a/build.fsx +++ b/build.fsx @@ -28,7 +28,7 @@ pipeline "Build" { } stage "sample" { run - "dotnet run --project src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbose" + "dotnet run --project src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbosity d" } stage "docs" { run "dotnet fsdocs build --properties Configuration=Release --eval --clean --strict" } runIfOnlySpecified false diff --git a/docs/content/Getting Started Using.md b/docs/content/Getting Started Using.md index 06c8671..c309e05 100644 --- a/docs/content/Getting Started Using.md +++ b/docs/content/Getting Started Using.md @@ -33,7 +33,7 @@ At the time of writing, the [G-Research analyzers](https://github.com/g-research With the package downloaded, we can run the CLI tool: ```shell -dotnet fsharp-analyzers --project ./YourProject.fsproj --analyzers-path C:\Users\yourusername\.nuget\packages\g-research.fsharp.analyzers\0.4.0\analyzers\dotnet\fs\ --verbose +dotnet fsharp-analyzers --project ./YourProject.fsproj --analyzers-path C:\Users\yourusername\.nuget\packages\g-research.fsharp.analyzers\0.4.0\analyzers\dotnet\fs\ --verbosity d ``` ### Using an MSBuild target @@ -57,7 +57,7 @@ Before we can run `dotnet msbuild /t:AnalyzeFSharpProject`, we need to specify o ```xml - --analyzers-path "$(PkgG-Research_FSharp_Analyzers)/analyzers/dotnet/fs" --report "$(MSBuildProjectName)-$(TargetFramework).sarif" --treat-as-warning IONIDE-004 --verbose + --analyzers-path "$(PkgG-Research_FSharp_Analyzers)/analyzers/dotnet/fs" --report "$(MSBuildProjectName)-$(TargetFramework).sarif" --treat-as-warning IONIDE-004 --verbosity d ``` @@ -101,7 +101,7 @@ This is effectively the same as adding a property to each `*proj` file which exi ./ . - --analyzers-path "$(PkgG-Research_FSharp_Analyzers)/analyzers/dotnet/fs" --report "$(SarifOutput)$(MSBuildProjectName)-$(TargetFramework).sarif" --code-root $(CodeRoot) --treat-as-warning IONIDE-004 --verbose + --analyzers-path "$(PkgG-Research_FSharp_Analyzers)/analyzers/dotnet/fs" --report "$(SarifOutput)$(MSBuildProjectName)-$(TargetFramework).sarif" --code-root $(CodeRoot) --treat-as-warning IONIDE-004 --verbosity d ``` diff --git a/docs/content/Getting Started Writing.fsx b/docs/content/Getting Started Writing.fsx index 63eb0a1..b6cb1b4 100644 --- a/docs/content/Getting Started Writing.fsx +++ b/docs/content/Getting Started Writing.fsx @@ -108,7 +108,7 @@ dotnet tool install --global fsharp-analyzers ``` ```shell -fsharp-analyzers --project YourProject.fsproj --analyzers-path ./OptionAnalyzer/bin/Release --verbose +fsharp-analyzers --project YourProject.fsproj --analyzers-path ./OptionAnalyzer/bin/Release --verbosity d ``` ### Packaging and Distribution diff --git a/docs/content/Programmatic access.fsx b/docs/content/Programmatic access.fsx index d1ebffb..76a86e3 100644 --- a/docs/content/Programmatic access.fsx +++ b/docs/content/Programmatic access.fsx @@ -15,6 +15,7 @@ The `Client` needs to know what type of analyzer you intend to load: *console* o (*** hide ***) #r "../../src/FSharp.Analyzers.Cli/bin/Release/net6.0/FSharp.Analyzers.SDK.dll" #r "../../src/FSharp.Analyzers.Cli/bin/Release/net6.0/FSharp.Compiler.Service.dll" +#r "../../src/FSharp.Analyzers.Cli/bin/Release/net6.0/Microsoft.Extensions.Logging.Abstractions.dll" (** *) open FSharp.Analyzers.SDK diff --git a/docs/index.md b/docs/index.md index 592f0e1..46a9a5d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -15,7 +15,7 @@ F# analyzers are live, real-time, project based plugins that enables to diagnose 2. Run the console application: ```shell -dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbose +dotnet run --project src\FSharp.Analyzers.Cli\FSharp.Analyzers.Cli.fsproj -- --project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbosity d ``` You can also set up a run configuration of FSharp.Analyzers.Cli in your favorite IDE using similar arguments. This also allows you to debug FSharp.Analyzers.Cli. diff --git a/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj b/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj index 62eecb6..75da0cf 100644 --- a/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj +++ b/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj @@ -13,6 +13,7 @@ + @@ -26,6 +27,7 @@ + diff --git a/src/FSharp.Analyzers.Cli/Logging.fs b/src/FSharp.Analyzers.Cli/Logging.fs new file mode 100644 index 0000000..1cf2651 --- /dev/null +++ b/src/FSharp.Analyzers.Cli/Logging.fs @@ -0,0 +1,50 @@ +namespace Console.ExampleFormatters.Custom + +open System +open System.IO +open System.Runtime.CompilerServices +open Microsoft.Extensions.Logging +open Microsoft.Extensions.Logging.Console +open Microsoft.Extensions.Logging.Abstractions +open Microsoft.Extensions.Options + +type CustomOptions() = + inherit ConsoleFormatterOptions() + + member val CustomPrefix = "" with get, set + +type CustomFormatter(options: IOptionsMonitor) as this = + inherit ConsoleFormatter("customName") + + let mutable optionsReloadToken: IDisposable = null + let mutable formatterOptions = options.CurrentValue + + do optionsReloadToken <- options.OnChange(fun x -> this.ReloadLoggerOptions(x)) + + member private _.ReloadLoggerOptions(opts: CustomOptions) = formatterOptions <- opts + + override this.Write<'TState> + ( + logEntry: inref>, + _scopeProvider: IExternalScopeProvider, + textWriter: TextWriter + ) + = + let message = logEntry.Formatter.Invoke(logEntry.State, logEntry.Exception) + this.CustomLogic(textWriter) + textWriter.WriteLine(message) + + member private _.CustomLogic(textWriter: TextWriter) = + textWriter.Write(formatterOptions.CustomPrefix) + + interface IDisposable with + member _.Dispose() = optionsReloadToken.Dispose() + +[] +type ConsoleLoggerExtensions = + + [] + static member AddCustomFormatter(builder: ILoggingBuilder, configure: Action) : ILoggingBuilder = + builder + .AddConsole(fun options -> options.FormatterName <- "customName") + .AddConsoleFormatter(configure) diff --git a/src/FSharp.Analyzers.Cli/Program.fs b/src/FSharp.Analyzers.Cli/Program.fs index dda7a67..3ce7400 100644 --- a/src/FSharp.Analyzers.Cli/Program.fs +++ b/src/FSharp.Analyzers.Cli/Program.fs @@ -10,7 +10,9 @@ open FSharp.Analyzers.SDK open GlobExpressions open Microsoft.CodeAnalysis.Sarif open Microsoft.CodeAnalysis.Sarif.Writers +open Microsoft.Extensions.Logging open Ionide.ProjInfo +open Console.ExampleFormatters.Custom type Arguments = | Project of string list @@ -29,7 +31,7 @@ type Arguments = | [] Report of string | [] FSC_Args of string | [] Code_Root of string - | [] Verbose + | [] Verbosity of string interface IArgParserTemplate with member s.Usage = @@ -52,7 +54,8 @@ type Arguments = | Ignore_Files _ -> "Source files that shouldn't be processed." | Exclude_Analyzer _ -> "The names of analyzers that should not be executed." | Report _ -> "Write the result messages to a (sarif) report file." - | Verbose -> "Verbose logging." + | Verbosity _ -> + "The verbosity level. The available verbosity levels are: n[ormal], d[etailed], diag[nostic]" | FSC_Args _ -> "Pass in the raw fsc compiler arguments. Cannot be combined with the `--project` flag." | Code_Root _ -> "Root of the current code repository, used in the sarif report to construct the relative file path. The current working directory is used by default." @@ -92,7 +95,7 @@ let mapMessageToSeverity (mappings: SeverityMappings) (msg: FSharp.Analyzers.SDK } } -let mutable verbose = false +let mutable logLevel = LogLevel.Warning let fcs = Utils.createFCS None @@ -106,22 +109,7 @@ let rec mkKn (ty: Type) = else box () -let origForegroundColor = Console.ForegroundColor - -let printInfo (fmt: Printf.TextWriterFormat<'a>) : 'a = - if verbose then - Console.ForegroundColor <- ConsoleColor.DarkGray - printf "Info : " - Console.ForegroundColor <- origForegroundColor - printfn fmt - else - unbox (mkKn typeof<'a>) - -let printError (text: string) : unit = - Console.ForegroundColor <- ConsoleColor.Red - Console.Write "Error : " - Console.WriteLine(text) - Console.ForegroundColor <- origForegroundColor +let mutable logger: ILogger = Abstractions.NullLogger.Instance let loadProject toolsPath properties projPath = async { @@ -129,7 +117,7 @@ let loadProject toolsPath properties projPath = let parsed = loader.LoadProjects [ projPath ] |> Seq.toList if parsed.IsEmpty then - printError $"Failed to load project '{projPath}'" + logger.LogError("Failed to load project '{0}'", projPath) exit 1 let fcsPo = FCS.mapToFSharpProjectOptions parsed.Head parsed @@ -151,7 +139,7 @@ let runProjectAux |> Array.filter (fun file -> match ignoreFiles |> List.tryFind (fun g -> g.IsMatch file) with | Some g -> - printInfo $"Ignoring file %s{file} for pattern %s{g.Pattern}" + logger.LogInformation("Ignoring file {0} for pattern {1}", file, g.Pattern) false | None -> true ) @@ -159,11 +147,11 @@ let runProjectAux let fileContent = File.ReadAllText fileName let sourceText = SourceText.ofString fileContent - Utils.typeCheckFile fcs printError fsharpOptions fileName (Utils.SourceOfSource.SourceText sourceText) + Utils.typeCheckFile fcs logger fsharpOptions fileName (Utils.SourceOfSource.SourceText sourceText) |> Option.map (Utils.createContext checkProjectResults fileName sourceText) ) |> Array.map (fun ctx -> - printInfo "Running analyzers for %s" ctx.FileName + logger.LogInformation("Running analyzers for {0}", ctx.FileName) client.RunAnalyzers ctx ) |> Async.Parallel @@ -203,7 +191,7 @@ let runFscArgs (mappings: SeverityMappings) = if String.IsNullOrWhiteSpace fscArgs then - printError "Empty --fsc-args were passed!" + logger.LogError("Empty --fsc-args were passed!") exit 1 else @@ -241,35 +229,30 @@ let runFscArgs runProjectAux client projectOptions globs mappings let printMessages (msgs: AnalyzerMessage list) = - if verbose then - printfn "" - - if verbose && List.isEmpty msgs then - printfn "No messages found from the analyzer(s)" + if List.isEmpty msgs then + logger.LogInformation("No messages found from the analyzer(s)") msgs |> Seq.iter (fun analyzerMessage -> let m = analyzerMessage.Message - let color = + let msgLogLevel = match m.Severity with - | Error -> ConsoleColor.Red - | Warning -> ConsoleColor.DarkYellow - | Info -> ConsoleColor.Blue - | Hint -> ConsoleColor.Cyan - - Console.ForegroundColor <- color - - printfn - "%s(%d,%d): %s %s - %s" - m.Range.FileName - m.Range.StartLine - m.Range.StartColumn - (m.Severity.ToString()) - m.Code + | Error -> LogLevel.Error + | Warning -> LogLevel.Warning + | Info -> LogLevel.Information + | Hint -> LogLevel.Trace + + logger.Log( + msgLogLevel, + "{0}({1},{2}): {3} {4} - {5}", + m.Range.FileName, + m.Range.StartLine, + m.Range.StartColumn, + (m.Severity.ToString()), + m.Code, m.Message - - Console.ForegroundColor <- origForegroundColor + ) ) () @@ -362,8 +345,8 @@ let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) sarifLogger.Dispose() with ex -> - let details = if not verbose then "" else $" %A{ex}" - printfn $"Could not write sarif to %s{report}%s{details}" + logger.LogError("Could not write sarif to {report}") + logger.LogInformation("{0}", ex) let calculateExitCode (msgs: AnalyzerMessage list option) : int = match msgs with @@ -397,7 +380,7 @@ let expandMultiProperties (properties: (string * string) list) = for pair in splits.[1..] |> Seq.chunkBySize 2 do match pair with | [| k; v |] when String.IsNullOrWhiteSpace(v) -> - printError $"Missing property value for '{k}'" + logger.LogError("Missing property value for '{0}'", k) exit 1 | [| k; v |] -> yield (k, v) | _ -> () @@ -409,10 +392,10 @@ let expandMultiProperties (properties: (string * string) list) = let validateRuntimeOsArchCombination (runtime, arch, os) = match runtime, os, arch with | Some _, Some _, _ -> - printError "Specifying both the `-r|--runtime` and `-os` options is not supported." + logger.LogError("Specifying both the `-r|--runtime` and `-os` options is not supported.") exit 1 | Some _, _, Some _ -> - printError "Specifying both the `-r|--runtime` and `-a|--arch` options is not supported." + logger.LogError("Specifying both the `-r|--runtime` and `-a|--arch` options is not supported.") exit 1 | _ -> () @@ -456,8 +439,35 @@ let main argv = let toolsPath = Init.init (DirectoryInfo Environment.CurrentDirectory) None let results = parser.ParseCommandLine argv - verbose <- results.Contains <@ Verbose @> - printInfo "Running in verbose mode" + + let logLevel = + let verbosity = results.TryGetResult <@ Verbosity @> + + match verbosity with + | Some "d" + | Some "detailed" -> LogLevel.Information + | Some "diag" + | Some "diagnostic" -> LogLevel.Debug + | Some "n" -> LogLevel.Warning + | Some "normal" -> LogLevel.Warning + | None -> LogLevel.Warning + | Some x -> + use factory = LoggerFactory.Create(fun b -> b.AddConsole() |> ignore) + let logger = factory.CreateLogger("") + logger.LogError("unknown verbosity level given {0}", x) + exit 1 + + use factory = + LoggerFactory.Create(fun builder -> + builder + .AddCustomFormatter(fun options -> options.CustomPrefix <- "") + .SetMinimumLevel(logLevel) + |> ignore + ) + + logger <- factory.CreateLogger("") + + logger.LogInformation("Running in verbose mode") let severityMapping = { @@ -467,13 +477,13 @@ let main argv = TreatAsError = results.GetResult(<@ Treat_As_Error @>, []) |> Set.ofList } - printInfo "Treat as Hints: [%s]" (severityMapping.TreatAsHint |> String.concat ", ") - printInfo "Treat as Info: [%s]" (severityMapping.TreatAsInfo |> String.concat ", ") - printInfo "Treat as Warning: [%s]" (severityMapping.TreatAsWarning |> String.concat ", ") - printInfo "Treat as Error: [%s]" (severityMapping.TreatAsError |> String.concat ", ") + logger.LogInformation("Treat as Hints: [{0}]", (severityMapping.TreatAsHint |> String.concat ", ")) + logger.LogInformation("Treat as Info: [{0}]", (severityMapping.TreatAsInfo |> String.concat ", ")) + logger.LogInformation("Treat as Warning: [{0}]", (severityMapping.TreatAsWarning |> String.concat ", ")) + logger.LogInformation("Treat as Error: [{0}]", (severityMapping.TreatAsError |> String.concat ", ")) if not (severityMapping.IsValid()) then - printError "An analyzer code may only be listed once in the arguments." + logger.LogError("An analyzer code may only be listed once in the arguments.") exit 1 @@ -482,16 +492,16 @@ let main argv = let report = results.TryGetResult <@ Report @> let codeRoot = results.TryGetResult <@ Code_Root @> let ignoreFiles = results.GetResult(<@ Ignore_Files @>, []) - printInfo "Ignore Files: [%s]" (ignoreFiles |> String.concat ", ") + logger.LogInformation("Ignore Files: [{0}]", (ignoreFiles |> String.concat ", ")) let ignoreFiles = ignoreFiles |> List.map Glob let properties = getProperties results if Option.isSome fscArgs && not properties.IsEmpty then - printError "fsc-args can't be combined with MSBuild properties." + logger.LogError("fsc-args can't be combined with MSBuild properties.") exit 1 - if verbose then - properties |> List.iter (fun (k, v) -> printInfo $"Property %s{k}=%s{v}") + properties + |> List.iter (fun (k, v) -> logger.LogInformation("Property {0}={1}", k, v)) let analyzersPaths = results.GetResults(<@ Analyzers_Path @>) @@ -506,19 +516,10 @@ let main argv = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, path)) ) - printInfo "Loading analyzers from %s" (String.concat ", " analyzersPaths) + logger.LogInformation("Loading analyzers from {0}", (String.concat ", " analyzersPaths)) let excludeAnalyzers = results.GetResult(<@ Exclude_Analyzer @>, []) - let logger = - { new Logger with - member _.Error msg = printError msg - - member _.Verbose msg = - if verbose then - printInfo "%s" msg - } - AssemblyLoadContext.Default.add_Resolving (fun _ctx assemblyName -> if assemblyName.Name <> "FSharp.Core" then null @@ -530,7 +531,7 @@ let main argv = The correct version can be found over at https://www.nuget.org/packages/FSharp.Analyzers.SDK#dependencies-body-tab. """ - printError msg + logger.LogError(msg) exit 1 ) @@ -544,7 +545,7 @@ let main argv = (accDlls + dlls), (accAnalyzers + analyzers) ) - printInfo "Registered %d analyzers from %d dlls" analyzers dlls + logger.LogInformation("Registered {0} analyzers from {1} dlls", analyzers, dlls) let results = if analyzers = 0 then @@ -552,17 +553,17 @@ let main argv = else match projOpts, fscArgs with | [], None -> - printError "No project given. Use `--project PATH_TO_FSPROJ`." + logger.LogError("No project given. Use `--project PATH_TO_FSPROJ`.") None | _ :: _, Some _ -> - printError "`--project` and `--fsc-args` cannot be combined." + logger.LogError("`--project` and `--fsc-args` cannot be combined.") exit 1 | [], Some fscArgs -> runFscArgs client fscArgs ignoreFiles severityMapping |> Async.RunSynchronously | projects, None -> for projPath in projects do if not (File.Exists(projPath)) then - printError $"Invalid `--project` argument. File does not exist: '{projPath}'" + logger.LogError("Invalid `--project` argument. File does not exist: '{projPath}'") exit 1 projects diff --git a/src/FSharp.Analyzers.Cli/Properties/launchSettings.json b/src/FSharp.Analyzers.Cli/Properties/launchSettings.json index 75b12e2..3a967a7 100644 --- a/src/FSharp.Analyzers.Cli/Properties/launchSettings.json +++ b/src/FSharp.Analyzers.Cli/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "ReadMeSample": { "commandName": "Project", - "commandLineArgs": "--project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbose" + "commandLineArgs": "--project ./samples/OptionAnalyzer/OptionAnalyzer.fsproj --analyzers-path ./samples/OptionAnalyzer/bin/Release --verbosity d" } } } diff --git a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs index be04b01..b54e043 100644 --- a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs +++ b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs @@ -4,6 +4,7 @@ module FSharp.Analyzers.SDK.Testing #nowarn "57" open Microsoft.Build.Logging.StructuredLogger +open Microsoft.Extensions.Logging open CliWrap open System open System.IO @@ -245,9 +246,14 @@ let getContextFor (opts: FSharpProjectOptions) isSignature source = if Array.isEmpty allSymbolUses then failwith "no symboluses" - let printError s = printf $"{s}" - - match Utils.typeCheckFile fcs printError opts fileName (Utils.SourceOfSource.DiscreteSource source) with + match + Utils.typeCheckFile + fcs + Abstractions.NullLogger.Instance + opts + fileName + (Utils.SourceOfSource.DiscreteSource source) + with | Some(parseFileResults, checkFileResults) -> let diagErrors = checkFileResults.Diagnostics diff --git a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fsproj b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fsproj index b7e1cd9..a094f6f 100644 --- a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fsproj +++ b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fsproj @@ -19,6 +19,7 @@ + diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs index 8e5fa24..156206a 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs @@ -7,6 +7,7 @@ open System.Reflection open System.Runtime.Loader open System.Text.RegularExpressions open McMaster.NETCore.Plugins +open Microsoft.Extensions.Logging type AnalysisResult = { @@ -126,25 +127,15 @@ module Client = |> Seq.choose (analyzerFromMember<'TAnalyzerAttribute, 'TContext> path) |> Seq.toList -[] -type Logger = - abstract member Error: string -> unit - abstract member Verbose: string -> unit - type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TContext :> Context> - (logger: Logger, excludedAnalyzers: string Set) + (logger: ILogger, excludedAnalyzers: string Set) = + do TASTCollecting.logger <- logger + let registeredAnalyzers = ConcurrentDictionary list>() - new() = - Client( - { new Logger with - member this.Error _ = () - member this.Verbose _ = () - }, - Set.empty - ) + new() = Client(Abstractions.NullLogger.Instance, Set.empty) member x.LoadAnalyzers(dir: string) : int * int = if Directory.Exists dir then @@ -192,8 +183,12 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC then true else - logger.Error - $"Trying to load %s{name} which was built using SDK version %A{version}. Expect %A{Utils.currentFSharpAnalyzersSDKVersion} instead. Assembly will be skipped." + logger.LogError( + "Trying to load {0} which was built using SDK version {1}. Expect {2} instead. Assembly will be skipped.", + name, + version, + Utils.currentFSharpAnalyzersSDKVersion + ) false ) @@ -205,7 +200,11 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC let shouldExclude = excludedAnalyzers.Contains(registeredAnalyzer.Name) if shouldExclude then - logger.Verbose $"Excluding %s{registeredAnalyzer.Name} from %s{assembly.FullName}" + logger.LogInformation( + "Excludings{0} from {1}", + registeredAnalyzer.Name, + assembly.FullName + ) not shouldExclude ) diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fsi b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fsi index d70dcb2..9a52a04 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fsi +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fsi @@ -1,18 +1,15 @@ namespace FSharp.Analyzers.SDK +open Microsoft.Extensions.Logging + type AnalysisResult = { AnalyzerName: string Output: Result } -[] -type Logger = - abstract member Error: string -> unit - abstract member Verbose: string -> unit - type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TContext :> Context> = - new: logger: Logger * excludedAnalyzers: string Set -> Client<'TAttribute, 'TContext> + new: logger: ILogger * excludedAnalyzers: string Set -> Client<'TAttribute, 'TContext> new: unit -> Client<'TAttribute, 'TContext> /// /// Loads into private state any analyzers defined in any assembly diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fs b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fs index 564d950..bd494d9 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fs +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fs @@ -3,6 +3,7 @@ namespace FSharp.Analyzers.SDK #nowarn "57" open System +open Microsoft.Extensions.Logging open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.EditorServices @@ -224,7 +225,7 @@ module Utils = let typeCheckFile (fcs: FSharpChecker) - (printError: string -> unit) + (logger: ILogger) (options: FSharpProjectOptions) (fileName: string) (source: SourceOfSource) @@ -244,6 +245,6 @@ module Utils = match checkAnswer with | FSharpCheckFileAnswer.Aborted -> - printError $"Checking of file {fileName} aborted" + logger.LogError("Checking of file {0} aborted", fileName) None | FSharpCheckFileAnswer.Succeeded result -> Some(parseRes, result) diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsi b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsi index 960d586..b3ef146 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsi +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsi @@ -2,6 +2,7 @@ namespace FSharp.Analyzers.SDK open System open System.Runtime.InteropServices +open Microsoft.Extensions.Logging open FSharp.Compiler.CodeAnalysis open FSharp.Compiler.Symbols open FSharp.Compiler.EditorServices @@ -165,7 +166,7 @@ module Utils = val typeCheckFile: fcs: FSharpChecker -> - printError: (string -> unit) -> + logger: ILogger -> options: FSharpProjectOptions -> fileName: string -> source: SourceOfSource -> diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj index d68b907..51a47d0 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj @@ -22,5 +22,6 @@ + \ No newline at end of file diff --git a/src/FSharp.Analyzers.SDK/TASTCollecting.fs b/src/FSharp.Analyzers.SDK/TASTCollecting.fs index ccc42e6..4f7587b 100644 --- a/src/FSharp.Analyzers.SDK/TASTCollecting.fs +++ b/src/FSharp.Analyzers.SDK/TASTCollecting.fs @@ -1,11 +1,14 @@ namespace FSharp.Analyzers.SDK +open Microsoft.Extensions.Logging open FSharp.Compiler.Symbols open FSharp.Compiler.Text open FSharp.Compiler.Symbols.FSharpExprPatterns module TASTCollecting = + let mutable logger: ILogger = Abstractions.NullLogger.Instance + type TypedTreeCollectorBase() = abstract WalkCall: objExprOpt: FSharpExpr option -> @@ -139,7 +142,9 @@ module TASTCollecting = try visitExpr f e with ex -> - printfn $"unhandled expression at {e.Range.FileName}:{e.Range.ToString()}" + logger.LogDebug("unhandled expression at {0}:{1}", e.Range.FileName, e.Range.ToString()) + logger.LogDebug("{0}", ex.Message) + logger.LogDebug("{0}", ex.StackTrace) | FSharpImplementationFileDeclaration.InitAction e -> visitExpr f e let walkTast (walker: TypedTreeCollectorBase) (tast: FSharpImplementationFileContents) : unit = diff --git a/src/FSharp.Analyzers.SDK/TASTCollecting.fsi b/src/FSharp.Analyzers.SDK/TASTCollecting.fsi index 9cff195..f3d41fc 100644 --- a/src/FSharp.Analyzers.SDK/TASTCollecting.fsi +++ b/src/FSharp.Analyzers.SDK/TASTCollecting.fsi @@ -1,5 +1,6 @@ namespace FSharp.Analyzers.SDK +open Microsoft.Extensions.Logging open FSharp.Compiler.Symbols open FSharp.Compiler.Text @@ -36,3 +37,6 @@ module TASTCollecting = /// Traverses the whole TAST and calls the appropriate members of the given TypedTreeCollectorBase /// to process the tree elements. val walkTast: walker: TypedTreeCollectorBase -> tast: FSharpImplementationFileContents -> unit + + /// Set this to use a custom logger + val mutable logger: ILogger From af76a935ca00480dee2d075da044801b20a1eede Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 16:58:28 +0100 Subject: [PATCH 2/8] colored output --- src/FSharp.Analyzers.Cli/Logging.fs | 41 ++++++++++++++++--- src/FSharp.Analyzers.Cli/Program.fs | 39 ++++++++++++------ .../FSharp.Analyzers.SDK.Testing.fs | 4 +- .../FSharp.Analyzers.SDK.Client.fs | 4 +- 4 files changed, 65 insertions(+), 23 deletions(-) diff --git a/src/FSharp.Analyzers.Cli/Logging.fs b/src/FSharp.Analyzers.Cli/Logging.fs index 1cf2651..21bd81c 100644 --- a/src/FSharp.Analyzers.Cli/Logging.fs +++ b/src/FSharp.Analyzers.Cli/Logging.fs @@ -1,4 +1,4 @@ -namespace Console.ExampleFormatters.Custom +module FSharp.Analyzers.Cli.CustomLogging open System open System.IO @@ -11,13 +11,16 @@ open Microsoft.Extensions.Options type CustomOptions() = inherit ConsoleFormatterOptions() - member val CustomPrefix = "" with get, set + /// if true: no LogLevel as prefix, colored output according to LogLevel + /// if false: LogLevel as prefix, no colored output + member val UseAnalyzersMsgStyle = false with get, set type CustomFormatter(options: IOptionsMonitor) as this = inherit ConsoleFormatter("customName") let mutable optionsReloadToken: IDisposable = null let mutable formatterOptions = options.CurrentValue + let origColor = Console.ForegroundColor do optionsReloadToken <- options.OnChange(fun x -> this.ReloadLoggerOptions(x)) @@ -31,11 +34,37 @@ type CustomFormatter(options: IOptionsMonitor) as this = ) = let message = logEntry.Formatter.Invoke(logEntry.State, logEntry.Exception) - this.CustomLogic(textWriter) - textWriter.WriteLine(message) - member private _.CustomLogic(textWriter: TextWriter) = - textWriter.Write(formatterOptions.CustomPrefix) + if formatterOptions.UseAnalyzersMsgStyle then + this.SetColor(textWriter, logEntry.LogLevel) + textWriter.WriteLine(message) + this.ResetColor() + else + this.WritePrefix(textWriter, logEntry.LogLevel) + textWriter.WriteLine(message) + + member private _.WritePrefix(textWriter: TextWriter, logLevel: LogLevel) = + match logLevel with + | LogLevel.Trace -> textWriter.Write("trace: ") + | LogLevel.Debug -> textWriter.Write("debug: ") + | LogLevel.Information -> textWriter.Write("info: ") + | LogLevel.Warning -> textWriter.Write("warn: ") + | LogLevel.Error -> textWriter.Write("error: ") + | LogLevel.Critical -> textWriter.Write("critical: ") + | _ -> () + + member private _.SetColor(textWriter: TextWriter, logLevel: LogLevel) = + let color = + match logLevel with + | LogLevel.Error -> "\x1B[1m\x1B[31m" // ConsoleColor.Red + | LogLevel.Warning -> "\x1B[33m" // ConsoleColor.DarkYellow + | LogLevel.Information -> "\x1B[1m\x1B[34m" // ConsoleColor.Blue + | LogLevel.Trace -> "\x1B[1m\x1B[36m" // ConsoleColor.Cyan + | _ -> "\x1B[37m" // ConsoleColor.Gray + + textWriter.Write(color) + + member private _.ResetColor() = Console.ForegroundColor <- origColor interface IDisposable with member _.Dispose() = optionsReloadToken.Dispose() diff --git a/src/FSharp.Analyzers.Cli/Program.fs b/src/FSharp.Analyzers.Cli/Program.fs index 3ce7400..9f9a2e4 100644 --- a/src/FSharp.Analyzers.Cli/Program.fs +++ b/src/FSharp.Analyzers.Cli/Program.fs @@ -12,7 +12,7 @@ open Microsoft.CodeAnalysis.Sarif open Microsoft.CodeAnalysis.Sarif.Writers open Microsoft.Extensions.Logging open Ionide.ProjInfo -open Console.ExampleFormatters.Custom +open FSharp.Analyzers.Cli.CustomLogging type Arguments = | Project of string list @@ -182,7 +182,7 @@ let runProject let fsharpFiles = set [| ".fs"; ".fsi"; ".fsx" |] let isFSharpFile (file: string) = - Seq.exists (fun (ext: string) -> file.EndsWith ext) fsharpFiles + Set.exists (fun (ext: string) -> file.EndsWith(ext, StringComparison.Ordinal)) fsharpFiles let runFscArgs (client: Client) @@ -229,22 +229,35 @@ let runFscArgs runProjectAux client projectOptions globs mappings let printMessages (msgs: AnalyzerMessage list) = + + let severityToLogLevel = + Map.ofArray + [| + Error, LogLevel.Error + Warning, LogLevel.Warning + Info, LogLevel.Information + Hint, LogLevel.Trace + |] + if List.isEmpty msgs then logger.LogInformation("No messages found from the analyzer(s)") + use factory = + LoggerFactory.Create(fun builder -> + builder + .AddCustomFormatter(fun options -> options.UseAnalyzersMsgStyle <- true) + .SetMinimumLevel(LogLevel.Trace) + |> ignore + ) + + let msgLogger = factory.CreateLogger("") + msgs |> Seq.iter (fun analyzerMessage -> let m = analyzerMessage.Message - let msgLogLevel = - match m.Severity with - | Error -> LogLevel.Error - | Warning -> LogLevel.Warning - | Info -> LogLevel.Information - | Hint -> LogLevel.Trace - - logger.Log( - msgLogLevel, + msgLogger.Log( + severityToLogLevel[m.Severity], "{0}({1},{2}): {3} {4} - {5}", m.Range.FileName, m.Range.StartLine, @@ -273,7 +286,7 @@ let writeReport (results: AnalyzerMessage list option) (codeRoot: string option) let driver = ToolComponent() driver.Name <- "Ionide.Analyzers.Cli" driver.InformationUri <- Uri("https://ionide.io/FSharp.Analyzers.SDK/") - driver.Version <- string (System.Reflection.Assembly.GetExecutingAssembly().GetName().Version) + driver.Version <- string (System.Reflection.Assembly.GetExecutingAssembly().GetName().Version) let tool = Tool() tool.Driver <- driver let run = Run() @@ -460,7 +473,7 @@ let main argv = use factory = LoggerFactory.Create(fun builder -> builder - .AddCustomFormatter(fun options -> options.CustomPrefix <- "") + .AddCustomFormatter(fun options -> options.UseAnalyzersMsgStyle <- false) .SetMinimumLevel(logLevel) |> ignore ) diff --git a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs index b54e043..6769c5e 100644 --- a/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs +++ b/src/FSharp.Analyzers.SDK.Testing/FSharp.Analyzers.SDK.Testing.fs @@ -44,7 +44,7 @@ exception CompilerDiagnosticErrors of FSharpDiagnostic array let fsharpFiles = set [| ".fs"; ".fsi"; ".fsx" |] let isFSharpFile (file: string) = - Seq.exists (fun (ext: string) -> file.EndsWith ext) fsharpFiles + Set.exists (fun (ext: string) -> file.EndsWith(ext, StringComparison.Ordinal)) fsharpFiles let readCompilerArgsFromBinLog (build: Build) = if not build.Succeeded then @@ -82,7 +82,7 @@ let readCompilerArgsFromBinLog (build: Build) = match args with | None -> failwith $"Could not parse binlog at {build.LogFilePath}, does it contain CoreCompile?" | Some args -> - let idx = args.IndexOf "-o:" + let idx = args.IndexOf("-o:", StringComparison.Ordinal) args.Substring(idx).Split [| '\n' |] let mkOptions (compilerArgs: string array) = diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs index 156206a..168e491 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs @@ -28,7 +28,7 @@ module Client = let isAnalyzer<'TAttribute when 'TAttribute :> AnalyzerAttribute> (mi: MemberInfo) = mi.GetCustomAttributes true - |> Seq.tryFind (fun n -> n.GetType().Name = typeof<'TAttribute>.Name) + |> Array.tryFind (fun n -> n.GetType().Name = typeof<'TAttribute>.Name) |> Option.map unbox<'TAttribute> let analyzerFromMember<'TAnalyzerAttribute, 'TContext @@ -217,7 +217,7 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC registeredAnalyzers.AddOrUpdate(path, analyzers, (fun _ _ -> analyzers)) |> ignore - Seq.length analyzers, analyzers |> Seq.collect snd |> Seq.length + Array.length analyzers, analyzers |> Seq.collect snd |> Seq.length else 0, 0 From 96e5b27c10bdc03a55638760e36ae51885353964 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 17:09:25 +0100 Subject: [PATCH 3/8] fix usage --- src/FSharp.Analyzers.Cli/Program.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Analyzers.Cli/Program.fs b/src/FSharp.Analyzers.Cli/Program.fs index 9f9a2e4..38e6705 100644 --- a/src/FSharp.Analyzers.Cli/Program.fs +++ b/src/FSharp.Analyzers.Cli/Program.fs @@ -55,7 +55,7 @@ type Arguments = | Exclude_Analyzer _ -> "The names of analyzers that should not be executed." | Report _ -> "Write the result messages to a (sarif) report file." | Verbosity _ -> - "The verbosity level. The available verbosity levels are: n[ormal], d[etailed], diag[nostic]" + "The verbosity level. The available verbosity levels are: n[ormal], d[etailed], diag[nostic]." | FSC_Args _ -> "Pass in the raw fsc compiler arguments. Cannot be combined with the `--project` flag." | Code_Root _ -> "Root of the current code repository, used in the sarif report to construct the relative file path. The current working directory is used by default." From 8673e278818b258f1d1f651644155f9ee95555b7 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 17:55:20 +0100 Subject: [PATCH 4/8] Let the SDK depend on Microsoft.Extensions.Logging.Abstractions --- Directory.Packages.props | 1 + src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index c9eee85..5aa4b90 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,6 +20,7 @@ + diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj index 51a47d0..3eb09bb 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.fsproj @@ -22,6 +22,6 @@ - + \ No newline at end of file From ffadf7cfa1a67ce6396f7765008f8db49ee64374 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 17:55:56 +0100 Subject: [PATCH 5/8] Update src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs Co-authored-by: Florian Verdonck --- src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs index 168e491..9608774 100644 --- a/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs +++ b/src/FSharp.Analyzers.SDK/FSharp.Analyzers.SDK.Client.fs @@ -201,7 +201,7 @@ type Client<'TAttribute, 'TContext when 'TAttribute :> AnalyzerAttribute and 'TC if shouldExclude then logger.LogInformation( - "Excludings{0} from {1}", + "Excluding {0} from {1}", registeredAnalyzer.Name, assembly.FullName ) From 504677b0c367be381731133f489422df8b215aa4 Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 17:59:39 +0100 Subject: [PATCH 6/8] add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5271e7..af5556b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### Changed * [Add path to ASTCollecting](https://github.com/ionide/FSharp.Analyzers.SDK/pull/171) (thanks @nojaf!) +* [Use Microsoft.Extensions.Logging instead of printf based logging infrastructure](https://github.com/ionide/FSharp.Analyzers.SDK/pull/175) (thanks @dawedawe!) ## [0.21.0] - 2023-11-22 From 30c86289be56f87bf3e5d2f46b50f5637301f1ce Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 18:01:17 +0100 Subject: [PATCH 7/8] add link to documentation about color settings --- src/FSharp.Analyzers.Cli/Logging.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharp.Analyzers.Cli/Logging.fs b/src/FSharp.Analyzers.Cli/Logging.fs index 21bd81c..60011d7 100644 --- a/src/FSharp.Analyzers.Cli/Logging.fs +++ b/src/FSharp.Analyzers.Cli/Logging.fs @@ -53,6 +53,7 @@ type CustomFormatter(options: IOptionsMonitor) as this = | LogLevel.Critical -> textWriter.Write("critical: ") | _ -> () + // see https://learn.microsoft.com/en-us/dotnet/core/extensions/console-log-formatter member private _.SetColor(textWriter: TextWriter, logLevel: LogLevel) = let color = match logLevel with From 0d3d02957d043e23baa8fb8f434f8bfa30cf1bcb Mon Sep 17 00:00:00 2001 From: dawe Date: Tue, 12 Dec 2023 18:01:46 +0100 Subject: [PATCH 8/8] rename file to match module name --- src/FSharp.Analyzers.Cli/{Logging.fs => CustomLogging.fs} | 0 src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename src/FSharp.Analyzers.Cli/{Logging.fs => CustomLogging.fs} (100%) diff --git a/src/FSharp.Analyzers.Cli/Logging.fs b/src/FSharp.Analyzers.Cli/CustomLogging.fs similarity index 100% rename from src/FSharp.Analyzers.Cli/Logging.fs rename to src/FSharp.Analyzers.Cli/CustomLogging.fs diff --git a/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj b/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj index 75da0cf..eb2711a 100644 --- a/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj +++ b/src/FSharp.Analyzers.Cli/FSharp.Analyzers.Cli.fsproj @@ -13,7 +13,7 @@ - +