Skip to content

BeforeNotify API is less powerful than before #80

@parsonsmatt

Description

@parsonsmatt

In bugsnag-haskell, a BugsnagEvent carried a BugsnagException which had a field beOriginalException, which would allow you to modify the original exception for further processing.

setOriginalException :: (Exception e) => e -> Bugsnag.Exception -> Bugsnag.Exception
setOriginalException e exn =
  exn
    { beOriginalException =
        Just (toException e)
    }

We use this to remove AnnotatedException wrapper and SomeAsyncException for reporting so that the next beforeNotify in the chain can work properly.

bugsnag-hs lacks this field entirely - upstream issue.

But, the BeforeNotify API was modified to account for this - now the function type is (forall e. Exception e => e -> Event -> Event) instead of Event -> Event. This means that the same e is passed to every BeforeNotify function, and a beforeNotiy can't modify that original e that is provided.

Well, that's probably fine - there's two ways to get the exception in processing. The SomeException on the event's exceptions, and the one that is passed in.

beforeNotify \originalException event -> 
    ... msum $ map exception_originalException (event_exceptions event) ...

Indeed I can even see an advantage to that, because you now have both the actual orginal exception, as well as the exception currently contained in the Bugsnag.Exception.


On a slightly unrelated note, the API around BeforeNotify is a bit awkward.

newtype BeforeNotify = BeforeNotify
    { _unBeforeNotify :: forall e. Exception.Exception e => e -> Event -> Event
    }

There's not really a lot you can do with a totally polymorphic Exception e => e ... - just show, toException, displayException. To do anything useful with it, you'd need to fromException . toException it.

I'd suggest replacing the polymorphic type with a SomeException. This would allow you to make beforeNotify a bit more friendly:

beforeNotify
    :: (SomeException -> Event -> Event)
    -> BeforeNotify
beforeNotify = BeforeNotify

And, if you want to make it only apply on a specific exception type, you can still do that:

beforeNotifyOnException
  :: forall e. Exception e
  => (e -> Event -> Event)
  -> BeforeNotify
beforeNotifyOnException k = 
  BeforeNotify \someException event ->
    fromMaybe event (\e -> k e event) (fromException someException)

(which is essentially how updateEventFromOriginalException is defined anyway - just one fewer toException call)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions