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.
Permalink
Failed to load latest commit information.
.github
.paket
.vscode
sample
src/Suave.SerilogExtensions
tests/Suave.SerilogExtensions.Tests
tools
.editorconfig
.gitignore
.travis.yml
LICENSE.md
README.md
RELEASE_NOTES.md
Suave.SerilogExtensions.sln
appveyor.yml
build.cmd
build.fsx
build.sh
paket.dependencies
paket.lock

README.md

Suave.SerilogExtensions Build Status Nuget

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

Install

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

Usage

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 <- 
  LoggerConfiguration()
    .Destructure.FSharpTypes()
    .WriteTo.Console() // from Serilog.Sinks.Console
    .CreateLogger() 

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 127.0.0.1:8080
[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 <- 
  LoggerConfiguration()
    .Destructure.FSharpTypes()
    .WriteTo.Console() // from Serilog.Sinks.Console
    .WriteTo.Console(JsonFormatter())
    .CreateLogger() 

Now there logs become:

[20:39:48 INF] Smooth! Suave listener started in 146.37 with binding 127.0.0.1:8080
[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":"127.0.0.1","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 = 
        Ignore.fromRequest
        |> Field.host
        |> Field.userAgent
        |> Field.queryString
      IgnoredResponseFields = 
        Ignore.fromResponse
        |> 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)

Builds

Build History

Building

Make sure the following requirements are installed in your system:

> build.cmd // on windows
$ ./build.sh  // 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

./build.sh WatchTests