Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use log-warper with Servant?

I have an application built on top of Servant, and now I want to add logging to the application. I skimmed through Haskell log packages, and I assume this one provides what I need: https://github.com/serokell/log-warper/blob/master/log-warper/examples/HowTo.md

One of the 'design patterns' often used for building apps with Servant is to use Reader monad, so I use this approach for the app: I have AppEnv which contains AppConfig. Usually, I could add something like a 'logger' entity to the AppEnv and so use it in handlers. Although, log-warper doesn't provide 'a logger', but it uses different approach instead (seems to be another monad, I assume; please, see the example on the link above). And so I can't figure out how to use this logger with Servant.

Here is my Servant-based app (using recent version of Servant, basing on examples from the doc: http://haskell-servant.readthedocs.io/en/stable/tutorial/Server.html#welcome-hoistserver):

data AppEnv = AppEnv { config :: Config }
type MyHandler = ReaderT AppEnv (ExceptT ServantErr IO)

startApp :: AppEnv -> IO ()
startApp env = do
  run 16384 (app env)

app :: AppEnv -> Application
app env = serve readerAPI (readerServer env)

readerAPI :: Proxy ReaderAPI
readerAPI = Proxy

readerToHandler :: AppEnv -> Reader AppEnv a -> Handler a
readerToHandler env r = return (runReader r env)

readerServer :: AppEnv -> Server ReaderAPI
readerServer env = hoistServer readerAPI (readerToHandler env) readerServerT

b :: Reader AppEnv Bool
b = do
  c <- config <$> ask
  let
    s = getServerConfig c
    p = getServerPort s
  return (p == 1)

getServerConfig :: Config -> ServerConfig
getServerConfig (Config s _) = s

getServerPort :: ServerConfig -> Int
getServerPort (ServerConfig _ p) = p

readerServerT :: ServerT ReaderAPI (Reader AppEnv)
readerServerT = a :<|> b where
    a :: Reader AppEnv Int
    a = return 1797

And here is the main function:

main :: IO ()
main = do
  config <- loadYamlSettings ["etc/config.yaml"] [] useEnv
  print (config :: Config)
  let
    env = AppEnv config
  startApp env

Now, how can I add log-warper to the application so I could initialize the logger (with launchFromFile I assume), and then use logging (logInfo, logError, etc.) in the app (in particular, in handlers, but possibly in other functions as well)?

Thanks

like image 716
fycth Avatar asked Nov 17 '22 07:11

fycth


1 Answers

General logging

If you want a generic logging tool with some sophisticated options katip looks like a good choice. There is even a small discussion about how to use it with servant. You just need to add a couple of parameters for katip to your Config type, initialize them, then you can log in your handlers.

Request logging

servant-server is built on top of wai and warp so you can reuse a lot of there tools. If you are just interested in logging data about requests to servant, you can use wai-logger without changing any of your types.

startApp would look something like this.

startApp :: AppEnv -> IO ()
startApp env = do
  withStdoutLogger $ \logger -> 
    runSettings (setPort 16384 $ setLogger logger $ defaultSettings) $ app env 
like image 59
MCH Avatar answered Dec 08 '22 00:12

MCH