Snippets

Tuomas Hietanen 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

Created by Tuomas Hietanen last modified
// 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()

Comments (1)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.