-
Notifications
You must be signed in to change notification settings - Fork 568
Open
Description
How do you use Sentry?
Self-hosted/on-premise
Version
2.43.0
Steps to Reproduce
Some of our exception define properties message and detail. The formatting of error message for those exceptions is almost always incorrect (doesn't contain important information, not formatted properly) or sometimes even fails. There is a couple of such exceptions in simplified form:
class GRpcError(Exception):
def __init__(self, code: int, message: bytes) -> None:
super().__init__(code, message)
self.code = code
# Original protobuf message to allow its inspection in error handlers.
# Here we use bytes, but it can be `google.protobuf.message.Message`
# instance as well.
self.message = message
def __str__(self) -> str:
return f"code={self.code}"
class ApiError(Exception):
def __init__(self, code: str, detail: dict[str, Any]) -> None:
super().__init__(code, detail)
self.code = code
self.detail = detail
def __str__(self) -> str:
formatted = f"[{self.code}]"
for key, value in self.detail.items():
formatted += f"\n {key}={value}"
return formattedExpected Result
Here is how they are formatted by Python itself:
grpc_exc = GRpcError(13, b"unreadable protobuf message")
print("".join(traceback.format_exception_only(grpc_exc)).strip())
# GRpcError: code=13
grpc_exc.add_note("additional context note")
print("".join(traceback.format_exception_only(grpc_exc)).strip())
# GRpcError: code=13
# additional context note
api_exc = ApiError("RATE_LIMIT_EXCEEDED", detail={"retry_after": 30})
print("".join(traceback.format_exception_only(api_exc)).strip())
# ApiError: [RATE_LIMIT_EXCEEDED]
# retry_after=30
api_exc.add_note("additional context note")
print("".join(traceback.format_exception_only(api_exc)).strip())
# ApiError: [RATE_LIMIT_EXCEEDED]
# retry_after=30
# additional context noteActual Result
And the formatting by sentry (get_error_message is used internally by event_from_exception, here I call it directly):
grpc_exc = GRpcError(13, b"unreadable protobuf message")
print(sentry_sdk.utils.get_error_message(grpc_exc))
# No `code` field, only unreadable field in the result:
# b'unreadable protobuf message'
grpc_exc.add_note("additional context note")
print(sentry_sdk.utils.get_error_message(grpc_exc))
# Fails with the error:
# TypeError: can't concat str to bytes
api_exc = ApiError("RATE_LIMIT_EXCEEDED", detail={"retry_after": 30})
print(sentry_sdk.utils.get_error_message(api_exc))
# No `code` field, `detail` is not formatted:
# {'retry_after': 30}
api_exc.add_note("additional context note")
print(sentry_sdk.utils.get_error_message(api_exc))
# Fails with the error:
# TypeError: unsupported operand type(s) for +=: 'dict' and 'str'nikitagashkov
Metadata
Metadata
Assignees
Projects
Status
Waiting for: Product Owner