{-# LANGUAGE GeneralizedNewtypeDeriving #-} module Log ( -- * Basic logging logIO, -- * Logging with prepended context MonadLog(..), LogT(..), withLogContext, ) where import Prelude hiding (log) import Control.Applicative (Applicative) import Control.Monad.IO.Class (MonadIO) import Control.Monad.Trans.Class (MonadTrans(..)) import Control.Monad.Trans.Reader (ReaderT(ReaderT)) import Data.Time.LocalTime (getZonedTime) import Data.Time.Format (formatTime) import System.IO (hPutStrLn, stderr) import System.Locale (defaultTimeLocale) -- | Write a message to standard error, prepending the time. logIO :: String -> IO () logIO msg = do time <- getZonedTime let time_str = formatTime defaultTimeLocale "%Y-%m-%d %H:%M:%S" time hPutStrLn stderr $ time_str ++ " " ++ msg class Monad m => MonadLog m where log :: String -> m () instance MonadLog IO where log = logIO newtype LogT m a = LogT (ReaderT (String -> m ()) m a) deriving (Functor, Applicative, Monad, MonadIO) instance MonadTrans LogT where lift = LogT . ReaderT . const instance Monad m => MonadLog (LogT m) where log msg = LogT $ ReaderT $ \f -> f msg withLogContext :: MonadLog m => String -> LogT m a -> m a withLogContext ctx (LogT (ReaderT m)) = m (\msg -> log $ ctx ++ ": " ++ msg)