Skip to content

Instantly share code, notes, and snippets.

@Thorium
Last active February 16, 2024 15:23
Show Gist options
  • Save Thorium/fa7bb89fd9b165c5e57820eeec9bd6d0 to your computer and use it in GitHub Desktop.
Save Thorium/fa7bb89fd9b165c5e57820eeec9bd6d0 to your computer and use it in GitHub Desktop.
Use (or replace) existing Logary via Microsoft.Extensions.Logging.Abstractions. This can be used to abstract Logary behind Microsoft.Extensions.Logging so it's easier to remove from existing infra (or migrate to, whatever).
// 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()
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()
@Thorium
Copy link
Author

Thorium commented Dec 14, 2023

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment