content: # co-log
  
  <img align="left" width="180" height="180" src="https://user-images.githubusercontent.com/8126674/80955687-92f21a80-8df7-11ea-90d3-422dafdc8391.png">
  
  [![GitHub CI](https://github.com/co-log/co-log/workflows/CI/badge.svg)](https://github.com/co-log/co-log/actions)
  [![MPL-2.0 license](https://img.shields.io/badge/license-MPL--2.0-blue.svg)](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:
  
  ![screenshot from 2018-09-17 20-52-01](https://user-images.githubusercontent.com/4276606/45623973-8bafb900-babb-11e8-9e20-4369a5a8e5ff.png)
  
  ## 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
  