[Haskell-cafe] attempt creating alternative logging lib which is actually much slower (?)

Marc Weber marco-oweber at gmx.de
Thu Feb 12 08:47:01 EST 2009

> > without removing all all setLevel calls to subloggers?
> > Is this desirable?
> I don't understand the problem.  If you told hslogger that you didn't
> want to hear about stuff about "A", why do you not like that it is
> following your instructions?

Because taht >>don't want to hear abuot "A"<< could have been set
without my knowledge. When trouble shooting a problem it could be handy
to just get all messages. But when such a use case arrives I can still
patch hslogger.

mlog (attempt to create a minimal alternative)

I've tried writing another minimal logging system.
The idea was driven by adding the possibility to add a handler logging
everything not matter what levels are set to different loggers or

The design is simple: keep a list of log handlers and a list of filters.
you can add a filter telling that a log message of "A.B" should not be
logged. The actual handler function then looks like this

  log shouldbeLogged logmessage loggername prio = ....

So you can still ignore shouldbeLogged easily.
However I couldn't even come close to the speed of hslogger even when
caching the list of handlers which are supposed to log the message.

[some code snippets see end of mail]

without any attached handlers:

  hslogger*[1] : 4ms
  mlog[2]: 12ms

with one default stderr logger (./test 2> /dev/null)

  hslogger*[1] : 109ms 
  mlog[2]:   150ms 

[1]: my modified version of hslogger (git://mawercer.de/hslogger)
[2]: (git://mawercer.de/mlog)

I've tried doing some investigation figuring out why my lib is that much
slower but I failed. I noticed that -O2 had an impact on how often the
list of generated test cases is run. But that has been all. I don't even
use existential types!

So I'll shut up and keep using hslogger. Thanks to you John Goerzen
for your support.

I've learned that I'm very bad at troubleshooting performance.
I really thought I could make mlog faster than hslogger*.
Using profiling (-P) didn't reveal the source wasting CPU cycles to me.

Marc Weber

[ some code snippets of mlog]

the global logger data looks like this:

  data GlobalLoggerData = GlobalLoggerData {

    handlers :: M.Map Int LogHandler 
      -- assign a key so that this logger can be removed easily again 

    ,filters :: M.Map Int GlobalFilter -- allow to add global filters 

    -- cache information about which logger accepts what logging data
    -- String = Priority : loggername
    , cached :: M.Map String (Bool, [ LogMessageAction ])


  {-# NOINLINE globalLoggerData #-}
  globalLoggerData :: MVar GlobalLoggerData
  globalLoggerData = unsafePerformIO $ newMVar $ GlobalLoggerData M.empty M.empty M.empty

  -- add default handler: 
  addHandler $ LogHandler {
    accept = \ln p -> True -- which logging events does this log handler accept? 
    ,logAction = \ln p msg doLog -> hPutStrLn stderr msg 
    ,close = return ()

More information about the Haskell-Cafe mailing list