module Blammo.Logging.Setup
  ( HasLogger (..)
  , withLogger
  , newLogger
  , runLoggerLoggingT
  , LoggingT
  , WithLogger (..)
  , runWithLogger
  , newLoggerEnv
  , withLoggerEnv
  , runSimpleLoggingT
  ) where

import Prelude

import Blammo.Logging
import qualified Blammo.Logging.LogSettings.Env as Env
import Blammo.Logging.Logger
import Blammo.Logging.WithLogger
import Control.Lens (view)
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.IO.Unlift (MonadUnliftIO)
import Control.Monad.Logger.Aeson
import UnliftIO.Exception (finally)

-- | Construct a 'Logger' configured via environment variables
newLoggerEnv :: MonadIO m => m Logger
newLoggerEnv :: forall (m :: * -> *). MonadIO m => m Logger
newLoggerEnv = IO Logger -> m Logger
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO Logger -> m Logger) -> IO Logger -> m Logger
forall a b. (a -> b) -> a -> b
$ LogSettings -> IO Logger
forall (m :: * -> *). MonadIO m => LogSettings -> m Logger
newLogger (LogSettings -> IO Logger) -> IO LogSettings -> IO Logger
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IO LogSettings
Env.parse

-- | Initialize logging (configured via environment variables),
--   pass a 'Logger' to the callback, and clean up at the end
--
-- Applications should avoid calling this more than once in their lifecycle.
withLoggerEnv :: MonadUnliftIO m => (Logger -> m a) -> m a
withLoggerEnv :: forall (m :: * -> *) a. MonadUnliftIO m => (Logger -> m a) -> m a
withLoggerEnv Logger -> m a
f = IO LogSettings -> m LogSettings
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO LogSettings
Env.parse m LogSettings -> (LogSettings -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \LogSettings
logger -> LogSettings -> (Logger -> m a) -> m a
forall (m :: * -> *) a.
MonadUnliftIO m =>
LogSettings -> (Logger -> m a) -> m a
withLogger LogSettings
logger Logger -> m a
f

-- | Construct a 'Logger' configured via environment variables and use it
runSimpleLoggingT :: MonadUnliftIO m => LoggingT m a -> m a
runSimpleLoggingT :: forall (m :: * -> *) a. MonadUnliftIO m => LoggingT m a -> m a
runSimpleLoggingT LoggingT m a
f = do
  Logger
logger <- m Logger
forall (m :: * -> *). MonadIO m => m Logger
newLoggerEnv
  Logger -> LoggingT m a -> m a
forall (m :: * -> *) env a.
(MonadUnliftIO m, HasLogger env) =>
env -> LoggingT m a -> m a
runLoggerLoggingT Logger
logger LoggingT m a
f

-- | Initialize logging, pass a 'Logger' to the callback, and clean up at the end
--
-- Applications should avoid calling this more than once in their lifecycle.
runLoggerLoggingT
  :: (MonadUnliftIO m, HasLogger env) => env -> LoggingT m a -> m a
runLoggerLoggingT :: forall (m :: * -> *) env a.
(MonadUnliftIO m, HasLogger env) =>
env -> LoggingT m a -> m a
runLoggerLoggingT env
env LoggingT m a
f =
  LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
forall (m :: * -> *) a.
LoggingT m a
-> (Loc -> LogSource -> LogLevel -> LogStr -> IO ()) -> m a
runLoggingT LoggingT m a
f (Logger -> Loc -> LogSource -> LogLevel -> LogStr -> IO ()
forall (m :: * -> *) msg.
(MonadIO m, ToLogStr msg) =>
Logger -> Loc -> LogSource -> LogLevel -> msg -> m ()
runLogAction Logger
logger) m a -> m () -> m a
forall (m :: * -> *) a b. MonadUnliftIO m => m a -> m b -> m a
`finally` Logger -> m ()
forall (m :: * -> *). MonadIO m => Logger -> m ()
flushLogStr Logger
logger
 where
  logger :: Logger
logger = Getting Logger env Logger -> env -> Logger
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Logger env Logger
forall env. HasLogger env => Lens' env Logger
Lens' env Logger
loggerL env
env