{"id":28361636,"url":"https://github.com/mvkara/loggerwrapper-fsharp","last_synced_at":"2025-10-18T01:37:37.291Z","repository":{"id":144136342,"uuid":"121937627","full_name":"mvkara/loggerwrapper-fsharp","owner":"mvkara","description":"Library to wrap most .NET logging frameworks giving them a functional F# style API","archived":false,"fork":false,"pushed_at":"2020-02-03T09:32:37.000Z","size":60,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-04T21:32:32.688Z","etag":null,"topics":["fsharp","logger","logging"],"latest_commit_sha":null,"homepage":null,"language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mvkara.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-02-18T09:34:18.000Z","updated_at":"2024-12-02T08:01:25.000Z","dependencies_parsed_at":"2023-04-03T15:19:24.929Z","dependency_job_id":null,"html_url":"https://github.com/mvkara/loggerwrapper-fsharp","commit_stats":null,"previous_names":["mvkra/loggerwrapper-fsharp"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/mvkara/loggerwrapper-fsharp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvkara%2Floggerwrapper-fsharp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvkara%2Floggerwrapper-fsharp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvkara%2Floggerwrapper-fsharp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvkara%2Floggerwrapper-fsharp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mvkara","download_url":"https://codeload.github.com/mvkara/loggerwrapper-fsharp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mvkara%2Floggerwrapper-fsharp/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260944176,"owners_count":23086750,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fsharp","logger","logging"],"created_at":"2025-05-28T14:08:22.174Z","updated_at":"2025-10-18T01:37:37.286Z","avatar_url":"https://github.com/mvkara.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# loggerwrapper-fsharp\n\nA small lightweight library to wrap most .NET logging frameworks giving them a functional F# style API.\nContains handly utility functions that are useful if you are in a project that requires you to use a particular logging framework not designed for F# use.\n\nSome features:\n\n- Printf style logging for any logging framework. Note that logging strings aren't built/allocated if logging is turned off to save performance especially around Debug logging.\n- Global logging sink as a singleton; meaning logging factories don't have to clutter your app if you prefer this style which is similar to many static logging .NET frameworks (e.g Log4Net, NLog).\n- No other package dependencies required to allow logging to function (besides FSharp.Core).\n- etc.\n\n## Writing your own logging sink\n\n### Console Logger Example ###\n\nAn example of how to wrap a console logger is below:\n\n```\nlet consoleLoggingSink applicablePredicate allowRuntimeChange : LoggingFactory = fun loggerName logLevel -\u003e \n    \n    let consoleLogLevelLogger = \n        fun exnOpt message -\u003e\n            match exnOpt with\n            | Some(e) -\u003e printfn \"%A %s [Error: %s]\" logLevel message e.StackTrace\n            | None -\u003e printfn \"%A %s\" logLevel message\n    \n    let buildLoggerOpt() =  \n        if applicablePredicate loggerName logLevel\n        then Some consoleLogLevelLogger\n        else None\n\n    if allowRuntimeChange\n    then Deferred buildLoggerOpt\n    elif applicablePredicate loggerName logLevel\n    then Applicable consoleLogLevelLogger\n    else NeverApplicable\n```\n\nIn this example the applicability of whether the log should trigger is decided by the applicablePredicate function. Note that the allowRuntime change variable exposes the user to a tradeoff; if logging levels don't need to change at runtime we can move the applicability check to the initialisation of the logger rather than the logger call by setting this to false. When wrapping most logging frameworks you simply invoke the underlying frameworks IsApplicable method instead for the applicability check.\n\n### ASP.NET/Microsoft.Extensions.Logging Example ###\nAnother example wrapping ASP.NET's ILoggerFactory (Microsoft.Extensions.Logging) that uses the underlying framework's check:\n\n```\nopen Microsoft.Extensions.Logging\nopen LoggerWrapper.FSharp\n\nlet createLoggerFactory (loggerFactory: ILoggerFactory) : LoggingFactory = fun loggerName loggerLevel -\u003e \n\n    let logger = loggerFactory.CreateLogger(loggerName)\n    \n    let inline convertLoggerLevels (loggerLevel: LoggerWrapper.FSharp.LogLevel) = \n        match loggerLevel with \n        | LogLevel.Info -\u003e Microsoft.Extensions.Logging.LogLevel.Information\n        | LogLevel.Debug -\u003e Microsoft.Extensions.Logging.LogLevel.Debug\n        | LogLevel.Error -\u003e Microsoft.Extensions.Logging.LogLevel.Error\n        | LogLevel.Fatal -\u003e Microsoft.Extensions.Logging.LogLevel.Critical\n        | LogLevel.Verbose -\u003e Microsoft.Extensions.Logging.LogLevel.Trace\n        | LogLevel.Warn -\u003e Microsoft.Extensions.Logging.LogLevel.Warning\n        | LogLevel.Trace -\u003e Microsoft.Extensions.Logging.LogLevel.Trace\n\n    let frameworkLoggingLevel = convertLoggerLevels loggerLevel\n\n    let loggerFunc = fun exOpt message -\u003e \n        match exOpt with \n        | Some(ex) -\u003e logger.Log\u003c_\u003e(frameworkLoggingLevel, EventId(0), message, ex, fun s _ -\u003e s)\n        | None -\u003e logger.Log\u003c_\u003e(frameworkLoggingLevel, EventId(0), message, null, fun s _ -\u003e s)\n    \n    if logger.IsEnabled(frameworkLoggingLevel) then Applicable loggerFunc else NeverApplicable\n```\n\n## Creating a logger\n\nTo create a logger inside your module there are a number of ways.\n\n### Using a string name\n\nYou can either call the \"LoggingFactory\" func directly with the name or use the convienence wrapper inside the Logger module.\n\n```\nLogger.createLoggerByName loggingFactory \"TestLogger\"\n```\n\n### Using a function instance to determine logger name\n\nAlternatively for type safety you can use either a member name or its enclosing type name (a module or class name) as the name of your logger. Example code is below.\n\ne.g.\n\n```\nmodule ModuleToLog = \n  // Logger name will be \"ModuleToLog\"\n  let rec logger = Logger.createLoggerFromMemberType staticLoggingFactory \u003c@ logger @\u003e\n\n  let rec doSomethingFunc loggerFactory () = \n    let logger = Logger.createLoggerFromMemberName \u003c@ doSomethingFunc @\u003e\n    // Rest of method code below...\n    ()\n```\n\n## Logging\n\nLogging is done via the Logger.logFormat* functions. Example is below\n\n```\nLogger.logFormat (logger LogLevel.Info) \"Example typesafe log %s %A\" \"1\" (2, 3)\n```\n\nNote: If runtime logging applicability check is disabled and performance is a concern it may be worth creating LoggerFunc's per level in advance especially around Debug or Trace logging.\nThis amortizes the cost of checking if the logger is applicable to only when the logging function is built. As an example:\n\n```\nlet debugLoggerFunc = logFactory \"LoggerName\" LogLevel.Debug // Note I applied the LogLevel as well\nLogger.logFormat debugLoggerFunc \"Example typesafe log %s %A\" \"1\" (2, 3)\n```\n\n## Composite logging factory/global logging\n\nThis is provided if you want your logging to log to more than one target for any particular reason. It's also useful as a way to avoid passing multiple logging factories through your program stack and/or outputting logs to more than one source.\n\nIn addition the module provides a optional static/singleton composite logging factory instance that can be used as an alternative to passing around the logger factory/loggers throughout your program. Simply initialise the logger factory you want to use by calling ```CompositeLoggingFactory.registerLogFactoryIntoGlobal``` with the logger factories you want to use before creating loggers.\n\nAn example showing both is below:\n\n```\nmodule SetupProgram = \n    let registerLoggingFactoryCreatedElsewhere (loggingFactory: LoggingFactory) = \n        // This registers the logging factory provided as  a sink to the globalLoggingFactory used for logger above.\n        CompositeLoggingFactory.registerLogFactoryIntoGlobal loggingFactory\n\n// Any module in the program\nmodule ModuleToLog = \n    let rec logger = Logger.createLoggerFromMemberType CompositeLoggingFactory.globalCompositeFactory \u003c@ logger @\u003e\n\n    let exampleFunction() = \n        Logger.logFormat (logger LogLevel.Info) \"This will use the ModuleToLog logger with the log factories registered in the global composite factory\"   \n```\n\n\n# Releases\n\nReleases are made to GitHub and Nuget.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvkara%2Floggerwrapper-fsharp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmvkara%2Floggerwrapper-fsharp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmvkara%2Floggerwrapper-fsharp/lists"}