content: # Message and LoggerT
  
  The previous tutorial shows how to use `LoggerT` with simple message.
  This tutorial will show you how to use LoggerT together with messages with more details(e.g. severity).
  
  You can run this tutorial by executing the following command:
  
  ```shell
  cabal new-run tutorial-loggert
  ```
  
  ## Preamble: imports and language extensions
  
  ```haskell
  {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE DerivingStrategies #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE FlexibleInstances #-}
  {-# LANGUAGE MultiParamTypeClasses #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# OPTIONS_GHC -Wno-unused-top-binds #-}
  
  module Main (main) where
  
  import Colog (
      LogAction,
      Message,
      Msg (..),
      WithLog,
      cmap,
      fmtMessage,
      formatWith,
      logError,
      logInfo,
      logTextStderr,
      logTextStdout,
      msgSeverity,
      msgText,
      richMessageAction,
      showSeverity,
      usingLoggerT,
   )
  
  import Data.Text (Text)
  import Prelude hiding (log)
  ```
  
  ## LoggerT
  
  The `LoggerT` monad transformer wraps a ReaderT that keeps `LogAction` in its context. It denotes a
  computation of logging. So you define your monadic actions with the `WithLog` constraint that allows you to perform logging.
  The `Message` allows you to log with severity.
  
  ```haskell
  example1 :: WithLog env Message m => m ()
  example1 = do
      logInfo "this is a demo log for message!"
  
  example2 :: WithLog env Message m => m ()
  example2 = do
      logError "Mayday! Mayday! Here is an example of error log\n"
  ```
  
  The `WithLog` constraint has three type parameters:
  
  - `env` – application environment
  - `msg` – type of the message
  - `m` – monad
  
  The actions constraint by `WithLog` could be used as `LoggerT`.
  
  ## Message
  
  The message is parametrized by the `Severity` type through `Msg`, which is a general logging message data type.
  
  ```idris
  type Message = Msg Severity
  data Msg sev = Msg
      { msgSeverity :: !sev
      , msgStack    :: !CallStack
      , msgText     ::  Text
      }
  ```
  
  Hence, besides printing the callstack, as the `LoggerT` with simple message tutorial shows, this example supports printing severity and thread id as well.
  
  ```haskell
  logStdoutAction :: LogAction IO Message
  logStdoutAction = cmap fmtMessage logTextStdout
  
  fmtMessageWithoutSourceLoc :: Message -> Text
  fmtMessageWithoutSourceLoc Msg{..} =
      showSeverity msgSeverity
          <> msgText
  
  logStdErrActionWithoutStackAction :: LogAction IO Message
  logStdErrActionWithoutStackAction = formatWith fmtMessageWithoutSourceLoc logTextStderr
  ```
  
  ## Running example
  
  Now we are ready to execute those actions defined above.
  
  ```haskell
  main :: IO ()
  main = do
      usingLoggerT logStdoutAction example1
      usingLoggerT logStdoutAction example2
      usingLoggerT logStdErrActionWithoutStackAction example1
      usingLoggerT logStdErrActionWithoutStackAction example2
      usingLoggerT richMessageAction example1
      usingLoggerT richMessageAction example2
  ```
  
  Run command `cabal new-run tutorial-loggert --flag=tutorial`, and the output will look like this:
  
  ![](../img/3-loggert-message.jpg)
  