Safe Haskell | None |
---|---|
Language | Haskell2010 |
Customize uncaught exception handler.
When any thread of your Haskell application throws an exception
that does not get caught explicitly, the Haskell runtime system will
handle it and print based on the Show
instance (by default). This
behavior can be customized using the setUncaughtExceptionHandler
function. However, implementing your own uncaught exception handler
sounds like a tricky task because you should keep a bunch of things
in mind:
- You should flush stdout.
- You should print output to stderr rather than stdout.
- You should take care of the exit code of your application and the
ExitCode
data type.
The aim of this module is to handle all these concerns and provide
easy-to-use functions that capture common cases when you want to
modify behavior of the default uncaught exception handler.
Currently we consider only one case: using displayException
instead
of the Show
methods. It's debatable whether displayException
is
more appropriate to print uncaught exceptions. Even though
displayException
is not used by default, we believe there are cases
when it makes sense to use it for printing.
We intentionally provide more than one implementation with similar types and semantics. We expect that over time these functions will be better tested and some feedback will be gathered that will let us figure out which approach is better.
Synopsis
- displayUncaughtException :: IO a -> IO a
- withDisplayExceptionHandler :: IO a -> IO a
- setDisplayExceptionHandler :: IO ()
- newtype DisplayExceptionInShow = DisplayExceptionInShow SomeException
- wrapException :: SomeException -> SomeException
Documentation
displayUncaughtException :: IO a -> IO a Source #
Customise default uncaught exception handling to use
displayException
instead of show
. This function is supposed to
be applied to the body of main
. Note that it only affects exceptions
in the current thread, other threads are not affected.
It is adviced to use the async
package that propagates exceptions
from the child thread to the parent thread.
It works by catching all exceptions and wrapping them into
a wrapper data type whose show
method uses displayException
.
The wrapped exception is re-thrown and the default exception
handler will handle it. displayException
will be used for printing
because that's how show
of the wrapper data type is implemented.
Some exceptions are not wrapped:
ExitCode
exception because it's treated specially and affects exit code of the application. If we catchExitSuccess
, wrap it into another data type and re-throw, the program will end with non-zero code which is not desirable.- Asynchronous exceptions. There are not many of them and applying
displayException
to them usually does not give big benefit. However, some of them may be handled somewhat specially by the runtime system and we don't want to mess up with that. We recognize asynchronous exceptions by casting toSomeAsyncException
the same way as thesafe-exceptions
library.
withDisplayExceptionHandler :: IO a -> IO a Source #
Customise default uncaught exception handling to use
displayException
instead of show
. This function is supposed to
be applied to the body of main
.
It works similarly to displayUncaughtException
, but instead of
catching and throwing exceptions it modifies the uncaught exception
handler to wrap the exception before processing it.
As a consequence, it affects all threads.
When the action finishes, the uncaught exception handler
is restored (normally it should not matter because the function is
supposed to be applied to the whole main
).
Note that it may cause race condition if the passed action spawns another
thread that throws an uncaught exception when the passed action stops.
There is a global variable that stores the uncaught exception handler.
Hence it's recommended to use functions from the async
package to spawn
threads, so that they are stopped before their parent.
The handler won't be restored in case of exception thrown by the passed action
because otherwise it wouldn't work.
Specifically, if we restored the handler in case of
exception (e. g. using bracket
), it would be restored before the
uncaught exception handler would be called (because the uncaught
exception handler is called after everything).
setDisplayExceptionHandler :: IO () Source #
A version of withDisplayExceptionHandler
that updates the handler forever.
The only difference is that it doesn't restore the default handler.
This function should give more predictable behavior in case there are
multiple threads.
Exported just in case you want to do something special
newtype DisplayExceptionInShow Source #
Helper data type used by displayUncaughtException
.
It causes show
to call displayException
.
When an exception of this type is caught, it will be show
n and
that will call displayException
of the wrapped exception.
Instances
Show DisplayExceptionInShow Source # | |
Defined in Control.Exception.Uncaught showsPrec :: Int -> DisplayExceptionInShow -> ShowS # show :: DisplayExceptionInShow -> String # showList :: [DisplayExceptionInShow] -> ShowS # | |
Exception DisplayExceptionInShow Source # | |