Archive for category Haskell

Logging to Growl from Haskell running on Lion

I am currently developing Haskell apps on a MacAir with Lion and wanted to enjoy the luxury of growling log messages.

This is a short write up on how I got this to work.

First thing needed is GrowlNotify for Lion, and of course Growl for Lion itself.

Next step is getting hslogger which can be installed via:

cabal install hslogger

hslogger actually includes a GrowlLogHandler, but I couldn’t get it to work. My guess is, that it only works with older versions of Growl.

This assumption is confirmed when looking at the source, It basically tries to set up a socket connection to the Growl app and has a port number hard coded, that is different from the one that the current version of Growl suggests.

Fortunately we  we have the growlnotify tool and don’t have to figure out how to talk to the Growl app. Instead we call growlnotify with a given message and it will take care of all that grunt work for us.

Here is the LogHandler that accomplishes the above:

module System.Log.Handler.GrowlNotifyHandler (growlNotifyHandler) where

import System.Log (Priority)
import System.Log.Handler (LogHandler(..))
import System.Log.Formatter (nullFormatter, LogFormatter(..))
import System.Cmd (rawSystem)

data GrowlNotifyHandler = GrowlNotifyHandler
    { priority :: Priority
    , formatter :: LogFormatter GrowlNotifyHandler
    , appName :: String

instance LogHandler GrowlNotifyHandler where
    setLevel gnh p = gnh { priority = p }

    getLevel = priority

    setFormatter gh f = gh { formatter = f }
    getFormatter = formatter

    emit gnh (prio, msg) _ = do
        rawSystem "growlnotify" ["-m", (show prio) ++ "\n" ++ msg]
        return ()
    close gnh     = return ()

growlNotifyHandler :: String -> Priority -> GrowlNotifyHandler
growlNotifyHandler service priority = GrowlNotifyHandler priority nullFormatter service

Make sure to place this inside “System/Log/Handler” relative to the root of your app.

Here is an example that uses this log handler in order to pop up a log message in growl:

import System.Log.Logger
import System.Log.Handler.GrowlNotifyHandler

main = do
    updateGlobalLogger "Main.Logger" (setLevel DEBUG)
    let hdlr = growlNotifyHandler "Main.Logger" DEBUG
    updateGlobalLogger rootLoggerName (addHandler hdlr)

    debugM "Main.Logger" "This shows in a growl message with Terminal Icon"

Assuming all goes well, you should see this when running it:


Leave a comment

%d bloggers like this: