
[](https://hackage.haskell.org/package/unclogging)
# unclogging
View repository: https://git.mangoiv.com/mangoiv/unclogging
Simple, yet extensible concurrent logging system based on publish/subscribe.
The frontend to this library is based on importing a specific logging frontend. Currently there are `Control.Effect.Unclog.{Json,Text}`
and `Unclog.IO.{Json,Text}` for `aeson` and `text` based logging and use with `fused-effects` and `MonadUnliftIO` respectively,
exposing functions with the same names, `debug`, `info`, `warn` and `fatal` for the four common log levels.
Subscribers watch a channel of logs and are constructed and destructed by the toplevel logging handler, like `runUnclogging` or
`withLoggingWithSubscribers`. To construct your own subscribers, check out the `Unclog.Subscriber` module, more specifically, the
`mkSubscriber`, `mkSubscriberSimple` and `bracketSubscriber` functions.
The library makes use of template haskell to efficiently create static information at compile time. This means that the logging frontend functions are
of type `Q Exp`, which isn't very telling. Due to limitations for typed template haskell we currently cannot perform better though. If you're familiar with
typed template haskell, you can imagine the logging functions to have a type similar to `Code m (frontend -> m ())` (more about this right below).
In reality, as soon as you're splicing in a logging function, e.g. by using `$info`, the type will "materialise" and you will obtain a function
of type `frontend -> m ()` where `frontend` is either `Data.Aeson.Object` if you're using the json frontend or `Data.Text.Text` if you're using the
text frontend. `m` will be something according to the effect system you're using. E.g. in the fused-effects case it will emit a `Has Log sig m` constraint
and in the io case it will emit a `MonadUnliftIO` constraint.
## example for standalone usage, i.e. `MonadUnliftIO` and `text` frontend
```haskell
-- import utilities that are useful for logging
import Unclog
-- the logging frontend has to be specific to the effect system used
import Unclog.Text
import Unclog.Subscribers (withLoggingWithSubscribers)
main :: IO ()
main = do
let subs = [colourSubscriber Info stdout, simpleSubscriber Fatal stderr, fileSubscriber Debug "bla.log"]
withLoggingWithSubscribers subs \logger -> do
$info logger "info"
$debug logger "some important debug info"
```
## example for use with `fused-effects` and `aeson` frontend
```haskell
import Unclog
-- logging frontend specific to fused-effects
import Control.Effect.Unclog.Json
import Control.Carrier.Unclog
-- for the construction of JSON objects.
import Data.Aeson
main :: IO ()
main = do
let subs = [colourSubscriber Info stdout, simpleSubscriber Fatal stderr, fileSubscriber Debug "bla.log"]
-- as you can see, we don't have to pass around the logger explicitly, which makes it a bit more concise and
-- also a tad more safe
runUnclogging subs do
$info ["msg" .= String "hello world"]
$debug ["msg" .= String "message with number", "number" .= Number 1]
```
## more verbose example with multiple threads involved
```haskell
import Unclog
import Unclog.Json
import Data.Aeson
import UnliftIO
import Data.String (fromString)
import Control.Monad (replicateM_, void)
main :: IO ()
main = do
let subs = [colourSubscriber Info stdout, simpleSubscriber Fatal stderr, fileSubscriber Debug "bla.log"]
withLoggingWithSubscribers subs \logger -> do
-- spawn a couple of tasks that write to the logger channel concurrently
let spawnTask (i :: Int) = do
$info logger ["msg" .= String ("I am task " <> fromString (show i))]
replicateM_ 2 do
replicateM_ 2 do
$debug logger ["msg" .= String ("debugging from " <> fromString (show i))]
$warn logger ["warning" .= String ("warning from " <> fromString (show i))]
$fatal logger ["error" .= String ("fatal from " <> fromString (show i))]
void $ runConcurrently $ traverse @[] (Concurrently . spawnTask) [1 .. 5]
```
## the looks of it
This is how the coloured logging looks with above example, as you can see, both the simple logger writes the fatal events to stderr witout colouring them, and the coloured logger writes everything from `Info` upwards.
