SimpleLog- Simple, configurable logging

Safe HaskellTrustworthy




SimpleLog is a library for convenient and configurable logging. It uses the usual monad transformer + associated class design: SLogT and MonadSLog.

Example usage:

import System.Log.SLog

main = simpleLog "Example.log" $ do
    logD "Some debugging information"
    logI "This is some other information"
    logW "Something bad is about to happen"
    logE "Something bad happened"

The above sample code when run will produce output similar to this:

2013-10-02 14:17:40 | INFO    | [ThreadId 58] This is some other information
2013-10-02 14:17:40 | WARNING | [ThreadId 58] Something bad is about to happen
2013-10-02 14:17:40 | ERROR   | [ThreadId 58] Something bad happened

Note how the debug line is not displayed. This is because the default configuration (defaultLogConfig) only logs to stdout when the severity is >= INFO. The above code will also append the log lines to the file "Example.log", including the debug line.

The following example shows how one can fine tune SimpleLog as well as how to fork other logging threads.

-- Our log configuration specifies that no ANSI colouring should be used, all log lines
-- should be written to the TChan, and >= INFO severity lines should be written to the
-- stdout synchronously.
logConfig :: TChan LogLine -> LogConfig
logConfig tchan
    = LogConfig { ansiColours = False
                , loggers = [ (anySev, TChanLogger tchan)
                            , ((>= INFO), StdoutLogger Sync)
                            ] }

-- Our custom logging format
logFormat :: Format
logFormat = $(format "%d(%T) (%s) %t: %m")

-- The main thread will fork a child thread, then wait until everything is flushed, then
-- count how many messages have been written in total to the TChan (which will be all
-- messages as our filter passes through everything)
main :: IO ()
main = do
  tchan <- newTChanIO
  (_, fkey) <- runSLogT (logConfig tchan) logFormat "main" $ do
    logS "Main thread started successfully"
    logD "This will not appear on stdout"
    _ <- forkSLog "child" $ do
      logS "I am the child"
      liftIO $ threadDelay 5000000
    logI "Exiting main thread"
  waitFlush fkey
  c <- countTChan tchan
  putStrLn $ show c ++ " messages have been logged in total"

-- Counts the number of elements in the TChan (and pops them all)
countTChan :: TChan a -> IO Int
countTChan tchan = do
  let count = do
        em <- isEmptyTChan tchan
        if em then return 0
        else readTChan tchan >> (1 +) <$> count
  atomically count

The above code when run will produce something like this:

17:35:15 (SUCCESS) main: Main thread started successfully
17:35:15 (SUCCESS) child: I am the child, waiting for 5 seconds...
17:35:15 (INFO   ) main: Exiting main thread
5 messages have been logged in total



data SLogT m a Source

The SLogT monad transformer is simply a ResourceT with an environment

type SLog = SLogT IO Source

This is a simple monad for the bottom of one's monad stack.

Running SLogT

runSLogT :: (MonadResource m, MonadBaseControl IO m) => LogConfig -> Format -> String -> SLogT m a -> m (a, FlushKey) Source

runSLogT runs an SLogT given a LogConfig, Format and the current thread's name. It returns a FlushKey besides the usual return value.

simpleLog :: (MonadResource m, MonadBaseControl IO m) => FilePath -> SLogT m a -> m a Source

simpleLog uses the default configuration with the specified log file name. It also waits using waitFlush until all resources have been released.


data FlushKey Source

A FlushKey is returned when an SLogT is run. You may wait on it with waitFlush.

waitFlush :: FlushKey -> IO () Source

waitFlush will only return when all resources have been released and all streams have been flushed. Note that this includes resources allocated by the user using the exposed MonadResource instance.

All threads internally accounted for are signaled to exit (they will first finish processing of all remaining jobs) when the SLogT is run, however it is the user's responsibility to shut down threads forked with forkSLog or fork before waitFlush can return.


class MonadIO m => MonadSLog m where Source

The class of monads that can perform logging

Minimal complete definition



log :: Severity -> Text -> m () Source

log logs the specified Text with the specified Severity


Convenience log functions

logD :: MonadSLog m => String -> m () Source

Log a DEBUG message

logI :: MonadSLog m => String -> m () Source

Log an INFO message

logS :: MonadSLog m => String -> m () Source

Log a SUCCESS message

logW :: MonadSLog m => String -> m () Source

Log a WARNING message

logE :: MonadSLog m => String -> m () Source

Log an ERROR message


data Logger Source

The Logger type specifies the types of sinks we can log to.


FileLogger Sync FilePath

FileLogger specifies a file to be logged in. Note that symbolic links will be resolved using canonicalizePath when deciding whether two FileLoggers point to the same file.

StdoutLogger Sync

StdoutLogger logs to the stdout

StderrLogger Sync

StderrLogger logs to the stderr

TChanLogger (TChan LogLine)

TChanLogger logs to a specified TChan. Note that LogLines are written instead of the final formatted text. If you wish to use the final text use formatLine.


data Sync Source

Sync is a type to specify whether a logger should log synchronously or asynchronously. Syncronous logging means that the logging thread will block until the message has been written and flushed to the sink. Asynchronous logging means that the logging thread will write to a work queue and move on. The work queue will be read by a dedicated thread that is forked for each sink.




data LogLine Source

LogLine is a log message together with the severity, time of logging and the logging thread's name.


data Severity Source

The type of severities with increasing importance



type Filter = Severity -> Bool Source

Filter is the type of logging filters. Filters may only depend on the Severity.

anySev :: Filter Source

anySev allows all lines to be logged.


data LogConfig Source

LogConfig is the configuration of SLogT




ansiColours :: Bool

Specifies whether ANSI colouring should be used when logging to stdout/stderr

loggers :: [(Filter, Logger)]

The list of loggers together with the associated filters

defaultLogConfig :: FilePath -> LogConfig Source

defaultLogConfig is the default log configuration. It writes all non-DEBUG messages to the stdout synchronously and all messages to a specified file asynchronously.


defaultLogFormat :: Format Source

The default log format, which currently is $(format "%d(%F %T) | %s | [%t] %m"). See System.Log.SLog.Format for more details on format strings.

Utility functions

forkSLog :: (MonadBaseControl IO m, MonadIO m) => String -> SLogT m () -> SLogT m ThreadId Source

forkSLog forks an SLogT thread with the specified thread name.

formatLine :: Bool -> Format -> LogLine -> Text Source

formatLine formats the given LogLine using the specified Format. The Boolean determines whether formatLine should insert ANSI colour codes or not.

unsafeUnliftSLogT :: forall m b. (Monad m, MonadBaseControl IO m) => ((forall a. SLogT m a -> m a) -> SLogT m b) -> SLogT m b Source

unsafeUnliftSLog gives you an unsafe unlift of an SLogT by assuming that any unlifted computation will finish earlier than the runSLogT of the calling thread. It is unsafe because if the unlifted computation doesn't finish earlier then it may access deallocated resources. This is useful when a library is implicitly forking but we still need to log in the forked threads, and we know that the child threads will finish earlier than the parent. An example is Network.WebSockets