packages feed

plow-log-0.1.6.0: src/Plow/Logging/Message.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}

module Plow.Logging.Message
  ( LogLevel (..),
    LogMessage (..),
  )
where

import Data.Aeson (FromJSON (parseJSON), ToJSON, withText)
import Data.Text (Text)
import qualified Data.Text as Text
import GHC.Generics (Generic)
import Plow.Logging (HasEnumerableConstructors)

-- | Generic log levels
data LogLevel = LevelDebug | LevelInfo | LevelWarn | LevelError | LevelOther Text
  deriving (Eq, Ord, Generic, HasEnumerableConstructors, ToJSON)

instance Show LogLevel where
  show LevelDebug = "DEBUG"
  show LevelInfo = "INFO"
  show LevelWarn = "WARN"
  show LevelError = "ERROR"
  show (LevelOther l) = Text.unpack l

instance FromJSON LogLevel where
  parseJSON = withText "LogLevel" $ \case
    "DEBUG" -> pure LevelDebug
    "INFO" -> pure LevelInfo
    "WARN" -> pure LevelWarn
    "ERROR" -> pure LevelError
    other -> pure $ LevelOther other

-- | A log message that allows for a log level to be specified or for the log
-- to be ignored.
data LogMessage a
  = Stdout LogLevel a
  | Ignore
  deriving (Show, Generic, HasEnumerableConstructors)

-- | Concatenates two log messages with a newline, keeping the log level of that has the higher severity
instance (Semigroup String) => Semigroup (LogMessage String) where
  a <> b = case (a, b) of
    (Stdout logLevelA a', Stdout logLevelB b') -> Stdout (max logLevelA logLevelB) (a' <> "\n" <> b')
    (Stdout logLevelA a', Ignore) -> Stdout logLevelA a'
    (Ignore, Stdout logLevelB b') -> Stdout logLevelB b'
    (Ignore, Ignore) -> Ignore