Suave plugin to use the awesome Serilog library as the logger for your application
Switch branches/tags
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Suave.SerilogExtensions Build Status Nuget

Suave plugin to use the awesome Serilog library as the logger for your application


Install from Nuget:

# using nuget client
dotnet add package Suave.SerilogExtensions
# using Paket
mono .paket/paket.exe add Suave.SerilogExtensions --project path/to/Your.fsproj


Wrap an existing WebPart with SerilogAdapter.Enable:

open Suave
open Suave.Filters
open Suave.Operators
open Suave.Successful
open Suave.SerilogExtensions
open Serilog 

let webApp = GET >=> path "/" >=> OK "Home"

// webAppWithLogging : WebPart
let webAppWithLogging = SerilogAdapter.Enable(webApp)

// Configure serilog 
Log.Logger <- 
    .WriteTo.Console() // from Serilog.Sinks.Console

startWebServer defaultConfig webAppWithLogging

Now dotnet run and curl http://localhost:8080 to get the following logs:

[20:33:37 INF] Smooth! Suave listener started in 185.966 with binding
[20:35:42 INF] GET Request at /
[20:35:42 INF] GET Response (StatusCode 200) at / took 121 ms

These request and response log events contain many properties that are extracted from the HttpContext, enable a detailed console sink to see this in action:

open Serilog.Formatting.Json
Log.Logger <- 
    .WriteTo.Console() // from Serilog.Sinks.Console

Now there logs become:

[20:39:48 INF] Smooth! Suave listener started in 146.37 with binding
[20:39:54 INF] GET Request at /
{"Timestamp":"2018-03-25T20:39:54.4942292+02:00","Level":"Information","MessageTemplate":"{Method} Request at {FullPath}","Properties":{"RequestId":"9817639f-fcc6-45c5-9c41-593f707a0649","Type":"Request","Path":"/","FullPath":"/","Method":"GET","Host":"localhost","QueryString":"","Query":{},"UserIPAddress":"","RequestHeaders":{"accept":"*/*"},"UserAgent":"curl/7.55.1","Body":""}}
[20:39:54 INF] GET Response (StatusCode 200) at / took 140 ms
{"Timestamp":"2018-03-25T20:39:54.6245586+02:00","Level":"Information","MessageTemplate":"{Method} Response (StatusCode {StatusCode}) at {FullPath} took {Duration} ms","Properties":{"Duration":140,"RequestId":"9817639f-fcc6-45c5-9c41-593f707a0649","Type":"Response","Method":"GET","StatusCode":200,"ReasonPhrase":"OK","FullPath":"/"}}

Logs from the same roundtrip will include a RequestId property that is the same for these logs to trace them back using your favorite log server.

Use the logger from inside the WebPart

You can get a reference for a logger with the RequestId attached to it from inside a WebPart:

let webApp = 
  choose [ GET >=> path "/" >=> OK "Home"
           GET >=> path "/index" 
               >=> context (fun ctx ->
                     // get the contextual logger
                     let logger = ctx.Logger() 
                     logger.Information("Read my {RequestId}")
                     OK "Some response") ]

the Logger() method is an extension method to HttpContext.

Ignore log fields

As you can see, there many fields being logged from the request and response. You can configure the logger to ignore some fields:

let serilogConfig = 
  { SerilogConfig.defaults with
      IgnoredRequestFields = 
        |> Field.userAgent
        |> Field.queryString
      IgnoredResponseFields = 
        |> Field.contentType
        |> Field.reasonPhrase }

let webAppWithLogging = SerilogAdapter.Enable(webApp, serilogConfig)

Error Handling

Error handling within the Serilog WebPart is also handled by Serilog and not Suave's internal logger. The error handler is of type: Exception -> HttpContext -> WebPart with the default handler returning a generic error message from the server:

let errorHandler = 
 fun ex httpContext -> 
    OK "Internal Server Error"
    >=> Writers.setStatus HttpCode.HTTP_500

You can override this error handler from the config:

let serilogConfig = 
 { SerilogConfig.defaults with 
    ErrorHandler = 
      fun ex httpContext -> 
        // NancyFx-style apologetic message :D
        OK "Sorry, something went terribly wrong!"
        >=> Writers.setStatus HttpCode.HTTP_500 }

let webAppWithLogging = SerilogAdapter.Enable(webApp, serilogConfig)


Build History


Make sure the following requirements are installed in your system:

> build.cmd // on windows
$ ./  // on unix

Watch Tests

The WatchTests target will use dotnet-watch to watch for changes in your lib or tests and re-run your tests on all TargetFrameworks

./ WatchTests