sabato 16 luglio 2016

New Fluent interface in Fslog

Fslog is a simple yet powerful library that can be used to log messages in your program. It was implemented with a semantic approach in mind, and you can find it on GitHub.


The initial interface was a bit cumbersome to use, so I decided to implement a more user friendly interface based on the Fluent style. Let see how to use this new interface, the first step is to configure a LogProvider:
open System
open ES.Fslog

let lp = new LogProvider()
let consoleLogger = new ConsoleLogger(LogLevel.Informational)
lp.AddLogger(consoleLogger)
That piece of code creates and configures a LogProvider with a ConsoleLogger. Now you can create your own LogSource and add it to the LogProvider in order to start to log to the console. Of course you can customize how the log messages are displayed by creating a LogFormatter, like this:
open System
open ES.Fslog
open ES.Fslog.Loggers
open ES.Fslog.TextFormatters

type internal ConsoleLogFormatter() = 
    let getLevelStr(logLevel: LogLevel) =
        match logLevel with
        | LogLevel.Critical      -> "CRIT"
        | LogLevel.Error         -> "ERRO"
        | LogLevel.Warning       -> "WARN"
        | LogLevel.Informational -> "INFO"
        | LogLevel.Verbose       -> "TRAC"
        | _ -> failwith "getLevelStr"
    
    member this.FormatMessage(logEvent: LogEvent) =
        String.Format("[{0}] {1}", getLevelStr(logEvent.Level), logEvent.Message)            

    interface ITextFormatter with
        member this.FormatMessage(logEvent: LogEvent) =
            this.FormatMessage(logEvent)

let customConsoleLogger = new ConsoleLogger(logLevel, new ConsoleLogFormatter())
You can now implement the different log sources where necessary, this is a very easy task thanks to the new fluent interface:
open System
open ES.Fslog

// create the log source
let logSource = 
    log "EntityRepository"
    |> verbose "NoPrint" "I will not be printed due to the current LogLevel value :("
    |> info "Start" "Process started!"
    |> warning "FileNotFound" "Unable to open the file {0}, create it"
    |> warning "DirectoryNotFound" "Unable to list file in directory: {0}. Create it."
    |> error "UnableToCreateFile" "Unable to create the file: {0} in directory: {1}"
    |> critical "DatabaseDown" "Database is not reachable, this is not good!"
    |> build

// add the log source to the log provider
logProvider.AddLogSourceToLoggers(logSource)

// start to log
logSource?NoPrint()
logSource?Start()
logSource?FileNotFound("log.txt")
logSource?DirectoryNotFound("logDirectory/")
logSource?UnableToCreateFile("log.txt", "logDirectory/")
logSource?DatabaseDown()
And that's all, you can find more examples in the FluentTests class.