co-log-0.7.0.0: README.md
# co-log
<img align="left" width="180" height="180" src="https://user-images.githubusercontent.com/8126674/80955687-92f21a80-8df7-11ea-90d3-422dafdc8391.png">
[](https://github.com/co-log/co-log/actions)
[](https://github.com/co-log/co-log/blob/main/LICENSE)
`co-log` is a composable and configurable logging framework. It
combines all the benefits of Haskell idioms to provide a reasonable
and convenient interface. Although the library design uses some advanced
concepts in its core, we are striving to provide beginner-friendly API. The
library also provides the complete documentation with a lot of beginner-friendly
examples, explanations and tutorials to guide users. The combination of a
pragmatic approach to logging and fundamental Haskell abstractions allows us to
create a highly composable and configurable logging framework.
---
If you're interested in how different Haskell typeclasses are used to
implement core functions of `co-log`, you can read the following blog
post which goes into detail about the internal implementation specifics:
- [co-log: Composable Contravariant Combinatorial Comonadic Configurable Convenient Logging](https://kowainik.github.io/posts/2018-09-25-co-log)
## Co-Log Family
Co-Log is a family of repositories for a composable and configurable logging
framework `co-log`.
Here is the list of currently available repositories and libraries that you can
check out:
| | | |
| :----------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------- |
| [`co-log-core`](https://github.com/co-log/co-log-core) | lightweight package with basic data types and general idea which depends only on `base` | [![Hackage][hk-img-core]][hk-core] |
| [`co-log`](https://github.com/co-log/co-log) | taggless final implementation of logging library based on `co-log-core` | [![Hackage][hk-img]][hk] |
| [`co-log-polysemy`](https://github.com/co-log/co-log-polysemy) | implementation of logging library based on `co-log-core` and the [`polysemy`](http://hackage.haskell.org/package/polysemy) extensible effects library. | [![Hackage][hk-img-ps]][hk-ps] |
| [`co-log-benchmarks`](https://github.com/co-log/co-log-benchmarks) | benchmarks of the `co-log` library | - |
## `co-log` library
Logging library based on [`co-log-core`](https://github.com/co-log/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 build
$ cabal 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 Control.Monad.IO.Class (MonadIO, liftIO)
import Colog (Message, WithLog, cmap, fmtMessage, logDebug, logInfo, logTextStdout, logWarning,
usingLoggerT)
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:

## More Tutorials
To provide a more user-friendly introduction to the library, we've
created the tutorial series which introduces the main concepts behind `co-log`
smoothly, please [check more details here](./tutorials/README.md).
[hk-img]: https://img.shields.io/hackage/v/co-log.svg?logo=haskell
[hk-img-ps]: https://img.shields.io/hackage/v/co-log-polysemy.svg?logo=haskell
[hk-img-core]: https://img.shields.io/hackage/v/co-log-core.svg?logo=haskell
[hk]: https://hackage.haskell.org/package/co-log
[hk-ps]: https://hackage.haskell.org/package/co-log-polysemy
[hk-core]: https://hackage.haskell.org/package/co-log-core