-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support annotated-exception
#76
Comments
I had this exact same thought when I saw your tweet. Happy to look at any PR you create, or I'll try to spend some time on this soon. Beware, there's a rewrite brewing in #75, so depending on how invasive this would be it might be better to wait. If it's just a small tweak in the report step it's probably OK to do sooner and port into the rewrite branch though. |
Oh, nice! Well, the "easy" thing is to add a new function that accepts an A deeper integration could do more clever things, but that can wait until I've got more ideas to hash out. |
Hmm, that use-case implies you are trying to catch an f `catch` notifyBugsnagWith myBeforeNotify settings
myBeforeNotify :: BeforeNotify
myBeforeNotify = updateEventFromOriginalException asAnnotatedException
asAnnotatedException :: AnnotatedException ex -> BeforeNotify
asAnnotatedException = -- what you want What I was picturing was somehow using But I'm now thinking that's not possible -- a user will still have to add the catch-and-rethrow gate required for any annotations to exist. At that point, they might as well do the 🤔 |
Oh, nice, that makes sense! Thanks 😄 Yeah, we can't retroactively grab a |
Closing this since the idea is possible through existing interfaces. Please let me know if that's not the case. |
OK, so I think it might be worthwhile to support it directly, but I am not sure the best way to do so. I'm building this stuff out now at work, and we've got something like: class BugsnagAnnotation ann where
annotationToBeforeNotify :: ann -> BeforeNotify At reporting sites, we're calling: reportAnnotated (Annotated anns e) =
notifyBugsnagWith (foldr (.) id $ map annotationToBeforeNotify anns) bugsnagSettings (toException e) I've been made aware that we can actually touch the original exception, so I have another thing that's called in our Bugsnag initialization: addAnnotationsFromAnnotatedException :: BugsnagEvent -> BugsnagEvent
addAnnotationsFromAnnotatedException =
updateEventFromOriginalException $ \(AnnotatedException anns exn) event ->
(annotationsToBugsnagModifier anns event)
{ beException =
(beException event)
{ beOriginalException =
Just exn
}
} The trick at play here is that we have a special sub-annotation data MercuryAnnotation where
MercuryAnnotation :: BugsnagAnnotation ann => ann -> MercuryAnnotation
mercuryCheckpoint :: (MercuryAnnotation ann) => ann -> m a -> m a
mercuryCheckpoint ann = checkpoint (Annotation (MercuryAnnotation ann)) Then our handling code separates our annotations into known and unknown: import Data.Annotation (tryAnnotations)
separateAnnotations :: [Annotation] -> ([MercuryAnnotation], [Annotation])
separateAnnotations anns =
tryAnnotations anns And then we get our special handling on the So, here's a problem. If we have done
fromException' :: Exception e => SomeException -> Maybe e
fromException' exn = asum
[ fromException exn
, do
AnnotatedException _ e <- fromException exn
pure e
] Then we don't have to worry about this. So, |
Hmm, when I see, fromException' :: Exception e => SomeException -> Maybe e
fromException' exn = asum
[ fromException exn
, do
AnnotatedException _ e <- fromException exn
pure e
] I can't tell why that's substantially better than having a before-notify that calls
I'm probably misunderstanding, but when I read this ^ I think the solution is pretty easy: myBeforeNotify =
updateEventFromOriginalException asMyException
+ . updateEventFromOriginalException asAnnotatedMyException ?
I'm not against adding direct support on principle, but I do generally feel that if something can be accomplished on top of a library through the interfaces it already exposes, there's little downside to making a separate package on top. I recently deprecated the monolithic That said, if WDYT? |
Yeah, that's exactly what I've settled on 😄 stripAnnotatedException =
updateEventFromOriginalException $ \case
AnnotatedException anns e ->
addAnnotationsToEvent anns . updateException (setOriginalException e) We've also got a myCheckpoint :: (ExceptionAnnotation ann, MonadUnliftIO m, MonadBugsnag m) => ann -> m a -> m a
myCheckpoint ann =
localBugsnagSettings (\bs -> bs { bsBeforeNotify = annToBeforeNotify ann . bsBeforeNotify bs })
. checkpoint (Annotation (OurAnnotation ann)) Which ensures that exceptions that are reported inside the |
Your and my (at Freckle) usages of this library are converging. We do See #65 ;) |
I'm re-opening this as Freckle has started using annotated-exceptions and run into a few edge-cases with Bugsnag. I was incorrect originally that this could be entirely handled from the outside, as at least /cc @chris-martin . |
@pbrisbin - I believe I've broken the uses of updateEventFromOriginalException. I had it in mind to apply the fix in freckle-app here, but could push the fix further up if you'd like. (Perhaps at a later time.) @parsonsmatt - I just wrote a little utility for this that might be nice for import Control.Applicative ((<|>))
import Control.Exception.Annotated
import Data.Function (($))
import Data.Functor ((<$>))
import Data.Maybe (Maybe (..))
-- | Like 'fromException', but matches both @e@ and @'AnnotatedException' e@
--
-- If the exception type is @e@, the value returned is an 'AnnotatedException'
-- with no annotations.
fromExceptionAnnotated
:: forall e. Exception e => SomeException -> Maybe (AnnotatedException e)
fromExceptionAnnotated e = annotated <|> notAnnotated
where
annotated = fromException @(AnnotatedException e) $ toException e
notAnnotated =
(\e' -> AnnotatedException {exception = e', annotations = []})
<$> fromException @e (toException e) (edit) Oh nevermind I just noticed you already wrote just about the same thing above! |
Part of the Magic of
The other half of the magic is the definitions of The main problem with the library is that Control.Exception.try @MyException do
Control.Exception.Annotated.throw MyException then the Control.Exception.try @(AnnotatedException MyException) do
Control.Exception.throwIO MyException Because the |
Looking over the work in freckle-app and just want to capture some notes here. I think there are two things happening over there that we could provide automatically from here instead,
|
Ahh okay, I didn't notice that this happens in the instance, cool. I can simplify a little then. |
He's saying keep using the |
Ah yes. I think I get it now. |
@chris-martin I know you've done some work here, is this Issue well enough addressed to be closed? Are there any gaps left in using Bugsnag and annotated-exception together? |
I just released a package
annotated-exception
which can be used to add things like aCallStack
(and other info) to an exception transparently.Integrating this into
bugsnag-haskell
at thereportException
level could be useful to add some of this additional data.Alternatively, we could expose a function that accepts the
[Caster]
, so end-users could write a conversion function forLocatedException e -> BugsnagException
.The text was updated successfully, but these errors were encountered: