module Hakyll.Core.Logger
( Logger
, makeLogger
, flushLogger
, section
, timed
, report
, thrown
) where
import Control.Monad (forever)
import Control.Monad.Trans (MonadIO, liftIO)
import Control.Applicative (pure, (<$>), (<*>))
import Control.Concurrent (forkIO)
import Control.Concurrent.Chan (Chan, newChan, readChan, writeChan)
import Control.Concurrent.MVar (MVar, newEmptyMVar, takeMVar, putMVar)
import Text.Printf (printf)
import Data.Time (getCurrentTime, diffUTCTime)
data Logger = Logger
{ loggerChan :: Chan (Maybe String)
, loggerSync :: MVar ()
, loggerSink :: String -> IO ()
}
makeLogger :: (String -> IO ()) -> IO Logger
makeLogger sink = do
logger <- Logger <$> newChan <*> newEmptyMVar <*> pure sink
_ <- forkIO $ loggerThread logger
return logger
where
loggerThread logger = forever $ do
msg <- readChan $ loggerChan logger
case msg of
Nothing -> putMVar (loggerSync logger) ()
Just m -> loggerSink logger m
flushLogger :: Logger -> IO ()
flushLogger logger = do
writeChan (loggerChan logger) Nothing
() <- takeMVar $ loggerSync logger
return ()
message :: Logger -> String -> IO ()
message logger = writeChan (loggerChan logger) . Just
section :: MonadIO m
=> Logger
-> String
-> m ()
section logger = liftIO . message logger
timed :: MonadIO m
=> Logger
-> String
-> m a
-> m a
timed logger msg action = do
start <- liftIO getCurrentTime
!result <- action
stop <- liftIO getCurrentTime
let diff = fromEnum $ diffUTCTime stop start
ms = diff `div` 10 ^ (9 :: Int)
formatted = printf " [%4dms] %s" ms msg
liftIO $ message logger formatted
return result
report :: MonadIO m
=> Logger
-> String
-> m ()
report logger msg = liftIO $ message logger $ " [ ] " ++ msg
thrown :: MonadIO m
=> Logger
-> String
-> m ()
thrown logger msg = liftIO $ message logger $ " [ ERROR] " ++ msg