Hi folks.
I’m using the python logging integration.
The way I like to define exceptions in python3 is to define a frozen dataclass for them, and have a couple fields of relevant data to be passed in. For example:
from dataclasses import dataclass
@dataclass(frozen=True)
class MyError(Exception):
error_code: int
magic_word: str
So an exception like that would be raised like:
if some_error_condition:
raise MyError(404, 'error not found')
and handled like:
try:
something_that_raises_as_above()
except MyError as exc:
logger.exception(exc)
So then I’d get an event in Sentry with the exception class as the main heading (I like this), but the ‘message’ section when I click into it just has the argument tuple:
(404, 'error_not_found')
What I want:
- the Exception class to define a property that composes a human-readable error message based on the fields. e.g. for the above exception, ‘Error code 404: event_not_found’
- the fields to appear as tags in Sentry
What I’ve tried:
I tried to find some documentation on how an exception object is converted into a Sentry message, but I was not successful.
I also defined a message
property on my error class to compose the human-readable message, and altered the capture line to
logger.exception(exc.message)
And that worked for the human-readable message bit. I’d prefer not to need to reach into the exception object in the logger.exception call though - I’d much prefer to define that in the exception class.
Hello @hoylemd, we run str(MyError())
on the exception to extract the message. I do not know what making the exception a dataclass does, but I suspect it reverts the default behavior of Exception.__str__
. I recommend overriding the __str__
method on your exception classes to return self.message
.
As for the extra info: You can pass extra
to logger.exception()
as per the stdlib documentation. This should allow you to write:
class MyError(...):
...
def __str__(self): return self.message
...
logging.exception(myerror, extra=myerror.__dict__)
I’m making the assumption that __dict__
actually exists on dataclasses but you get the idea.
Let me know if that works for you.
Thanks @untitaker! That’s really helpful.
I ended up finding solutions on my own as well, which I will post here for posterity:
-
Turns out I was using the old raven
sdk, which may have complicated things a bit, so I updated to the new sentry_sdk
package. I originally was integrating with logging by adding SentryHandler
to my logging config. After updating to sentry_sdk
, I switched to using the sentry_sdk.init
function to set up. This wasn’t too difficult in my case, as I was configuring loggers in a ‘setup’ python module instead of loading logging config from a file, but it could be a bit of a speed bump for others.
-
I was having an issue where the extra
info I passed in didn’t appear to make it onto a sentry event page anywhere. At some point I noticed it showing up in the ‘Additional info’ section though. It was probably there all along, but I wasn’t able to find any documentation pointing me there. I’m sure it is documented somewhere, and I can only speak from my own experience, but there might be a bit of a discoverability issue there.
Is there any chance that info on what the Sentry SDK does with an Exception object to compile an Event report could be added to the documentation? I’m imagining a section on the python logging integration page that maps the major parts of an Event page to the components of a logger call that define their content. Might be useful for other integration pages too. Alternatively if something like this already exists, I’d appreciate a link so I can bookmark it.
Thanks again for the helpful response!