Skip to content
Merged
3 changes: 3 additions & 0 deletions log-base/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# log-base-0.12.1.0 (2025-??-??)
* Add utility function to log unhandled exceptions.

# log-base-0.12.0.1 (2023-03-14)
* Add support for GHC 9.6.

Expand Down
2 changes: 1 addition & 1 deletion log-base/log-base.cabal
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cabal-version: 3.0
name: log-base
version: 0.12.0.1
version: 0.12.1.0
synopsis: Structured logging solution (base package)

description: A library that provides a way to record structured log
Expand Down
20 changes: 20 additions & 0 deletions log-base/src/Log/Monad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Log.Monad (
, InnerLogT
, LogT(..)
, runLogT
, logExceptions
, mapLogT
, logMessageIO
, getLoggerIO
Expand Down Expand Up @@ -67,6 +68,25 @@ runLogT component logger maxLogLevel m = runReaderT (unLogT m) LoggerEnv {
} -- We can't do synchronisation here, since 'runLogT' can be invoked
-- quite often from the application (e.g. on every request).

-- | Ensure uncaught exceptions get logged.
-- Convenient to compose right after `runLogT` so any exception
-- will show up.
logExceptions :: (MonadBaseControl IO m, MonadLog m) => m a -> m a
logExceptions f =
liftedCatch f $ \(SomeException e) -> do
logAttention "Uncaught exception" $ object ["exception" .= show e]
liftBase $ E.throwIO e

-- Generalized version of catch taken from `lifted-base`.
liftedCatch :: (MonadBaseControl IO m, Exception e)
=> m a -- ^ The computation to run.
-> (e -> m a) -- ^ Handler to invoke if an exception is raised.
-> m a
liftedCatch a handler = control $ \runInIO ->
E.catch
(runInIO a)
(runInIO . handler)

-- | Transform the computation inside a 'LogT'.
mapLogT :: (m a -> n b) -> LogT m a -> LogT n b
mapLogT f = LogT . mapReaderT f . unLogT
Expand Down