packages feed

polysemy-log-0.2.2.0: lib/Polysemy/Log/Format.hs

-- |Description: Formatting helpers
module Polysemy.Log.Format where

import qualified Data.Text as Text
import GHC.Exception (SrcLoc(..))
import System.Console.ANSI (Color(..), ColorIntensity(Dull), ConsoleLayer(Foreground), SGR (..), setSGRCode)

import Polysemy.Log.Data.LogEntry (LogEntry(LogEntry))
import qualified Polysemy.Log.Data.LogMessage as LogMessage
import Polysemy.Log.Data.LogMessage (LogMessage(LogMessage))
import Polysemy.Log.Data.Severity (Severity(..))

-- |Create a colored tag with the format @"[tag]"@ for a 'Severity' value.
formatSeverity :: Severity -> Text
formatSeverity = \case
  Trace -> "[trace]"
  Debug -> color Green "[debug]"
  Info -> color Blue "[info] "
  Warn -> color Yellow "[warn] "
  Error -> color Red "[error]"
  Crit -> color Magenta "[crit] "
 where
   color c txt =
     toText (setSGRCode [SetColor Foreground Dull c]) <>
     txt <>
     toText (setSGRCode [Reset])

-- |Turn a module string like @Foo.Bar.Baz@ into an abbreviated @F.B.Baz@.
shortModule :: Text -> Text
shortModule =
  spin . Text.splitOn "."
  where
    spin = \case
      [] -> ""
      [m] -> m
      h : t -> Text.take 1 h <> "." <> spin t

-- |Format a call stack's top element as @"F.B.Baz#32"@ with the line number.
formatCaller :: CallStack -> Text
formatCaller =
  maybe "<unknown loc>" format . listToMaybe . getCallStack
  where
    format (_, SrcLoc {..}) =
      [qt|#{shortModule (toText srcLocModule)}\##{srcLocStartLine}|]

-- |Default formatter for the default message type.
formatLogEntry :: LogEntry LogMessage -> Text
formatLogEntry (LogEntry LogMessage {..} _ source) =
  [qt|#{formatSeverity severity} [#{formatCaller source}] #{message}|]