{-# LANGUAGE OverloadedStrings, TypeSynonymInstances, FlexibleInstances, ExistentialQuantification, TypeFamilies, GeneralizedNewtypeDeriving, StandaloneDeriving, MultiParamTypeClasses, UndecidableInstances, AllowAmbiguousTypes, ScopedTypeVariables, FunctionalDependencies, FlexibleContexts, ConstraintKinds #-} -- | This module contains default implementation of @HasLogBackend@, -- @HasLogContext@, @HasLogger@ instances, based on @ReaderT@ - @LoggingT@ -- monad transformer. module System.Log.Heavy.LoggingT ( LoggingT (LoggingT), LoggingTState (..), runLoggingT ) where import Control.Monad.Reader import Control.Monad.Base import Control.Monad.Trans.Control import System.Log.Heavy.Types -- | State of @LoggingT@ monad data LoggingTState = LoggingTState { ltsLogger :: SpecializedLogger , ltsBackend :: AnyLogBackend , ltsContext :: LogContext } -- | Logging monad transformer. -- This is just a default implementation of @HasLogging@ interface. -- Applications are free to use this or another implementation. newtype LoggingT m a = LoggingT { runLoggingT_ :: ReaderT LoggingTState m a } deriving (Functor, Applicative, Monad, MonadReader LoggingTState, MonadTrans) deriving instance MonadIO m => MonadIO (LoggingT m) instance MonadIO m => MonadBase IO (LoggingT m) where liftBase = liftIO instance MonadTransControl LoggingT where type StT LoggingT a = StT (ReaderT LoggingTState) a liftWith = defaultLiftWith LoggingT runLoggingT_ restoreT = defaultRestoreT LoggingT instance (MonadBaseControl IO m, MonadIO m) => MonadBaseControl IO (LoggingT m) where type StM (LoggingT m) a = ComposeSt LoggingT m a liftBaseWith = defaultLiftBaseWith restoreM = defaultRestoreM instance Monad m => HasLogger (LoggingT m) where getLogger = asks ltsLogger localLogger l actions = LoggingT $ ReaderT $ \lts -> runReaderT (runLoggingT_ actions) $ lts {ltsLogger = l} instance (Monad m) => HasLogContext (LoggingT m) where getLogContext = asks ltsContext withLogContext frame actions = LoggingT $ ReaderT $ \lts -> runReaderT (runLoggingT_ actions) $ lts {ltsContext = frame: ltsContext lts} -- | Run logging monad runLoggingT :: LoggingT m a -> LoggingTState -> m a runLoggingT actions context = runReaderT (runLoggingT_ actions) context instance Monad m => HasLogBackend AnyLogBackend (LoggingT m) where getLogBackend = asks ltsBackend