packages feed

logger 0.1.0.1 → 0.1.0.2

raw patch · 3 files changed

+35/−25 lines, 3 filesdep ~ansi-wl-pprintdep ~containersdep ~mtl

Dependency ranges changed: ansi-wl-pprint, containers, mtl, time, time-locale-compat, transformers, transformers-compat, unagi-chan

Files

README.md view
@@ -34,17 +34,17 @@ ```  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 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 similar 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:+As every logger transformer, `BaseLogger` has an appropriate 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.+There is one very important design decision. All the logger transformers, apart 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 @@ -52,16 +52,16 @@ ```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:+As a result we get tuple, whose first element is the function's 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.+WriterLogger 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:+`HandlerLogger` allows you to handle messages using handlers and log formatters. At last we will see something useful as a logging library! To start, let's look at a simple example:  ```haskell import System.Log.Simple@@ -84,7 +84,7 @@  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.+For now only the `printHandler` is provided, but it is straightforward to define custom handlers. Others will be added in the next versions of the library.  #### Formatters @@ -96,13 +96,13 @@  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:+So what if we would like to output not only the message and its 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 let's see for now how it is defined:  ```haskell defaultFormatterTH = colorLvlFormatter ("[" <:> Lvl <:> "] ") <:> Loc <:> ": " <:> Msg ``` -It's output is simmilar to:+Its output is similar to:  ```haskell [Debug] Main.hs:4: a debug@@ -136,7 +136,7 @@  ### 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:+The `ThreadedLogger` is a very fancy one. It allows to 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 sent 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. Let's look at the example:  ```haskell import           System.Log.Simple@@ -171,12 +171,12 @@ [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.+The output may of course vary, based on the way threads will be scheduled, 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:+All the loggers behave in a proper way, when an exception is raised. The exception will be evaluated after all necessary logging has been done:  ```haskell test = do@@ -257,9 +257,9 @@  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+### Custom priority 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:+Defining a custom priority level is as easy as creating a new datatype that derives the `Enum` and start using it. The default priorities are defined as:  ```haskell data Level = Debug     -- ^ Debug Logs@@ -317,7 +317,7 @@ [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.+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 its 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: 
logger.cabal view
@@ -1,6 +1,6 @@ name:                logger category:            System-version:             0.1.0.1+version:             0.1.0.2 license:             Apache-2.0 license-file:        LICENSE cabal-version:       >=1.10@@ -76,16 +76,16 @@    build-depends:       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,+      transformers >=0.3.0.0,+      transformers-compat >=0.4.0.0,+      time >=1.4.2,+      time-locale-compat >=0.1.0.1,+      ansi-wl-pprint >=0.6,       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+      mtl >=2.1.3.1,+      containers >=0.5,+      unagi-chan >=0.3    hs-source-dirs:      src 
src/System/Log/Logger/Handler.hs view
@@ -35,7 +35,8 @@ 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 qualified System.IO                     as IO+import           Text.PrettyPrint.ANSI.Leijen  (Doc, putDoc, hPutDoc)  ---------------------------------------------------------------------- -- MonadLoggerHandler@@ -86,12 +87,18 @@  -- === Handlers === +topHandler :: Monad m => Formatter l -> Handler m l topHandler fmt = mkHandler "TopHandler" (\_ _ -> return ()) Nothing                & formatter .~ (Just fmt) +printHandler :: MonadIO m => Maybe (Formatter l) -> Handler m l printHandler = mkHandler "PrintHandler" handle where     handle defDoc l = liftIO $ putDoc defDoc *> putStrLn "" +fileHandler :: MonadIO m => IO.Handle -> Maybe (Formatter l) -> Handler m l+fileHandler h = mkHandler "FileHandler" (handle h) where+    handle h defDoc l = liftIO $ hPutDoc h defDoc *> IO.hPutStrLn h ""+ ---------------------------------------------------------------------- -- HandlerLoggerT ----------------------------------------------------------------------@@ -119,7 +126,10 @@     runFilters h l = foldr (&&) True $ fmap (\f -> runFilter f l) (h^.filters)  +getTopHandler :: Monad m => HandlerLoggerT m (Handler (HandlerLoggerT m) (LogFormat m)) getTopHandler = HandlerLoggerT State.get++putTopHandler :: Monad m => Handler (HandlerLoggerT m) (LogFormat m) -> HandlerLoggerT m () putTopHandler = HandlerLoggerT . State.put  -- === Instances ===