-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Fast & extensible logging framework -- -- Logging is a fast and extensible Haskell logging framework. -- -- Logging allows you to log any kind of messages in both IO as well as -- pure code, depending on the informations you want to log. -- -- The framework bases on the idea of logger transformer stack defining -- the way it works. You can build your own stack to highly tailor the -- behaviour to your needs, starting with such simple things, like -- logging messages to a list, ending on logging compile-time, -- priority-filtered messages from different threads and gathering them -- in other logger thread. -- -- For detailed documentation and examples look at the ''System.Log'' -- module. @package logger @version 0.1.0.0 module System.Log.Log newtype Log a Log :: a -> Log a fromLog :: Log a -> a class (Monad m, Applicative m) => MonadLogger m appendLog :: MonadLogger m => Log (LogFormat m) -> m () instance Show a => Show (Log a) instance Functor Log module System.Log.Data log :: (Show pri, Enum pri, MonadRecord (Data Lvl, (Data Msg, r)) m) => RecordBuilder r -> pri -> String -> m () newtype RecordBuilder a RecordBuilder :: a -> RecordBuilder a fromRecordBuilder :: RecordBuilder a -> a empty :: RecordBuilder () class MonadRecord d m where appendRecord d = do { l <- buildLog d; appendLog l } appendRecord :: MonadRecord d m => RecordBuilder d -> m () appData :: a ~ DataOf base => base -> a -> RecordBuilder as -> RecordBuilder (Data base, as) data Data base Data :: base -> DataOf base -> Data base recBase :: Data base -> base recData :: Data base -> DataOf base class DataGetter base m getData :: DataGetter base m => m (Data base) class LogBuilderProto a m b buildLogProto :: LogBuilderProto a m b => RecordBuilder a -> m (Log b) type LogBuilder a m = LogBuilderProto a m (LogFormat m) buildLog :: (Monad m, Applicative m, LogBuilder a m) => RecordBuilder a -> m (Log (LogFormat m)) class Lookup base s lookup :: Lookup base s => base -> s -> Data base readData :: Lookup a l => a -> l -> DataOf a class LookupDataSet base s lookupDataSet :: LookupDataSet base s => base -> s -> Data base data Time Time :: Time data Msg Msg :: Msg data Lvl Lvl :: Lvl data LevelData LevelData :: Int -> String -> LevelData mkLevel :: (Show a, Enum a) => a -> LevelData type Pos = (Int, Int) data LocData LocData :: String -> String -> String -> Pos -> Pos -> LocData _filename :: LocData -> String _package :: LocData -> String _module :: LocData -> String _start :: LocData -> Pos _end :: LocData -> Pos mkLoc :: (String, String, String, Pos, Pos) -> LocData data Loc Loc :: Loc instance [overlap ok] (Show (DataOf base), Show base) => Show (Data base) instance [overlap ok] Show a => Show (RecordBuilder a) instance [overlap ok] Functor RecordBuilder instance [overlap ok] Show Time instance [overlap ok] Show Msg instance [overlap ok] Show Lvl instance [overlap ok] Show LevelData instance [overlap ok] Ord LevelData instance [overlap ok] Eq LevelData instance [overlap ok] Show LocData instance [overlap ok] Show Loc instance [overlap ok] MonadIO m => DataGetter Time m instance [overlap ok] LookupDataSet base as => LookupDataSet base (Data b, as) instance [overlap ok] LookupDataSet base (Data base, as) instance [overlap ok] LookupDataSet base r => Lookup base (RecordBuilder r) instance [overlap ok] LookupDataSet base l => Lookup base (Log l) instance [overlap ok] (Functor m, Applicative m, DataGetter y m, LogBuilderProto () m ys) => LogBuilderProto () m (Data y, ys) instance [overlap ok] Monad m => LogBuilderProto a m () instance [overlap ok] (LogBuilderProto (Data x, xs) m ys, LogBuilderProto xs m (Data y, ()), Monad m) => LogBuilderProto (Data x, xs) m (Data y, ys) instance [overlap ok] (LogBuilderProto xs m ys, Functor m) => LogBuilderProto (Data x, xs) m (Data x, ys) module System.Log.Format newtype Formatter a Formatter :: (Log a -> Doc) -> Formatter a runFormatter :: Formatter a -> Log a -> Doc mapFormatter :: ((Log t -> Doc) -> Log a -> Doc) -> Formatter t -> Formatter a class FormatterBuilder a b buildFormatter :: FormatterBuilder a b => a -> Formatter b (<:>) :: (FormatterBuilder a c, FormatterBuilder b c) => a -> b -> Formatter c concatFormatters :: Formatter a -> Formatter a -> Formatter a class PPrint a pprint :: PPrint a => a -> Doc defaultFormatter :: (LookupDataSet Msg c, LookupDataSet Lvl c) => Formatter c defaultTimeFormatter :: (LookupDataSet Time c, LookupDataSet Msg c, LookupDataSet Lvl c) => Formatter c defaultFormatterTH :: (LookupDataSet Msg c, LookupDataSet Lvl c, LookupDataSet Loc c) => Formatter c colorLvlFormatter :: LookupDataSet Lvl a => Formatter a -> Formatter a lvlColor :: (Ord a, Num a) => a -> Doc -> Doc instance [overlap ok] Pretty UTCTime instance [overlap ok] Pretty LocData instance [overlap ok] Pretty LevelData instance [overlap ok] Pretty a => PPrint a instance [overlap ok] PPrint String instance [overlap ok] FormatterBuilder Doc a instance [overlap ok] FormatterBuilder String a instance [overlap ok] a ~ b => FormatterBuilder (Formatter a) b instance [overlap ok] (PPrint (DataOf seg), Lookup seg (Log a)) => FormatterBuilder seg a instance [overlap ok] Show (Formatter a) module System.Log.Filter newtype Filter a Filter :: (Log a -> Bool) -> Filter a runFilter :: Filter a -> Log a -> Bool lvlFilter' :: (LookupDataSet Lvl l, Enum a) => a -> Log l -> Bool lvlFilter :: (LookupDataSet Lvl a, Enum a1) => a1 -> Filter a module System.Log.Logger.Handler class MonadLoggerHandler n m | m -> n where addHandler = lift . addHandler addHandler :: MonadLoggerHandler n m => Handler n (LogFormat m) -> m () data Handler m l Handler :: String -> (Doc -> Log l -> m ()) -> [Handler m l] -> Maybe (Formatter l) -> [Filter l] -> Handler m l _name :: Handler m l -> String _action :: Handler m l -> Doc -> Log l -> m () _children :: Handler m l -> [Handler m l] _formatter :: Handler m l -> Maybe (Formatter l) _filters :: Handler m l -> [Filter l] name :: Lens' (Handler m_aesG l_aesH) String formatter :: Lens' (Handler m_aesG l_aesH) (Maybe (Formatter l_aesH)) filters :: Lens' (Handler m_aesG l_aesH) [Filter l_aesH] children :: Lens' (Handler m_aesG l_aesH) [Handler m_aesG l_aesH] action :: Lens' (Handler m_aesG l_aesH) (Doc -> Log l_aesH -> m_aesG ()) type Handler' m = Handler m (LogFormat m) mkHandler :: String -> (Doc -> Log l -> m ()) -> Maybe (Formatter l) -> Handler m l addChildHandler :: Handler m l -> Handler m l -> Handler m l addFilter :: Filter l -> Handler m l -> Handler m l setFormatter :: Formatter l -> Handler m l -> Handler m l topHandler :: Monad m => Formatter l -> Handler m l printHandler :: MonadIO m => Maybe (Formatter l) -> Handler m l newtype HandlerLogger m a HandlerLogger :: StateT (Handler' (HandlerLogger m)) m a -> HandlerLogger m a fromHandlerLogger :: HandlerLogger m a -> StateT (Handler' (HandlerLogger m)) m a runHandlerLoggerT :: (Functor m, Monad m) => Formatter (LogFormat m) -> HandlerLogger m b -> m b runHandler :: (Applicative m, Monad m) => Doc -> Log (LogFormat m) -> Handler' m -> m () getTopHandler :: Monad m => HandlerLogger m (Handler (HandlerLogger m) (LogFormat m)) putTopHandler :: Monad m => Handler (HandlerLogger m) (LogFormat m) -> HandlerLogger m () instance Monad m => Monad (HandlerLogger m) instance MonadIO m => MonadIO (HandlerLogger m) instance (Monad m, Functor m) => Applicative (HandlerLogger m) instance Functor m => Functor (HandlerLogger m) instance (Functor m, MonadLogger m, l ~ LogFormat m, LogBuilder d (HandlerLogger m), LookupDataSet Msg l, LookupDataSet Lvl l) => MonadRecord d (HandlerLogger m) instance (Monad m, Functor m) => MonadLoggerHandler (HandlerLogger m) (HandlerLogger m) instance (MonadLogger m, Functor m, l ~ LogFormat m, LookupDataSet Msg l, LookupDataSet Lvl l) => MonadLogger (HandlerLogger m) instance MonadTrans HandlerLogger instance Show (Handler m l) module System.Log.Logger.Priority class MonadPriorityLogger m getPriority :: MonadPriorityLogger m => m Int setPriority :: (MonadPriorityLogger m, Enum a) => a -> m () newtype PriorityLoggerT m a PriorityLoggerT :: StateT Int m a -> PriorityLoggerT m a fromPriorityLoggerT :: PriorityLoggerT m a -> StateT Int m a runPriorityLoggerT :: (Functor f, Enum a) => a -> PriorityLoggerT f b -> f b instance Monad m => Monad (PriorityLoggerT m) instance MonadIO m => MonadIO (PriorityLoggerT m) instance (Monad m, Functor m) => Applicative (PriorityLoggerT m) instance Functor m => Functor (PriorityLoggerT m) instance MonadTrans PriorityLoggerT instance (Monad m, MonadLoggerHandler h m) => MonadLoggerHandler h (PriorityLoggerT m) instance (MonadLogger m, MonadRecord d m, LookupDataSet Lvl d) => MonadRecord d (PriorityLoggerT m) instance Monad m => MonadPriorityLogger (PriorityLoggerT m) module System.Log.Logger.Drop newtype DropLoggerT m a DropLoggerT :: m a -> DropLoggerT m a runDropLoggerT :: DropLoggerT m a -> m a instance Monad m => Monad (DropLoggerT m) instance MonadIO m => MonadIO (DropLoggerT m) instance Applicative m => Applicative (DropLoggerT m) instance Functor m => Functor (DropLoggerT m) instance Monad m => MonadPriorityLogger (DropLoggerT m) instance (Monad m, MonadLoggerHandler h m) => MonadLoggerHandler h (DropLoggerT m) instance Monad m => MonadRecord d (DropLoggerT m) instance (Monad m, Applicative m) => MonadLogger (DropLoggerT m) instance MonadTrans DropLoggerT module System.Log.Logger.Writer type Logs m = Seq (Log (LogFormat m)) newtype WriterLogger m a WriterLogger :: StateT (Logs m) m a -> WriterLogger m a fromWriterLogger :: WriterLogger m a -> StateT (Logs m) m a runWriterLoggerT :: WriterLogger m a -> m (a, Logs m) class MonadWriterLogger m getLogs :: MonadWriterLogger m => m (Logs m) putLogs :: MonadWriterLogger m => Logs m -> m () withLogs :: (MonadWriterLogger m, Monad m) => (Logs m -> Logs m) -> m () instance Monad m => Monad (WriterLogger m) instance MonadIO m => MonadIO (WriterLogger m) instance (Monad m, Functor m) => Applicative (WriterLogger m) instance Functor m => Functor (WriterLogger m) instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (WriterLogger m) instance (Functor m, Monad m, MonadLogger m) => MonadLogger (WriterLogger m) instance (Monad m, Functor m, LogBuilderProto d (WriterLogger m) (LogFormat m), MonadLogger m) => MonadRecord d (WriterLogger m) instance Monad m => MonadWriterLogger (WriterLogger m) instance MonadTrans WriterLogger module System.Log.Level data Level -- | Debug Logs Debug :: Level -- | Information Info :: Level -- | Normal runtime conditions Notice :: Level -- | General Warnings Warning :: Level -- | General Errors Error :: Level -- | Severe situations Critical :: Level -- | Take immediate action Alert :: Level -- | System is unusable Panic :: Level instance Eq Level instance Ord Level instance Show Level instance Read Level instance Enum Level module System.Log.Tuples class MapRTuple2 f tup tup' | f tup -> tup' mapRTuple :: MapRTuple2 f tup tup' => f -> tup -> tup' instance MapRTuple2 (a -> b) as bs => MapRTuple2 (a -> b) (a, as) (b, bs) instance MapRTuple2 f () () module System.Log.Logger.Base newtype BaseLoggerT l m a BaseLoggerT :: m a -> BaseLoggerT l m a runRawBaseLoggerT :: BaseLoggerT l m a -> m a runBaseLoggerT :: (Functor m, Monad m) => l -> BaseLoggerT (MapRTuple Data (Tuple2RTuple l)) m a -> m a runBaseLogger :: l -> BaseLoggerT (MapRTuple Data (Tuple2RTuple l)) Identity c -> c instance Monad m => Monad (BaseLoggerT l m) instance MonadIO m => MonadIO (BaseLoggerT l m) instance Applicative m => Applicative (BaseLoggerT l m) instance Functor m => Functor (BaseLoggerT l m) instance Monad m => MonadRecord d (BaseLoggerT l m) instance MonadTrans (BaseLoggerT l) instance (Applicative m, Monad m) => MonadLogger (BaseLoggerT l m) module System.Log.Logger.Thread newtype ThreadedLogger' d r m a ThreadedLogger' :: ReaderT (InChan (ChMsg d r)) m a -> ThreadedLogger' d r m a fromThreadedLogger :: ThreadedLogger' d r m a -> ReaderT (InChan (ChMsg d r)) m a type ThreadedLogger d m a = ThreadedLogger' d a m a data ChMsg m a ChMsg :: (m ()) -> ChMsg m a End :: a -> ChMsg m a Exc :: SomeException -> ChMsg m a class MonadThreadLogger m n a | m -> n a getLogChan :: MonadThreadLogger m n a => m (InChan (ChMsg n a)) runRawThreadedLogger :: InChan (ChMsg d r) -> ThreadedLogger' d r m a -> m a runRawBaseThreadedLogger :: InChan (ChMsg d r) -> ThreadedLogger' d r (BaseLoggerT l m) a -> m a runThreadedLogger :: (MonadIO m, Applicative m) => ThreadedLogger m (BaseLoggerT l IO) a -> m a liftIOThread :: (MonadIO m, MonadThreadLogger m n a) => (IO () -> IO fa) -> ThreadedLogger' n a (BaseLoggerT l IO) b -> m b fork :: (MonadIO m, MonadThreadLogger m n a) => ThreadedLogger' n a (BaseLoggerT l IO) b -> m b withTarget :: (MonadThreadLogger m n a, MonadIO m) => n () -> m () instance Monad m => Monad (ThreadedLogger' d r m) instance MonadIO m => MonadIO (ThreadedLogger' d r m) instance Applicative m => Applicative (ThreadedLogger' d r m) instance Functor m => Functor (ThreadedLogger' d r m) instance MonadTrans (ThreadedLogger' d r) instance (MonadIO m, MonadPriorityLogger d) => MonadPriorityLogger (ThreadedLogger' d a m) instance (MonadIO m, MonadLoggerHandler h d, LogFormat m ~ LogFormat d) => MonadLoggerHandler h (ThreadedLogger' d a m) instance (MonadIO m, MonadRecord d n) => MonadRecord d (ThreadedLogger' n a m) instance Monad m => MonadThreadLogger (ThreadedLogger' d r m) d r module System.Log.TH getLoc :: Q Exp logN :: Exp emptyN :: Exp appDataN :: Exp locN :: Exp debugN :: Exp infoN :: Exp noticeN :: Exp warningN :: Exp errorN :: Exp criticalN :: Exp alertN :: Exp panicN :: Exp debug :: String -> Q Exp info :: String -> Q Exp notice :: String -> Q Exp warning :: String -> Q Exp error :: String -> Q Exp critical :: String -> Q Exp alert :: String -> Q Exp panic :: String -> Q Exp mkLog :: Exp -> String -> Q Exp mkBaseData :: Q Exp module System.Log.Simple simpleLog :: (MonadRecord (Data Lvl, (Data Msg, ())) m, Show pri, Enum pri) => pri -> String -> m () debug :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () info :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () notice :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () warning :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () error :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () critical :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () alert :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () panic :: MonadRecord (Data Lvl, (Data Msg, ())) m => String -> m () -- | Written by Wojciech DaniĆo @ Flowbox.io -- --
-- import System.Log.Simple -- -- test = do -- debug "a debug" -- warning "a warning" -- return Done -- -- main = print $ runBaseLogger (Lvl, Msg) test -- -- output: Done ---- -- There are few things to not here: * We are importing the -- ''System.Log.Simple'' interface. It provides all necessary functions -- to start with the library. There is other interface, -- ''System.Log.TH'', which provides simmilar functionality, but allows -- additionally logging such informations like file or module name and -- log location inside the file. * We are running the logger using -- runBaseLogger function providing the description what type of -- information we want to gather with each call to debug, -- warning, etc. This is very important, because we can choose -- only the needed information, like messages and levels and run the -- logger as a pure code. If you try to run the example with other -- description, like (Lvl, Msg, Time), it will fail complaining -- that it needs the IO monad for that. * The BaseLogger -- is the most base logger transformer and it should be run as a base for -- every logger transformer stack. It do not log any messages under the -- hood, in fact you cannot do anything sensible with it. -- -- As every logger transformer, BaseLogger has an appriopriate -- transformer type called BaseLoggerT. You can use it just as -- every monad transformer, to pipe computations to an underlying monad. -- Using the transformer we can ask our logger to log also such -- information as the time: -- --
-- main = print =<< runBaseLogger (Lvl, Msg, Time) test ---- -- There is one very important design decision. All the logger -- transformers, appart from the base one, pass the newly registered log -- to underlying transformers. This way we can create a transformer that -- writes messages to disk and combine it with the one, that registers -- the logs in a list. There are some examples showing this behavior -- later in this document. -- --
-- import System.Log.Simple -- -- test = do -- addHandler $ printHandler Nothing -- debug "a debug" -- warning "a warning" -- -- main = print =<< (runBaseLoggerT (Lvl, Msg) . runHandlerLoggerT defaultFormatter) test ---- -- As a result, we get a colored output (on all platforms, including -- Windows): -- --
-- [Debug] a debug -- [Warning] a warning -- Done ---- -- Ok, so what's happening here? The function addHandler registers -- new log handler in current logger monad. The Nothing just -- indicates, that this handler does not need any special formatter and -- can use the default one, provided when executing the monad - in this -- case, the defaultFormatter. We can of course define our custom -- message formatters. -- -- For no only the printHandler is provided, but it is -- straightforward to define custom handlers. Other will be added in the -- next versions of the library. -- --
-- defaultFormatter = colorLvlFormatter ("[" : Lvl : "] ") : Msg
--
--
-- You might ask now, what are Lvl or Msg. They are "data
-- pointers". You will learn about them later, for now just remember, you
-- can use them while running loggers as well as defining formatters.
-- There is one very important thing to note here - you cannot use any
-- data provider in your logger, that was not declared to be gathered
-- when the logger is run! In later chapters you will also learn how to
-- create custom data providers.
--
-- So what if we would like to output not only the message and it's
-- priority level, but also the module name and location of the message
-- in the source file? Such logger is also defined and it's called
-- defaultFormatterTH. You cannot use it using the Simple
-- interface, so lets see for now how it is defined:
--
--
-- defaultFormatterTH = colorLvlFormatter ("[" : Lvl : "] ") : Loc : ": " : Msg
--
--
-- It's output is simmilar to:
--
-- -- [Debug] Main.hs:4: a debug -- [Warning] Main.hs:5: a warning ---- --
-- test = do -- addHandler $ printHandler Nothing -- debug "a debug" -- setPriority Debug -- debug "another debug" -- warning "a warning" -- -- print =<< ( runBaseLoggerT (Lvl, Msg) -- . runHandlerLoggerT defaultFormatter -- . runPriorityLoggerT Warning -- ) test ---- -- As the output we get: -- --
-- [Debug] another debug -- [Warning] a warning ---- --
-- import System.Log.Simple -- import qualified System.Log.Logger.Thread as Thread -- import Control.Monad.IO.Class (liftIO) -- -- test = do -- addHandler $ printHandler Nothing -- debug "a debug" -- setPriority Debug -- debug "another debug" -- warning "a warning" -- Thread.fork $ do -- liftIO $ print "Threaded print" -- debug "debug in fork" -- liftIO $ print "End of the test!" -- -- print =<< ( runBaseLoggerT (Lvl, Msg) -- . runHandlerLoggerT defaultFormatter -- . runPriorityLoggerT Warning -- . runThreadedLogger -- ) test ---- -- As the output we get: -- --
-- "Threaded print" -- "End of the test!" -- [Debug] another debug -- [Warning] a warning -- [Debug] debug in fork ---- -- The output may of course vary, based on the way threads will be -- sheduled, because we use print functions here. Anyway you can -- notice, that the prints were executed at the same time as all the -- logging. It is important to use Thread.fork, which is just a -- simple wrapper around forkIO. -- --
-- test = do -- addHandler $ printHandler Nothing -- debug "debug" -- Thread.fork $ do -- fail "oh no" -- debug "debug in fork" -- warning "a warning" -- -- print =<< ( runBaseLoggerT (Lvl, Msg) -- . runHandlerLoggerT defaultFormatter -- . runThreadedLogger -- ) test ---- -- Results in: -- --
-- [Debug] debug -- Main.hs: user error (oh no) ---- --
-- import System.Log.TH -- -- test = do -- addHandler $ printHandler Nothing -- $(debug "a debug") -- setPriority Debug -- $(debug "another debug") -- $(warning "a warning") -- -- print =<< ( runBaseLoggerT (Lvl, Msg, Loc) -- . runHandlerLoggerT defaultFormatterTH -- . runPriorityLoggerT Warning -- . runThreadedLogger -- ) test ---- -- Which results in the following output: -- --
-- [Debug] Main:7: another debug -- [Warning] Main:8: a warning ---- --
-- test = do -- addHandler $ addFilter (lvlFilter Warning) $ printHandler Nothing -- $(debug "a debug") -- $(warning "a warning") -- -- print =<< ( runBaseLoggerT (Lvl, Msg, Loc) -- . runHandlerLoggerT defaultFormatterTH -- ) test ---- -- Which results in: -- --
-- [Warning] Main:5: a warning ---- --
-- data Level = Debug -- ^ Debug Logs -- | Info -- ^ Information -- | Notice -- ^ Normal runtime conditions -- | Warning -- ^ General Warnings -- | Error -- ^ General Errors -- | Critical -- ^ Severe situations -- | Alert -- ^ Take immediate action -- | Panic -- ^ System is unusable -- deriving (Eq, Ord, Show, Read, Enum) ---- --
-- data Msg = Msg deriving (Show) -- type instance DataOf Msg = String ---- -- That's it. There is no more code for it. After creating such new -- datatype you can create a pretty printing instance for it and use it -- just like all other data even in the formatter builder! But how the -- data is being registered? Let's look how the debug function is -- defined in the Simple library: -- --
-- debug = log empty Debug ---- -- The log function is a very generic one and allows creating -- almost any logging functionality. If for example we would love to add -- a new data provider Foo registering an Int, we can do -- this simply by: -- --
-- data Foo = Foo deriving (Show)
-- type instance DataOf Foo = Int
--
-- debugFoo i = log (appData Foo i empty) Debug
--
-- instance PPrint Foo where
-- pprint = text . show
--
-- fooFormatter = defaultFormatter : " (" : Foo : ")"
--
-- test = do
-- addHandler $ printHandler Nothing
-- debugFoo 7 "my custom debug"
--
-- print =<< ( runBaseLoggerT (Lvl, Msg, Foo)
-- . runHandlerLoggerT defaultFormatter
-- ) test
--
--
-- Which results in:
--
-- -- [Debug] my custom debug (7) ---- --
-- import Data.Time.Clock (getCurrentTime, UTCTime)
-- import Data.Time.Format (formatTime, defaultTimeLocale)
--
-- data Time = Time deriving (Show)
-- type instance DataOf Time = UTCTime
--
-- instance MonadIO m => DataGetter Time m where
-- getData = do liftIO $ Data Time $ getCurrentTime
--
-- instance Pretty UTCTime where
-- pretty = text . formatTime defaultTimeLocale "%c"
--
-- defaultTimeFormatter = colorLvlFormatter ("[" : Lvl : "] ") : Time : ": " : Msg
--
--
-- That's it! You can use any function inside - both pure as well as IO.
-- If you use pure function, just return the value. If you will execute
-- runBaseLogger it will be evaluated inside the Identity
-- monad.
--
--