suave icon indicating copy to clipboard operation
suave copied to clipboard

Unable to attach a unique `requestId` to Suave log messages

Open adamchester opened this issue 8 years ago • 2 comments

I'm looking at sending Suave logs to Seq.

A key feature is missing. Log messages generated by Suave should have the associated requestId (where appropriate) so they can be easily filtered: image

Using the following sample code, I've managed to associate my custom log events with the context.request.trace.traceId field, however all other related Suave debug events have no such field:

open System
open Suave
open Suave.Operators
open Suave.Filters
open Suave.RequestErrors

[<EntryPoint>]
let main argv =
    let logger = Logary.Facade.Seq.SeqTarget([||], Logging.Verbose, "http://localhost:5341")
                 :> Suave.Logging.Logger
    let myapp : WebPart =
        choose [
            path "/" >=> GET >=> Successful.OK "Hello World!"
            path "/" >=> POST >=> Successful.OK "{\"hello\": \"world\"}"
            NOT_FOUND "What are you trying to do?"
        ]
        >=> logWithLevelStructured Logging.Info logger (fun context ->
            let fields : (string * obj) list = [
                "requestMethod", box context.request.method
                "requestPathAndQuery", box context.request.url.PathAndQuery
                "requestId", box context.request.trace.traceId
                "httpStatusReason", box context.response.status.reason
                "httpStatusCode", box context.response.status.code
                "requestForm", box context.request.form ]
            "HTTP {requestMethod} at \"{requestPathAndQuery}\" responded {httpStatusReason} ({httpStatusCode})",
            fields |> Map.ofList
        )

    let config = { defaultConfig with logger = logger }
    startWebServer config myapp

    0

@haf what do you think? Have you ever tried correlating Suave debug messages to a particular request?

adamchester avatar Feb 12 '17 02:02 adamchester

Yes, I'm on my way towards it, but haven't reached that point yet.

  • https://github.com/SuaveIO/suave/blob/master/src/Suave/Http.fsi#L177
  • http://zipkin.io/pages/data_model.html
  • https://github.com/logary/logary/blob/master/src/targets/Logary.Targets.Zipkin/Targets_Zipkin.fs
  • https://github.com/logary/logary/tree/master/src/targets/Logary.Zipkin
  • https://github.com/logary/logary-js/blob/master/src/index.js#L94

So as you can see I have all the building parts written, just need to combine them. I wouldn't mind help doing that.

haf avatar Feb 12 '17 06:02 haf

module Program

open System
open Suave
open Suave.Operators
open Suave.Filters
open Suave.RequestErrors
open Suave.Logging
open Logary
open Logary.Adapters.Facade
open Logary.Configuration
open Logary.EventsProcessing
open Logary.Targets
open System.Runtime.Remoting.Messaging

[<EntryPoint>]
let main argv =

  let traceId =
    fun next msg ->
      Message.setContext "traceId" (CallContext.LogicalGetData("traceId")) msg
      |> next

  let threadId =
    fun next msg ->
      Message.setContext "ManagedThreadId" (System.Threading.Thread.CurrentThread.ManagedThreadId) msg
      |> next

  let logary = 
    Config.create "suave.example" "localhost"
    |> Config.ilogger (ILogger.LiterateConsole Verbose)
    |> Config.middleware traceId
    |> Config.middleware threadId
    |> Config.target (LiterateConsole.create LiterateConsole.empty "console")
    |> Config.processing (Events.events |> Events.sink ["console"])
    |> Config.build
    |> Hopac.Hopac.run

  LogaryFacadeAdapter.initialise<Suave.Logging.Logger> logary

  let logger = Suave.Logging.Log.create "logger.from.suave"
  let myapp : WebPart =
      (fun ctx -> async {
        CallContext.LogicalSetData("traceId", ctx.request.trace.traceId)
        logger.info (Suave.Logging.Message.eventX "set trace id from beginning")
        return Some ctx
      })
      >=>
      choose [
          path "/" >=> GET >=> fun x -> async {
            logger.info (Suave.Logging.Message.eventX "got some msg")
            do! Async.Sleep 200
            do! logger.infoWithBP (Suave.Logging.Message.eventX "after some working")
            failwith "something wrong"
            return! Successful.OK "Hello World!" x
          }
          path "/" >=> POST >=> Successful.OK "{\"hello\": \"world\"}"
          NOT_FOUND "What are you trying to do?"
      ]

  let eh (ex: exn) msg ctx = async {
    let msg =
      Suave.Logging.Message.eventX msg
      >> Suave.Logging.Message.addExn ex
      |> logger.infoWithBP
    do! msg

    return! Suave.RequestErrors.BAD_REQUEST (ctx.request.trace.traceId.ToString() + "   "+ ex.Message) ctx
  }

  let config = { defaultConfig with logger = logger; errorHandler = eh }
  startWebServer config myapp

  0

image

if you are concern about request logs around application business logic, maybe things above can meet your need.

however all other related Suave debug events have no such field:

some parts are not have their request info there, so they can not have such a field. if we can hook the set traceid part here facade.processRequest _ctx , maybe can get something you want ?

lust4life avatar Dec 22 '17 16:12 lust4life