Created by
Tuomas Hietanen
last modified
2024-02-16
// This expects you have 2 projects, this first one has dependendency only to Microsoft.Extensions.Logging.Abstractions
// (and temporarily usage of Microsoft.Extensions.Logging.Console ).
module AbstractProject
let loggerFactory =
Microsoft.Extensions.Logging.LoggerFactory.Create(fun builder ->
let _ = Microsoft.Extensions.Logging.ConsoleLoggerExtensions.AddSimpleConsole builder
())
/// This is ILogger.
let mutable logger = lazy(loggerFactory.CreateLogger("Temp-logger")) // Initially some temp-logger, replaced below.
/// Module to repalce Logary with Microsoft.Extensions.Logging
/// Usage: Replace Logary.Message.eventDebug "hi {a}" |> Logary.Message "a" "world" |> writeLogSimple
/// With: Logari.Message.eventDebug "hi {a}" |> Logari.Message "a" "world" |> writeLogSimple
module Logari =
type CustomMessage =
{ Level: Microsoft.Extensions.Logging.LogLevel
Message: string
Fields: System.Collections.Generic.Dictionary<string, obj>
} with override this.ToString() =
if this = Unchecked.defaultof<CustomMessage> then "" else
let mutable sb = System.Text.StringBuilder this.Message
if this.Fields = null then sb.ToString()
else
for i in this.Fields do
if i.Value <> null then
sb <- sb.Replace("{" + i.Key + "}", i.Value.ToString())
sb.ToString()
module Message =
let eventDebug (msg:string) = {Level = Microsoft.Extensions.Logging.LogLevel.Debug; Message = msg; Fields = new System.Collections.Generic.Dictionary<_,_>()}
let eventInfo (msg:string) = {Level = Microsoft.Extensions.Logging.LogLevel.Information; Message = msg; Fields = new System.Collections.Generic.Dictionary<_,_>()}
let eventWarn (msg:string) = {Level = Microsoft.Extensions.Logging.LogLevel.Warning; Message = msg; Fields = new System.Collections.Generic.Dictionary<_,_>()}
let eventError (msg:string) = {Level = Microsoft.Extensions.Logging.LogLevel.Error; Message = msg; Fields = new System.Collections.Generic.Dictionary<_,_>()}
let eventFatal (msg:string) = {Level = Microsoft.Extensions.Logging.LogLevel.Critical; Message = msg; Fields = new System.Collections.Generic.Dictionary<_,_>()}
let setField (name:string) (value:obj) (msg:CustomMessage)=
if not (msg.Fields.ContainsKey name) then
msg.Fields.Add(name, value)
msg
let setFieldFromObject (name:string) (value:obj) (msg:CustomMessage)=
if not (msg.Fields.ContainsKey name) then
msg.Fields.Add(name, value)
msg
module Logger =
let logSimple (l:Microsoft.Extensions.Logging.ILogger) (msg:CustomMessage) =
l.Log(msg.Level, 0 , msg, null, fun msg _ -> msg.ToString())
let writeLogSimple = Logari.Logger.logSimple
// This second one has Logary dependency that is registering the Logary as Microsoft.Extensions.Logging.Abstraction
[<AutoOpen>]
module Logging
open Microsoft.Extensions.Logging
open Logary
/// Old Logary direct calls:
let logger = lazy(Logary.Logging.getCurrentLogger())
/// General Logary logger
let writeLog x =
let l = logger.Force()
Logary.Logger.logSimple l x
type LogaryLogger(name) =
new() = LogaryLogger "default"
interface ILogger with
member __.IsEnabled(_) = true
member __.BeginScope(_) = { new System.IDisposable with
member this.Dispose() = ()}
member __.Log(level, evetId:EventId, state, ex, formatter) =
let msg = unbox<AbstractProject.Logari.CustomMessage>(state)
let mutable lmsg =
match level with
| Microsoft.Extensions.Logging.LogLevel.Debug ->
Logary.Message.eventDebug msg.Message
| Microsoft.Extensions.Logging.LogLevel.Information ->
Logary.Message.eventInfo msg.Message
| Microsoft.Extensions.Logging.LogLevel.Warning ->
Logary.Message.eventWarn msg.Message
| Microsoft.Extensions.Logging.LogLevel.Error ->
Logary.Message.eventError msg.Message
| Microsoft.Extensions.Logging.LogLevel.Critical ->
Logary.Message.eventFatal msg.Message
| Microsoft.Extensions.Logging.LogLevel.Trace
| Microsoft.Extensions.Logging.LogLevel.None
| _ -> Logary.Message.eventVerbose msg.Message
for i in msg.Fields do
lmsg <- lmsg |> Message.setFieldFromObject i.Key i.Value
()
writeLog lmsg
[<ProviderAlias("LogaryLogger")>]
type LogaryLoggerProvider() =
let loggers = System.Collections.Concurrent.ConcurrentDictionary<string, LogaryLogger>()
interface ILoggerProvider with
member _.CreateLogger categoryName =
loggers.GetOrAdd(categoryName, fun name -> new LogaryLogger(name));
member _.Dispose() = loggers.Clear()
let mutable loggingSetup = false
let setupLogging() =
if not loggingSetup then
AbstractProject.logger <- lazy(LogaryLogger() :> ILogger)
loggingSetup <- true
setupLogging()