module Main (main) where import Relude import Blammo.Logging.Simple qualified as Blammo (runSimpleLoggingT) import Control.Monad.Logger ( Loc, LogLevel, LogSource, LogStr, MonadLogger (monadLoggerLog), MonadLoggerIO (askLoggerIO), ToLogStr (toLogStr), ) import Control.Monad.Logger.Aeson (Message ((:#)), (.=)) import Control.Monad.Logger.Aeson qualified as LoggerJson ( defaultOutput, logInfo, logWarn, ) import Control.Monad.Logger.CallStack qualified as Logger ( defaultOutput, logInfo, logWarn, ) type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO () data Item = Item { itemId :: Text , itemContents :: Text } fetchItem :: Text -> IO Item fetchItem _itemUrl = pure $ Item { itemId = "652412308" , itemContents = "

Hello world!

" } isInvalidItem :: Item -> Bool isInvalidItem _item = True processItem :: (MonadIO m) => Item -> m () processItem _item = pure () data AppEnv = AppEnv { appName :: Text , appItemUrl :: Text , appLogFunc :: LogFunc } newtype App a = App {unApp :: ReaderT AppEnv IO a} deriving newtype ( Functor , Applicative , Monad , MonadIO , MonadReader AppEnv ) instance MonadLogger App where monadLoggerLog loc logSource logLevel msg = do logFunc <- asks appLogFunc liftIO $ logFunc loc logSource logLevel (toLogStr msg) runApp :: AppEnv -> App a -> IO a runApp env action = runReaderT (unApp action) env actionPlain :: (MonadReader AppEnv m, MonadLogger m, MonadIO m) => m () actionPlain = do itemUrl <- asks appItemUrl Logger.logInfo $ "Fetching item: " <> "itemUrl=" <> itemUrl item <- liftIO $ fetchItem itemUrl if isInvalidItem item then Logger.logWarn $ "Skipping invalid item: " <> "itemUrl=" <> itemUrl <> " itemId=" <> itemId item else processItem item appPlain :: App () appPlain = do appName <- asks appName Logger.logInfo $ "App started: " <> "appName=" <> appName actionPlain actionJson :: (MonadReader AppEnv m, MonadLogger m, MonadIO m) => m () actionJson = do itemUrl <- asks appItemUrl LoggerJson.logInfo $ "Fetching item" :# ["itemUrl" .= itemUrl] item <- liftIO $ fetchItem itemUrl if isInvalidItem item then LoggerJson.logWarn $ "Skipping invalid item" :# [ "itemUrl" .= itemUrl , "itemId" .= itemId item ] else processItem item appJson :: App () appJson = do appName <- asks appName LoggerJson.logInfo $ "App started" :# ["appName" .= appName] actionJson mainPlain :: IO () mainPlain = do let logFunc = Logger.defaultOutput stdout appEnv = AppEnv { appName = "example-2a" , appItemUrl = "https://www.example.com/item" , appLogFunc = logFunc } runApp appEnv appPlain mainJson :: IO () mainJson = do let logFunc = LoggerJson.defaultOutput stdout appEnv = AppEnv { appName = "example-2b" , appItemUrl = "https://www.example.com/item" , appLogFunc = logFunc } runApp appEnv appJson getBlammoLogFunc :: IO LogFunc getBlammoLogFunc = Blammo.runSimpleLoggingT askLoggerIO mainBlammo :: IO () mainBlammo = do logFunc <- getBlammoLogFunc let appEnv = AppEnv { appName = "example-2c" , appItemUrl = "https://www.example.com/item" , appLogFunc = logFunc } runApp appEnv appJson main :: IO () main = do mainPlain putStrLn "" mainJson putStrLn "" mainBlammo