I'm trying to set up logging in a RIO application; yet, I don't seem to understand the logging interface.
RIO documentation encourages to define a logger and run the application as follows:
withLogFunc logOptions $ \lf -> do
let env = Env -- application specific environment
{ appLogFunc = lf
, appOtherStuff = ...
}
runRIO env $ do
logInfo "Starting app"
myApp ...
That is, withLogFunc
brackets execution of the actual application - why?
I want to hoist my RIO monad into Servant, so this bracketing approach gets in the way. What I'd like to do is to define an environment for use with RIO, say:
data Env = Env
{ config :: ...
, logger :: !LogFunc
}
make the environment an instance of the HasLogFunc
typeclass:
instance HasLogFunc Env where
logFuncL = lens logger (\x y -> x { logger = y })
and then create a value of the Env
type before passing it to runRIO
, instead of passing the entire application execution as a function parameter to withLogFunc
.
That is, I would like something along the lines
let env = Env {
config = ...
logger = mkLogFunc ...
}
in runRIO env $ do
logInfo "Starting app"
...
However, I do not understand how to create a LogFunc
as part of the environment separately. In this way, I could hoist runRIO
into a Servant server (server :: S.ServerT UserApi (RIO Env)
) and then execute the latter. It appears that the RIO logging interface discourages this. Why? What am I missing?
Thanks for any insights!
The creation of a
LogFunc
(other than trivial ones which discard all messages) will require performing effects for the initial setup. Effects like opening the log file, or allocating some other resource. This, in addition to the effects of logging each particular message.That's why
LogFunc
-creating functions will either have bracket-like shapes, likewithLogFunc
does, or else return the log function inside a monad, likenewLogFunc
does.I think the solution is simply to pull the
withLogFunc
outward, so that it also wraps the point in the code at which you create the Servant server. That way, you'll have theLogFunc
at hand when you need it, and you'll be able to construct the environment and "hoist"runRIO
.