6

I'm writing a simple web server in Haskell, and putting in a bit of logging. I've got some calls to a logging function in a chain of IO >>=. It all feels a bit manual. Is there a better/more "Haskelish" way?

log :: (Show a) => String -> a -> IO a
log label val = getCurrentTime >>= \time ->
                putStrLn ("[" ++ show time ++ "] [" ++ label ++ "] " ++ (take maxLogLength $ show val)) >>
                return val 

handle :: Socket -> IO ()
handle conn = recv conn incomingBufferSize >>=
              log "request" >>=
              log "path" . extractPath . unpack >>=
              response >>= log "response" >>=
              send conn >>
              close conn
2
  • I have no experience with it, but what about hackage.haskell.org/package/logging-effect-1.1.1/docs/…?
    – Giorgio
    Mar 12, 2017 at 12:28
  • I'm much less experienced in Haskell than many of our regulars here, but just wanted to comment on two things. First, you're tying yourself down to a specific logging implementation, is writing to output. If your needs ever change (writing to files, ignoring logging during testing, etc) you'll have trouble. Use a monad transformer stack with an instance of the Writer monad in it to receive your logging data, not IO. And if you want to make logging less verbose, consider partially applying your logging function to the functions that produce the data being logged.
    – Jules
    May 12, 2017 at 12:04

3 Answers 3

3

Logging is a common use-case given during the presentation of so-called Free monads, Freer monads, and/or Extensible Effects.

In any case, the basic idea is simple -- rather than having your program perform actions directly, your program produces a data-structure that abstractly describes the actions to be performed. The actual execution of these actions is deferred to an interpreter that interprets the data-structure.

There are at least two ways this can be applied to logging. The first is by specifying some set of explicit logging operations. This isn't much different to what you currently have, through, except the implementation of the logging operations can be changed by providing a different interpreter. For example, you could change where the logging goes or even eliminate logging all together (i.e., implement logging as a no-op).

Another way to apply this is to add logging to the interpretation of certain operations. If done correctly, the logging and the "actual" interpretation of the operation are completely orthogonal. This is analogous to Aspect-Oriented Programming, which allows additional code to be "mixed-in" to the main code.

1

Aspect Oriented Programming is the usual approach to this. In java you 'intercept' methods you wish to log. To the developer it seems that nothing is happening, but every time that method is called it is logged automatically.

I'm not sure if the language you're using supports AOP, but I'm sure there may be some way to implement a similar system.

3
  • 1
    AOP really doesn't apply to functional languages. The way they are constructed kind of obviates the need. I've only seen AOP applied to some OOP languages (like Java). There's a lot of people (me included) that don't like surprise activity that they can't see in the source code. May 11, 2017 at 12:18
  • 2
    It's a shame. It's a great solution.
    – Richard
    May 11, 2017 at 12:20
  • AOP is great for logging.
    – Laiv
    May 11, 2017 at 18:24
0

In several languages you can implement logging functions as decorators. This might be worth investigating, but in the process I stumbled across the hslogger package (documentation).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.