packages feed

log-effectful-1.0.0.0: src/Effectful/Log.hs

{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Logging via 'MonadLog'.
module Effectful.Log
  ( -- * Effect
    Log

    -- ** Handlers
  , runLog

    -- * Re-exports
  , module Log
  ) where

import Data.Text (Text)
import Data.Time.Clock
import Effectful.Dispatch.Static
import Effectful
import Log

-- | Provide the ability to log messages via 'MonadLog'.
data Log :: Effect

type instance DispatchOf Log = Static WithSideEffects
newtype instance StaticRep Log = Log LoggerEnv

-- | Run the 'Log' effect.
--
-- /Note:/ this is the @effectful@ version of 'runLogT'.
runLog
  :: IOE :> es
  => Text
  -- ^ Application component name to use.
  -> Logger
  -- ^ The logging back-end to use.
  -> LogLevel
  -- ^ The maximum log level allowed to be logged.
  -> Eff (Log : es) a
  -- ^ The computation to run.
  -> Eff es a
runLog component logger maxLogLevel = evalStaticRep $ Log LoggerEnv
  { leLogger = logger
  , leComponent = component
  , leDomain = []
  , leData = []
  , leMaxLogLevel = maxLogLevel
  }

-- | Orphan, canonical instance.
instance Log :> es => MonadLog (Eff es) where
  logMessage level message data_ = do
    time <- unsafeEff_ getCurrentTime
    Log logEnv <- getStaticRep
    unsafeEff_ $ logMessageIO logEnv time level message data_

  localData data_ = localStaticRep $ \(Log logEnv) ->
    Log logEnv { leData = data_ ++ leData logEnv }

  localDomain domain = localStaticRep $ \(Log logEnv) ->
    Log logEnv { leDomain = leDomain logEnv ++ [domain] }

  localMaxLogLevel level = localStaticRep $ \(Log logEnv) ->
    Log logEnv { leMaxLogLevel = level }

  getLoggerEnv = do
    Log env <- getStaticRep
    pure env