Skip to content

Commit 36318d6

Browse files
Ravelinearybczak
andauthored
[CORE-7914] Log an unhandled exception or a user abort before the computation ends (#97)
* [CORE-7914] Log an unhandled exception or a user abort before the computation ends * Apply PR suggestions * [EXPERIMENT] Try with catch * Trying something * Have a dedicated runner that logs on exception * Retrying with MonadMask * Use MonadBaseControl IO * Apply PR suggestions * Bump version and update changelog * Provide exceptions logging as a function Rather than patching runLogT directly, add a composable utility * Apply PR suggestions * Add missing dots * Change error to exception * fix changelog --------- Co-authored-by: Andrzej Rybczak <[email protected]>
1 parent 7d51f52 commit 36318d6

File tree

3 files changed

+24
-1
lines changed

3 files changed

+24
-1
lines changed

log-base/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# log-base-0.12.1.0 (2025-??-??)
2+
* Add utility function to log unhandled exceptions.
3+
14
# log-base-0.12.0.1 (2023-03-14)
25
* Add support for GHC 9.6.
36

log-base/log-base.cabal

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cabal-version: 3.0
22
name: log-base
3-
version: 0.12.0.1
3+
version: 0.12.1.0
44
synopsis: Structured logging solution (base package)
55

66
description: A library that provides a way to record structured log

log-base/src/Log/Monad.hs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module Log.Monad (
66
, InnerLogT
77
, LogT(..)
88
, runLogT
9+
, logExceptions
910
, mapLogT
1011
, logMessageIO
1112
, getLoggerIO
@@ -67,6 +68,25 @@ runLogT component logger maxLogLevel m = runReaderT (unLogT m) LoggerEnv {
6768
} -- We can't do synchronisation here, since 'runLogT' can be invoked
6869
-- quite often from the application (e.g. on every request).
6970

71+
-- | Ensure uncaught exceptions get logged.
72+
-- Convenient to compose right after `runLogT` so any exception
73+
-- will show up.
74+
logExceptions :: (MonadBaseControl IO m, MonadLog m) => m a -> m a
75+
logExceptions f =
76+
liftedCatch f $ \(SomeException e) -> do
77+
logAttention "Uncaught exception" $ object ["exception" .= show e]
78+
liftBase $ E.throwIO e
79+
80+
-- Generalized version of catch taken from `lifted-base`.
81+
liftedCatch :: (MonadBaseControl IO m, Exception e)
82+
=> m a -- ^ The computation to run.
83+
-> (e -> m a) -- ^ Handler to invoke if an exception is raised.
84+
-> m a
85+
liftedCatch a handler = control $ \runInIO ->
86+
E.catch
87+
(runInIO a)
88+
(runInIO . handler)
89+
7090
-- | Transform the computation inside a 'LogT'.
7191
mapLogT :: (m a -> n b) -> LogT m a -> LogT n b
7292
mapLogT f = LogT . mapReaderT f . unLogT

0 commit comments

Comments
 (0)