Safe Haskell | Trustworthy |
---|---|
Language | Haskell98 |
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 logW "CHILD SHUTTING DOWN" 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 17:35:20 (WARNING) child: CHILD SHUTTING DOWN 5 messages have been logged in total
- data SLogT m a
- type SLog = SLogT IO
- runSLogT :: (MonadResource m, MonadBaseControl IO m) => LogConfig -> Format -> String -> SLogT m a -> m (a, FlushKey)
- simpleLog :: (MonadResource m, MonadBaseControl IO m) => FilePath -> SLogT m a -> m a
- data FlushKey
- waitFlush :: FlushKey -> IO ()
- class MonadIO m => MonadSLog m where
- logD :: MonadSLog m => String -> m ()
- logI :: MonadSLog m => String -> m ()
- logS :: MonadSLog m => String -> m ()
- logW :: MonadSLog m => String -> m ()
- logE :: MonadSLog m => String -> m ()
- data Logger
- data Sync
- data LogLine = LogLine {}
- data Severity
- type Filter = Severity -> Bool
- anySev :: Filter
- data LogConfig = LogConfig {
- ansiColours :: Bool
- loggers :: [(Filter, Logger)]
- defaultLogConfig :: FilePath -> LogConfig
- module System.Log.SLog.Format
- defaultLogFormat :: Format
- forkSLog :: (MonadBaseControl IO m, MonadIO m) => String -> SLogT m () -> SLogT m ThreadId
- formatLine :: Bool -> Format -> LogLine -> Text
- unsafeUnliftSLogT :: forall m b. (Monad m, MonadBaseControl IO m) => ((forall a. SLogT m a -> m a) -> SLogT m b) -> SLogT m b
SLogT
The SLogT monad transformer is simply a ResourceT
with an environment
MonadTransControl SLogT | |
MonadTrans SLogT | |
MonadBase IO m => MonadBase IO (SLogT m) | |
MonadBaseControl IO m => MonadBaseControl IO (SLogT m) | |
Monad m => Monad (SLogT m) | |
Functor m => Functor (SLogT m) | |
Applicative m => Applicative (SLogT m) | |
MonadThrow m => MonadThrow (SLogT m) | |
MonadIO m => MonadIO (SLogT m) | |
(MonadBase IO m, MonadThrow m, MonadIO m) => MonadResource (SLogT m) | |
MonadIO m => MonadSLog (SLogT m) | |
(MonadBaseControl IO m, MonadIO m) => Forkable (SLogT m) (SLogT m) | |
type StT SLogT a = StT ResourceT a | |
type StM (SLogT m) a = ComposeSt SLogT m a |
Running SLogT
runSLogT :: (MonadResource m, MonadBaseControl IO m) => LogConfig -> Format -> String -> SLogT m a -> m (a, FlushKey) Source
simpleLog :: (MonadResource m, MonadBaseControl IO m) => FilePath -> SLogT m a -> m a Source
FlushKey
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.
MonadSLog
Convenience log functions
Loggers
The Logger
type specifies the types of sinks we can log to.
FileLogger Sync FilePath |
|
StdoutLogger Sync |
|
StderrLogger Sync |
|
TChanLogger (TChan LogLine) |
|
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.
LogLine
is a log message together with the severity, time of logging and the logging thread's name.
LogLine | |
|
Filters
The type of severities with increasing importance
Configuration
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.
Format
module System.Log.SLog.Format
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
formatLine :: Bool -> Format -> LogLine -> Text Source
formatLine
formats the given LogLine
using the specified Format
. The Bool
ean 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