packages feed

unclogging-0.1.0.1: src/Unclog/Render.hs

-- | functions for different ways of rendering log entries to bytestring builders
module Unclog.Render
  ( -- * rendering to bytestring builders

    -- ** default builders
    simpleBuilder
  , colouredBuilder

    -- ** helpers
  , builderWithFn
  , renderLevel
  , renderLocation
  , colourLevel
  , bracketBuilder
  )
where

import Chronos (SubsecondPrecision (SubsecondPrecisionFixed), builderUtf8_YmdHMS, timeToDatetime, w3c)
import Colourista.Pure (blue, formatWith, green, red, yellow)
import Data.ByteString.Builder qualified as BS
import Data.List qualified as List
import Data.Text.Encoding qualified as T
import Unclog.Common

-- | a simple, non-coloured builder which takes all of the information into account
simpleBuilder :: LogEntry -> BS.Builder
simpleBuilder = builderWithFn id

-- |  a simple, coloured builder which takes all information into account but also makes it colourful
colouredBuilder :: LogEntry -> BS.Builder
colouredBuilder entry = builderWithFn (colourLevel entry.level) entry

builderWithFn :: (BS.Builder -> BS.Builder) -> LogEntry -> BS.Builder
builderWithFn fn entry =
  mconcat
    [ fn $ bracketBuilder $ renderLevel entry.level
    , bracketBuilder $ builderUtf8_YmdHMS (SubsecondPrecisionFixed 0) w3c (timeToDatetime entry.timestamp)
    , bracketBuilder $ renderLocation entry.location
    , BS.charUtf8 ' '
    , BS.byteString entry.payload
    , BS.charUtf8 '\n'
    ]

-- | surround a builder with brackets
bracketBuilder :: BS.Builder -> BS.Builder
bracketBuilder a = BS.charUtf8 '[' <> a <> BS.charUtf8 ']'

-- | render the log level with even spacing
renderLevel :: LogLevel -> BS.Builder
renderLevel = \case
  Debug -> "Debug"
  Info -> "Info "
  Warn -> "Warn "
  Fatal -> "Fatal"

-- | colour a builder according to the loglevel
colourLevel :: LogLevel -> BS.Builder -> BS.Builder
colourLevel =
  formatWith . \case
    Debug -> [blue]
    Info -> [green]
    Warn -> [yellow]
    Fatal -> [red]

-- | render a source location
renderLocation :: Location -> BS.Builder
renderLocation MkLocation {locpkg, locmod, locpos = MkPosition {posLeft, posRight}} =
  mconcat $
    List.intersperse
      (BS.charUtf8 ':')
      [ T.encodeUtf8Builder locpkg
      , T.encodeUtf8Builder locmod
      , BS.intDec posLeft
      , BS.intDec posRight
      ]