packages feed

logger 0.1.0.0 → 0.1.0.1

raw patch · 10 files changed

+523/−109 lines, 10 filesdep +time-locale-compatdep +transformers-compatdep ~basedep ~lensdep ~mtl

Dependencies added: time-locale-compat, transformers-compat

Dependency ranges changed: base, lens, mtl, template-haskell, time, transformers

Files

README.md view
@@ -1,2 +1,362 @@-# haskell-logging+# haskell-logger Fast &amp; extensible logging framework for Haskell!++# Overview++Logger is a fast and extensible Haskell logging framework. ++Logger allows you to log any kind of messages in both `IO` as well as pure code, depending on the information 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.++# Documentation++The following documentation describes how to use the framework, how it works under the hood and how can you extend it.++## Basics++This chapter covers all the basic information about logger transformers shipped with the framework.++### BaseLogger++Let's start with a very simple example:++```haskell+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 note here:+* We are importing the `System.Log.Simple` interface. It provides all necessary functions to start with the library. There is another interface, `System.Log.TH` (using `TemplateHaskell` to gather logs location information), 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 does 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:++```haskell+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.++### WriterLogger++`WriterLogger` is just like `Writer` monad - it gathers all the logs into a list and returns it:+```haskell+main = print $ (runBaseLogger (Lvl, Msg) . runWriterLoggerT) test+```+As a result we get tuple, which first element is the functions return value, while the second is list of all Log messages. For now the log message is not very friendly nested-tuple structure, but it will change in the next versions of the library. To be clear, the single log looks like this at the moment:+```haskell+Log {fromLog = (Data {recBase = Lvl, recData = LevelData 0 "Debug"},(Data {recBase = Msg, recData = "a debug"},()))}+```++WiterLogger should work as fast as just `WriterT` monad transformer with `Dlist` used for logs gathering, because there should be no overhead introduced by the library.++### HandlerLogger++`HandlerLogger` allows you to handle messages using handlers and log formatters. At last we will see something usefull as a logging library! To start, let's look at a simple example:++```haskell+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):++```haskell+[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.++#### Formatters++It is possible to define a custom message formatter. To do it, import the module `System.Log.Format` and use so called formatter builder. Let's see how the `defaultFormatter` is defined:++```haskell+defaultFormatter = colorLvlFormatter ("[" <:> Lvl <:> "] ") <:> Msg+```++You might ask now, what are `Lvl` or `Msg`. They are "data providers". 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:++```haskell+defaultFormatterTH = colorLvlFormatter ("[" <:> Lvl <:> "] ") <:> Loc <:> ": " <:> Msg+```++It's output is simmilar to:++```haskell+[Debug] Main.hs:4: a debug+[Warning] Main.hs:5: a warning+```++### PriorityLogger++The `PriorityLogger` is used to filter the messages by priority levels. It is important to note here, that `PriorityLogger` is able to filter them at compile time, so if we need some `IO` actions to construct a log, like reading a time or process id, they will not be executed when the priority of such log is too low. Let's see how we can use it:++```haskell+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:++```haskell+[Debug] another debug+[Warning] a warning+```++### ThreadedLogger++The `ThreadedLogger` is a very fancy one. It allows separate the actual logging from program. Program is being run on a separate thread, while logs are being gathered by the main thread. You can fork the program as many times you want and all the logs will be send to the log-gather routine. This allows to get nicely not-broken output in terminal or in files from different threads. The program stops after all the logs have been processed. Lets look at the example:++```haskell+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:++```haskell+"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`.++#### Exception handling++All the loggers behave in a proper way, when an exception is rised. The exception will be evaluated after all necessary logging has been done:++```haskell+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:++```haskell+[Debug] debug+Main.hs: user error (oh no)+```++### DropLogger++The `DropLogger` allows you to simply drop all logs from the function. It could be used if you want to execute a subroutine but just discard all logging there. The log messages would be completely discarded - they will not even be created.++## TemplateHaskell interface++You can use more advanced interface to be able to log more information, like module name or file number. To use it, import ```System.Log.TH``` instead of ```System.Log.Simple``` and use TemplateHaskell syntax to report logs:++```haskell+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:++```haskell+[Debug] Main:7: another debug+[Warning] Main:8: a warning+```++## Filtering messages++The framework allows you to filter messages after they have been created. It is slower than using `PriorityLogger` because the messages are created even if they are not needed. It could be used for example in a situation, where you've got many handlers and you want to output only important logs to the screen and all the logs into files. Here's a small example showing how it works.++```haskell+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:++```haskell+[Warning] Main:5: a warning+```++## Extending the logger++It is possible to extend the logging framework in any way you want. All the functionality you have seen above are just simple logger transformers and you can modify them in a ton of ways or create custom ones.++### Custom prioritiy levels++Defining a custom priority levels is as easy as creating a new datatype that derives the `Enum` and start using it. The default prorities are defined as:++```haskell+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)+```++### Custom data providers++It is possible to define custom data providers. Let's look how the `Msg` data provided is defined in the library:++```haskell+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:++```haskell+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:++```haskell+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:++```haskell+[Debug] my custom debug (7)+```++A new function `appData` is used here. It allows providing a data to be registered when creating log messages. You can provide this way any data you want and only the data will be used, that is explicitly defined when running a logger. If you run a logger asking about data that was not provided when constructing the log, the framework will look for it's monad data provider (described later). If there will be no such provider, it will fail at compile-time.++In fact, if we look how the log function is defined, we will find some similarities:++```haskell+log rec pri msg = do+    [...]+    appendRecord $ appData Lvl (mkLevel pri)+                 $ appData Msg msg+                 $ rec+```++#### Monad data providers++What happens when such data is not provided when constructing the message? Like `Time` data? If data is not available at construction time, the logger looks for its `DataGetter` instance. A simple `Time` data provider could be defined as:++```haskell+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.++### Custom logger transformers++It's also straightforward to define custom logger transformers. They have to be instances of some datatypes. To know more about it, look at example transformers inside the `System.Log.Logger` module.++# Conclusion++This is a new logging library written for purposes of fast logging between threads. It is still under development, so you can expect some api changes. There is still some functionality missing, like file handlers, but as you have seen, it is easy to define such. Any help would be welcome.++Happy logging!
logger.cabal view
@@ -1,6 +1,6 @@ name:                logger category:            System-version:             0.1.0.0+version:             0.1.0.1 license:             Apache-2.0 license-file:        LICENSE cabal-version:       >=1.10@@ -14,9 +14,9 @@ homepage:            https://github.com/wdanilo/haskell-logger bug-reports:         https://github.com/wdanilo/haskell-logger/issues -description:         +description: -  Logging is a fast and extensible Haskell 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.   .@@ -31,25 +31,25 @@   location: git://github.com/wdanilo/haskell-logger.git  library-  exposed-modules:     -      System.Log, -      System.Log.Tuples, -      System.Log.Simple, -      System.Log.Filter, -      System.Log.Level, -      System.Log.Format, -      System.Log.Data, -      System.Log.Log, -      System.Log.TH, -      System.Log.Logger.Base, -      System.Log.Logger.Writer, -      System.Log.Logger.Thread, -      System.Log.Logger.Priority, -      System.Log.Logger.Handler, +  exposed-modules:+      System.Log,+      System.Log.Tuples,+      System.Log.Simple,+      System.Log.Filter,+      System.Log.Level,+      System.Log.Format,+      System.Log.Data,+      System.Log.Log,+      System.Log.TH,+      System.Log.Logger.Base,+      System.Log.Logger.Writer,+      System.Log.Logger.Thread,+      System.Log.Logger.Priority,+      System.Log.Logger.Handler,       System.Log.Logger.Drop-  -  -- other-modules:     +  -- other-modules:+   default-extensions:       DefaultSignatures,       ViewPatterns,@@ -61,7 +61,7 @@       FlexibleContexts,       FlexibleInstances,       GeneralizedNewtypeDeriving-  +   -- LANGUAGE extensions used by modules in this package.   other-extensions:       KindSignatures,@@ -73,19 +73,21 @@       TemplateHaskell,       CPP,       OverloadedStrings-  +   build-depends:-      base >=4.7 && <4.8,-      transformers >=0.4 && <0.5,-      time >=1.5 && <1.6,+      base >=4.7 && <= 4.9,+      transformers >=0.3.0.0 && <0.5,+      transformers-compat >=0.4.0.0 && <0.5,+      time >=1.4.2 && <1.6,+      time-locale-compat ==0.1.0.1,       ansi-wl-pprint >=0.6 && <0.7,-      lens >=4.6 && <4.7,-      template-haskell >=2.9 && <2.10,-      mtl >=2.2 && <2.3,+      lens >=4.6,+      template-haskell >=2.9,+      mtl >=2.1.3.1 && <2.3,       containers >=0.5 && <0.6,       unagi-chan >=0.3 && <0.4-  +   hs-source-dirs:      src-  +   default-language:    Haskell2010-  +
src/System/Log.hs view
@@ -41,7 +41,8 @@ -- output: "Done" @ -There are few things to not here:+There are few things to note 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.@@ -161,11 +162,11 @@         liftIO $ print "Threaded print"         debug "debug in fork"     liftIO $ print "End of the test!"-    -print =<< ( runBaseLoggerT (Lvl, Msg) -          . runHandlerLoggerT defaultFormatter -          . runPriorityLoggerT Warning -          . runThreadedLogger++print =<< ( runBaseLoggerT (Lvl, Msg)+          . runHandlerLoggerT defaultFormatter+          . runPriorityLoggerT Warning+          . runThreadedLoggerT           ) test @ @@ -195,9 +196,9 @@         debug "debug in fork"     warning "a warning" -print =<< ( runBaseLoggerT (Lvl, Msg) -          . runHandlerLoggerT defaultFormatter -          . runThreadedLogger+print =<< ( runBaseLoggerT (Lvl, Msg)+          . runHandlerLoggerT defaultFormatter+          . runThreadedLoggerT           ) test @ @@ -226,10 +227,10 @@     $(debug "another debug")     $(warning "a warning") -print =<< ( runBaseLoggerT (Lvl, Msg, Loc) +print =<< ( runBaseLoggerT (Lvl, Msg, Loc)           . runHandlerLoggerT defaultFormatterTH-          . runPriorityLoggerT Warning -          . runThreadedLogger+          . runPriorityLoggerT Warning+          . runThreadedLoggerT           ) test @ 
src/System/Log/Data.hs view
@@ -28,7 +28,15 @@ import System.Log.Log         (MonadLogger, LogFormat, Log(Log), fromLog, appendLog) import Data.Time.Clock        (getCurrentTime, UTCTime) import Control.Lens-+import Control.Monad.Trans.Class+import Control.Monad.Trans.Except+import Control.Monad.Trans.List+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader+import Control.Monad.Trans.RWS+import Control.Monad.Trans.State+import Control.Monad.Trans.Writer+import Data.Monoid  ---------------------------------------------------------------------- -- Logging utils@@ -62,6 +70,28 @@         l <- buildLog d         appendLog l +instance (Monad m, MonadRecord d m) => MonadRecord d (ExceptT e m) where+    appendRecord = lift . appendRecord++instance (Monad m, MonadRecord d m) => MonadRecord d (ListT m) where+    appendRecord = lift . appendRecord++instance (Monad m, MonadRecord d m) => MonadRecord d (MaybeT m) where+    appendRecord = lift . appendRecord++instance (Monad m, MonadRecord d m) => MonadRecord d (ReaderT s m) where+    appendRecord = lift . appendRecord++instance (Monad m, Monoid w, MonadRecord d m) => MonadRecord d (RWST r w s m) where+    appendRecord = lift . appendRecord++instance (Monad m, MonadRecord d m) => MonadRecord d (StateT s m) where+    appendRecord = lift . appendRecord++instance (Monad m, Monoid w, MonadRecord d m) => MonadRecord d (WriterT w m) where+    appendRecord = lift . appendRecord++ appData :: (a~DataOf base) => base -> a -> RecordBuilder as -> RecordBuilder (Data base, as) appData base a = fmap (Data base a,) @@ -105,7 +135,7 @@         Log ys     <- buildLogProto b         Log (y,()) <- buildLogProto $ RecordBuilder xs         return $ Log (y, ys)-      + instance Monad m => LogBuilderProto a m () where     buildLogProto _ = return $ Log () @@ -117,7 +147,7 @@ -- Data reading ---------------------------------------------------------------------- -class Lookup base s where +class Lookup base s where     lookup :: base -> s -> Data base  readData :: Lookup a l => a -> l -> DataOf a@@ -133,7 +163,7 @@  --- -class LookupDataSet base s where +class LookupDataSet base s where     lookupDataSet :: base -> s -> Data base  instance LookupDataSet base (Data base,as) where@@ -161,7 +191,7 @@ type instance DataOf Msg = String  --- Lvl -- +-- Lvl --  data Lvl = Lvl deriving (Show) type instance DataOf Lvl = LevelData
src/System/Log/Format.hs view
@@ -18,7 +18,8 @@ import System.Log.Log               (Log) import System.Log.Data              (Lvl(Lvl), Msg(Msg), Loc(Loc), Time(Time), LocData(LocData), LevelData(LevelData), readData, DataOf, Lookup) import Data.Time.Clock              (UTCTime)-import Data.Time.Format             (formatTime, defaultTimeLocale)+import Data.Time.Format             (formatTime)+import Data.Time.Locale.Compat      (defaultTimeLocale) import Text.PrettyPrint.ANSI.Leijen  
src/System/Log/Log.hs view
@@ -15,6 +15,13 @@ module System.Log.Log where  import Control.Applicative+import Control.Monad.Trans.Except+import Control.Monad.Trans.List+import Control.Monad.Trans.Maybe+import Control.Monad.Trans.Reader+import Control.Monad.Trans.RWS+import Control.Monad.Trans.State+import Control.Monad.Trans.Writer   ----------------------------------------------------------------------@@ -25,17 +32,17 @@  type family LogFormat (m :: * -> *) +type instance LogFormat (ExceptT e m) = LogFormat m+type instance LogFormat (ListT m) = LogFormat m+type instance LogFormat (MaybeT m) = LogFormat m+type instance LogFormat (ReaderT r m) = LogFormat m+type instance LogFormat (RWST r w s m) = LogFormat m+type instance LogFormat (StateT s m) = LogFormat m+type instance LogFormat (WriterT w m) = LogFormat m+ ---------------------------------------------------------------------- -- MonadLogger ----------------------------------------------------------------------  class (Monad m, Applicative m) => MonadLogger m where     appendLog :: Log (LogFormat m) -> m ()--------
src/System/Log/Logger/Base.hs view
@@ -23,9 +23,9 @@ -- BaseLoggerT ---------------------------------------------------------------------- -newtype BaseLoggerT l m a = BaseLoggerT { runRawBaseLoggerT :: m a } deriving (Monad, MonadIO, Applicative, Functor) +newtype BaseLoggerT l m a = BaseLoggerT { runRawBaseLoggerT :: m a } deriving (Monad, MonadIO, Applicative, Functor) -runBaseLoggerT :: (Functor m, Monad m) => l -> BaseLoggerT (MapRTuple Data (Tuple2RTuple l)) m a -> m a+runBaseLoggerT :: l -> BaseLoggerT (MapRTuple Data (Tuple2RTuple l)) m a -> m a runBaseLoggerT _ = runRawBaseLoggerT  runBaseLogger d = runIdentity . runBaseLoggerT d
src/System/Log/Logger/Handler.hs view
@@ -23,15 +23,20 @@ import           System.Log.Filter             (Filter, runFilter) import           Control.Lens                  hiding (children) import           System.Log.Log                (Log, MonadLogger(appendLog), LogFormat, LogFormat)-import           Control.Monad.Trans           (lift)+import           Control.Monad.Trans           (MonadTrans, lift)+import           Control.Monad.Trans.Except+import           Control.Monad.Trans.List+import           Control.Monad.Trans.Maybe+import           Control.Monad.Trans.Reader+import           Control.Monad.Trans.RWS+import           Control.Monad.Trans.State+import           Control.Monad.Trans.Writer import           Control.Monad.State           (StateT, runStateT) import qualified Control.Monad.State           as State import           Control.Monad.IO.Class        (MonadIO, liftIO) import           System.Log.Format             (Formatter, runFormatter, defaultFormatter) import           Text.PrettyPrint.ANSI.Leijen  (Doc, putDoc)-import Control.Monad.Trans (MonadTrans) - ---------------------------------------------------------------------- -- MonadLoggerHandler ----------------------------------------------------------------------@@ -42,6 +47,14 @@     default addHandler :: (Monad m, MonadTrans t) => Handler n (LogFormat m) -> t m ()     addHandler = lift . addHandler +instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (ExceptT e m)+instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (ListT m)+instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (MaybeT m)+instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (ReaderT r m)+instance (Monad m, Monoid w, MonadLoggerHandler n m) => MonadLoggerHandler n (RWST r w s m)+instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (StateT s m)+instance (Monad m, Monoid w, MonadLoggerHandler n m) => MonadLoggerHandler n (WriterT w m)+ ---------------------------------------------------------------------- -- Handler ----------------------------------------------------------------------@@ -80,17 +93,17 @@     handle defDoc l = liftIO $ putDoc defDoc *> putStrLn ""  ------------------------------------------------------------------------- HandlerLogger+-- HandlerLoggerT ---------------------------------------------------------------------- -newtype HandlerLogger m a = HandlerLogger { fromHandlerLogger :: StateT (Handler' (HandlerLogger m)) m a } deriving (Monad, MonadIO, Applicative, Functor)+newtype HandlerLoggerT m a = HandlerLoggerT { fromHandlerLogger :: StateT (Handler' (HandlerLoggerT m)) m a } deriving (Monad, MonadIO, Applicative, Functor) -type instance LogFormat (HandlerLogger m) = LogFormat m+type instance LogFormat (HandlerLoggerT m) = LogFormat m -instance MonadTrans HandlerLogger where-    lift = HandlerLogger . lift+instance MonadTrans HandlerLoggerT where+    lift = HandlerLoggerT . lift -runHandlerLoggerT :: (Functor m, Monad m) => Formatter (LogFormat m) -> HandlerLogger m b -> m b+runHandlerLoggerT :: (Functor m, Monad m) => Formatter (LogFormat m) -> HandlerLoggerT m b -> m b runHandlerLoggerT fmt = fmap fst . flip runStateT (topHandler fmt) . fromHandlerLogger  @@ -106,21 +119,21 @@     runFilters h l = foldr (&&) True $ fmap (\f -> runFilter f l) (h^.filters)  -getTopHandler = HandlerLogger State.get-putTopHandler = HandlerLogger . State.put+getTopHandler = HandlerLoggerT State.get+putTopHandler = HandlerLoggerT . State.put  -- === Instances ===  instance (MonadLogger m, Functor m, l~LogFormat m, LookupDataSet Msg l, LookupDataSet Lvl l)-      => MonadLogger (HandlerLogger m) where-    appendLog l =  (runHandler defDoc l =<< getTopHandler) +      => MonadLogger (HandlerLoggerT m) where+    appendLog l =  (runHandler defDoc l =<< getTopHandler)                 *> lift (appendLog l)         where defDoc = runFormatter defaultFormatter l -instance (Monad m, Functor m) => MonadLoggerHandler (HandlerLogger m) (HandlerLogger m) where+instance (Monad m, Functor m) => MonadLoggerHandler (HandlerLoggerT m) (HandlerLoggerT m) where     addHandler h = do         topH <- getTopHandler         putTopHandler $ addChildHandler h topH -instance (Functor m, MonadLogger m, l~LogFormat m, LogBuilder d (HandlerLogger m), LookupDataSet Msg l, LookupDataSet Lvl l) -      => MonadRecord d (HandlerLogger m)+instance (Functor m, MonadLogger m, l~LogFormat m, LogBuilder d (HandlerLoggerT m), LookupDataSet Msg l, LookupDataSet Lvl l)+      => MonadRecord d (HandlerLoggerT m)
src/System/Log/Logger/Thread.hs view
@@ -32,12 +32,12 @@   ------------------------------------------------------------------------- ThreadedLogger+-- ThreadedLoggerT ---------------------------------------------------------------------- -newtype ThreadedLogger' d r m a = ThreadedLogger' { fromThreadedLogger :: ReaderT (InChan (ChMsg d r)) m a } deriving (Monad, MonadIO, Applicative, Functor, MonadTrans)-type ThreadedLogger d m a = ThreadedLogger' d a m a-type instance LogFormat (ThreadedLogger' d r m) = LogFormat m+newtype ThreadedLoggerT' d r m a = ThreadedLoggerT' { fromThreadedLoggerT :: ReaderT (InChan (ChMsg d r)) m a } deriving (Monad, MonadIO, Applicative, Functor, MonadTrans)+type ThreadedLoggerT d m a = ThreadedLoggerT' d a m a+type instance LogFormat (ThreadedLoggerT' d r m) = LogFormat m  data ChMsg m a = ChMsg (m ()) | End a | Exc SomeException @@ -46,18 +46,18 @@  -- === Utils === -runRawThreadedLogger :: InChan (ChMsg d r) -> ThreadedLogger' d r m a -> m a-runRawThreadedLogger ch = flip runReaderT ch . fromThreadedLogger+runRawThreadedLoggerT :: InChan (ChMsg d r) -> ThreadedLoggerT' d r m a -> m a+runRawThreadedLoggerT ch = flip runReaderT ch . fromThreadedLoggerT  -- cutting out all the logs and sending them over channel, computing result-runRawBaseThreadedLogger :: InChan (ChMsg d r) -> ThreadedLogger' d r (BaseLoggerT l m) a -> m a-runRawBaseThreadedLogger ch = runRawBaseLoggerT . runRawThreadedLogger ch+runRawBaseThreadedLoggerT :: InChan (ChMsg d r) -> ThreadedLoggerT' d r (BaseLoggerT l m) a -> m a+runRawBaseThreadedLoggerT ch = runRawBaseLoggerT . runRawThreadedLoggerT ch -runThreadedLogger :: (MonadIO m, Applicative m) => ThreadedLogger m (BaseLoggerT l IO) a -> m a-runThreadedLogger m = do+runThreadedLoggerT :: (MonadIO m, Applicative m) => ThreadedLoggerT m (BaseLoggerT l IO) a -> m a+runThreadedLoggerT m = do     (inChan, outChan) <- liftIO newChan     liftIO $ forkIO $ do-        out <- (End <$> runRawBaseThreadedLogger inChan m) `catch` (\e -> return (Exc e))+        out <- (End <$> runRawBaseThreadedLoggerT inChan m) `catch` (return . Exc)         writeChan inChan out     loop outChan     where loop :: (MonadIO m, Applicative m) => OutChan (ChMsg m a) -> m a@@ -68,18 +68,18 @@                   ChMsg d -> d *> loop ch                   Exc   e -> liftIO $ throwIO e -liftIOThread :: (MonadIO m, MonadThreadLogger m n a) => (IO () -> IO fa) -> ThreadedLogger' n a (BaseLoggerT l IO) b -> m b+liftIOThread :: (MonadIO m, MonadThreadLogger m n a) => (IO () -> IO fa) -> ThreadedLoggerT' n a (BaseLoggerT l IO) b -> m b liftIOThread f m = do     inChan <- getLogChan     ret    <- liftIO $ newEmptyMVar     liftIO . f $ do-        out <- (End <$> runRawBaseThreadedLogger inChan m) `catch` (\e -> return (Exc e))+        out <- (End <$> runRawBaseThreadedLoggerT inChan m) `catch` (return . Exc)         case out of             End v -> putMVar ret v             Exc e -> putMVar ret undefined *> writeChan inChan (Exc e)     liftIO $ takeMVar ret -fork :: (MonadIO m, MonadThreadLogger m n a) => ThreadedLogger' n a (BaseLoggerT l IO) b -> m b+fork :: (MonadIO m, MonadThreadLogger m n a) => ThreadedLoggerT' n a (BaseLoggerT l IO) b -> m b fork = liftIOThread forkIO  withTarget :: (MonadThreadLogger m n a, MonadIO m) => n () -> m ()@@ -89,17 +89,17 @@  -- === Instances === -instance Monad m => MonadThreadLogger (ThreadedLogger' d r m) d r where-    getLogChan = ThreadedLogger' Reader.ask+instance Monad m => MonadThreadLogger (ThreadedLoggerT' d r m) d r where+    getLogChan = ThreadedLoggerT' Reader.ask  --- -instance (MonadIO m, MonadRecord d n) => MonadRecord d (ThreadedLogger' n a m) where+instance (MonadIO m, MonadRecord d n) => MonadRecord d (ThreadedLoggerT' n a m) where     appendRecord = withTarget . appendRecord -instance (MonadIO m, MonadLoggerHandler h d, LogFormat m ~ LogFormat d) => MonadLoggerHandler h (ThreadedLogger' d a m) where+instance (MonadIO m, MonadLoggerHandler h d, LogFormat m ~ LogFormat d) => MonadLoggerHandler h (ThreadedLoggerT' d a m) where     addHandler = withTarget . addHandler -instance (MonadIO m, MonadPriorityLogger d) => MonadPriorityLogger (ThreadedLogger' d a m) where+instance (MonadIO m, MonadPriorityLogger d) => MonadPriorityLogger (ThreadedLoggerT' d a m) where     setPriority = withTarget . setPriority     getPriority = error "Cannot get priority from within ThreadLogger!"
src/System/Log/Logger/Writer.hs view
@@ -29,38 +29,38 @@ import           Control.Monad.Trans    (MonadTrans, lift)  ------------------------------------------------------------------------- WriterLogger+-- WriterLoggerT ----------------------------------------------------------------------  type Logs m = Seq (Log (LogFormat m)) -newtype WriterLogger m a = WriterLogger { fromWriterLogger :: StateT (Logs m) m a } deriving (Monad, MonadIO, Applicative, Functor)+newtype WriterLoggerT m a = WriterLoggerT { fromWriterLoggerT :: StateT (Logs m) m a } deriving (Monad, MonadIO, Applicative, Functor) -instance MonadTrans WriterLogger where-    lift = WriterLogger . lift+instance MonadTrans WriterLoggerT where+    lift = WriterLoggerT . lift -type instance LogFormat (WriterLogger m) = LogFormat m+type instance LogFormat (WriterLoggerT m) = LogFormat m ---runWriterLoggerT :: (Functor m, Monad m) => WriterLogger m b -> m b-runWriterLoggerT = flip runStateT mempty . fromWriterLogger+--runWriterLoggerT :: (Functor m, Monad m) => WriterLoggerT m b -> m b+runWriterLoggerT = flip runStateT mempty . fromWriterLoggerT  class MonadWriterLogger m where     getLogs :: m (Logs m)     putLogs :: Logs m -> m () -instance Monad m => MonadWriterLogger (WriterLogger m) where-    getLogs = WriterLogger State.get-    putLogs = WriterLogger . State.put+instance Monad m => MonadWriterLogger (WriterLoggerT m) where+    getLogs = WriterLoggerT State.get+    putLogs = WriterLoggerT . State.put  withLogs f = do     logs <- getLogs     putLogs $ f logs -instance (Monad m, Functor m, LogBuilderProto d (WriterLogger m) (LogFormat m), MonadLogger m)-      => MonadRecord d (WriterLogger m)+instance (Monad m, Functor m, LogBuilderProto d (WriterLoggerT m) (LogFormat m), MonadLogger m)+      => MonadRecord d (WriterLoggerT m) -instance (Functor m, Monad m, MonadLogger m) => MonadLogger (WriterLogger m) where+instance (Functor m, Monad m, MonadLogger m) => MonadLogger (WriterLoggerT m) where     appendLog l =  withLogs (|> l)                 *> lift (appendLog l) -instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (WriterLogger m)+instance (Monad m, MonadLoggerHandler n m) => MonadLoggerHandler n (WriterLoggerT m)