In this recipe we will use [Sentry](https://sentry.io) to collect the runtime exceptions generated by our application. We will use the [raven-haskell](https://hackage.haskell.org/package/raven-haskell) package, which is a client for a Sentry event server. Mind that this package is not present on [Stackage](https://www.stackage.org/), so if we are using [Stack](https://docs.haskellstack.org) we’ll need to add it to our `extra-deps` section in the `stack.yaml` file.
To exemplify this we will need the following imports
Just for the sake of the example we will use the following API which will throw an exception
```haskell
type API = "break" :> Get '[JSON] ()
data MyException = MyException deriving (Show)
instance Exception MyException
server = breakHandler
where breakHandler :: Handler ()
breakHandler = do
throw MyException
return ()
```
First thing we need to do if we want to intercept and log this exception, we need to look in the section of our code where we run the `warp` application, and instead of using the simple `run` function from `warp`, we use the `runSettings` functions which allows to customise the handling of requests
```haskell
main :: IO ()
main =
let
settings =
setPort 8080 $
setOnException sentryOnException $
defaultSettings
in
runSettings settings $ serve (Proxy :: Proxy API) server
```
The definition of the `sentryOnException` function could look as follows
It does three things. First it initializes the service which will communicate with Sentry. The parameters it receives are:
- the Sentry `DSN`, which is obtained when creating a new project on Sentry
- a default way to update sentry fields, where we use the identity function
- an event trasport, which generally would be `sendRecord`, an HTTPS capable trasport which uses http-conduit
- a fallback handler, which we choose to be `silentFallback` since later we are logging to the console anyway.
In the second step it actually sends our message to Sentry with the `register` function. Its arguments are:
- the configured Sentry service which we just created
- the name of the logger
- the error level (see [SentryLevel](https://hackage.haskell.org/package/raven-haskell-0.1.2.0/docs/System-Log-Raven-Types.html#t:SentryLevel) for the possible options)
- the message we want to send
- an update function to handle the specific `SentryRecord`
Eventually it just delegates the error handling to the default warp mechanism.
The function `formatMessage` simply uses the request and the exception to return a string with the error message.
The only piece left now is the `recordUpdate` function which allows to decorate with other [attributes](https://docs.sentry.io/clientdev/attributes/) the default `SentryRecord`.
In this examples we set the raw path as the culprit and we use the `Host` header to populate the server name field.
You can try to run this code using the `cookbook-sentry` executable. You should obtain a `MyException` error in the console and, if you provided a valid Sentry DSN, you should also find your error in the Sentry interface.