How can I make Servant to put information regarding the handler that was used to serve a particular request into the log?
I am using the logging method outlined in this post
https://github.com/algas/haskell-servant-cookbook/blob/master/doc/Logger.md
Is there any way Servant can be made to include the details of the Handler used, in the Response structure, so that the middleware can put such details into the log?
The most common approach, which perhaps isn't as well-integrated as it could be, is to use Middleware. That can very easily get you each request (and/or response).
It sounds like you want every handler to be able to log which request they're serving though. One approach is to use the Vault combinator to pass information from the Middleware. This way your handlers could know all the request details and log accordingly. Another is to just write a new combinator that gives you all the request information. Your handlers would get that and could log however they wanted.
I think these solutions would help, but they're definitely not as well-packaged as they could be. It;s probably worth thinking what exactly we want to package, and how. One thing @proger suggested that I really like,and that's related, is having an opentracing combinator (possibly in a different package, to remain vendor-neutral in servant). That's an interesting direction.
If you have thoughts on the previous paragraph, or if the approaches I mentioned aren't clear, let us know!
Quite complex approach: https://github.com/input-output-hk/cardano-sl/blob/develop/lib/src/Pos/Util/Servant.hs#L524
I've done this for one of my projects. Quite ugly but not too complex:
instrumentHandlerValueWithFilter ::
String
-> (Wai.Response -> Maybe Wai.Response) -- ^ Response filter
-> (Wai.Request -> Text) -- ^ The function used to derive the "handler" value in Prometheus
-> Wai.Application -- ^ The app to instrument
-> Wai.Application -- ^ The instrumented app
instrumentHandlerValueWithFilter environment resFilter f app req respond = do
start <- getTime Monotonic
app req $ \res -> do
case resFilter res of
Nothing -> return ()
Just res' -> do
end <- getTime Monotonic
let method = decodeUtf8 (Wai.requestMethod req)
let status = T.pack (show (HTTP.statusCode (Wai.responseStatus res')))
countRoute (f req) method status (display environment)
P.observeSeconds (f req) (Just method) (Just status) start end
respond res