# co-log
[![Hackage](https://img.shields.io/hackage/v/co-log.svg)](https://hackage.haskell.org/package/co-log)
[![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](https://github.com/kowainik/co-log/blob/master/LICENSE)
[![Build status](https://secure.travis-ci.org/kowainik/co-log.svg)](https://travis-ci.org/kowainik/co-log)
Logging library based on [`co-log-core`](../co-log-core) package. Provides
ready-to-go implementation of logging. This README contains _How to_ tutorial on
using this library. This tutorial explains step by step how to integrate
`co-log` into small basic project, specifically how to replace `putStrLn` used
for logging with library provided logging.
All code below can be compiled and run with the following commands:
```shell
$ cabal new-build co-log
$ cabal new-exec readme
```
## Preamble: imports and language extensions
Since this is a literate haskell file, we need to specify all our language
extensions and imports up front.
```haskell
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
import Colog (Message, WithLog, cmap, fmtMessage, logDebug, logInfo, logTextStdout, logWarning,
usingLoggerT)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Semigroup ((<>))
import qualified Data.Text as Text
import qualified Data.Text.IO as TextIO
```
## Simple IO function example
Consider the following function that reads lines from `stdin` and outputs
different feedback depending on the line size.
```haskell
processLinesBasic :: IO ()
processLinesBasic = do
line <- TextIO.getLine
case Text.length line of
0 -> do
-- here goes logging
TextIO.putStrLn ">>>> Empty input"
processLinesBasic
n -> do
TextIO.putStrLn ">>>> Correct input"
TextIO.putStrLn $ "Line length: " <> Text.pack (show n)
```
This code mixes application logic with logging of the steps. It's convenient to
have logging to observe behavior of the application. But `putStrLn` is very
simple and primitive way to log things.
## Using `co-log` library
In order to use `co-log` library, we need to refactor `processLinesBasic`
function in the following way:
```haskell
processLinesLog :: (WithLog env Message m, MonadIO m) => m ()
processLinesLog = do
line <- liftIO TextIO.getLine
case Text.length line of
0 -> do
-- here goes logging
logWarning "Empty input"
processLinesLog
n -> do
logDebug "Correct line"
logInfo $ "Line length: " <> Text.pack (show n)
```
Let's summarize required changes:
1. Make type more polymorphic: `(WithLog env Message m, MonadIO m) => m ()`
2. Add `liftIO` to all `IO` functions.
3. Replace `putStrLn` with proper `log*` function.
## Running actions
Let's run both functions:
```haskell
main :: IO ()
main = do
processLinesBasic
let action = cmap fmtMessage logTextStdout
usingLoggerT action processLinesLog
```
And here is how output looks like:
![screenshot from 2018-09-17 20-52-01](https://user-images.githubusercontent.com/4276606/45623973-8bafb900-babb-11e8-9e20-4369a5a8e5ff.png)