commercialhaskell / rio

A standard library for Haskell
Other
838 stars 54 forks source link

missing a way to modify a logfunc to provide context #214

Open robx opened 4 years ago

robx commented 4 years ago

I'm having trouble finding a way provide context for log messages while using rio's logging infrastructure, and without creating new log functions all over the place. Below's my understanding of the situation; chances are I'm missing a nice way to achieve this now.

Concretely, for a web request handler, I'd like to extract a client IP address from a header, and prepend that to every logged message.

If LogFunc weren't opaque, I could replace the unLogFunc field with one that preprocesses the str argument. Another approach might be to replace or modify the logFormat option, but again that's currently not exposed (and the original value is captured by the log function itself currently).

It seems to me to be better to not create new log functions for this, since their actions might need to be synchronized.

How I'm imagining using this is by replacing the log function in my environment with a modified version, and using the modified environement via local.

snoyberg commented 4 years ago

You may want to consider using glog for this kind of case, it makes it possible to use arbitrary data structures to represent the log messages, which would let you include additional metadata. https://www.stackage.org/haddock/nightly-2020-03-26/rio-0.1.14.1/RIO.html#v:glog

robx commented 4 years ago

I'll give it a shot, thanks! (And see if can break this down to an example that might be added to the documentation.)

My interim solution is below, but it's a bit unsatisfying in that it sidesteps the RIO logging API a bit.

info :: Utf8Builder -> RIO App ()
info msg = do
  logContext <- view $ to appLogContext
  logInfo $ mconcat (map (\c -> c <> ": ") logContext) <> msg
robx commented 4 years ago

Hmm, no, I don't think I can get the GLog facilities to help here. The thing is, I want to augment the messages with some information from the environment, e.g. the appLogContext as above, without having to do that manually for every message I log. I don't see how wrapping around glog is any better there than wrapping logGeneric. No matter what, it looks like I'll have to write a separate myLogDebug, myLogInfo etc. for each log level that I want to use.

danstn commented 3 years ago

@robx I agree that if LogFunc's lfOptions was exposed - it would be very handy to modify it at runtime.

Would be great to be able to use setLogFormat at runtime (trying to achieve a similar thing - need to tag each WAI request with a unique hash to aggregate all logs of a specific operation).

@snoyberg any thoughts on how this could be achieved?

snoyberg commented 3 years ago

Nothing in particular, proposals on concrete changes are welcome.