-
Notifications
You must be signed in to change notification settings - Fork 552
feat(loguru): Sentry logs for Loguru #4445
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
Changes from all commits
f992680
1be8d9a
3824524
96a0f2b
062de97
31b868d
1d74c18
f48d293
a15716e
0b15f29
a377c54
e66c0c2
ac6dd2d
b8bd5ef
88cb4d7
05ccc59
2c8be6c
fab0fba
a6b083b
1a35e02
f26fc8c
8397b10
e3670f9
eb8e5a4
fc2f1bd
cfac8d7
61f6395
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
|
||
import sentry_sdk | ||
from sentry_sdk.client import BaseClient | ||
from sentry_sdk.logger import _log_level_to_otel | ||
from sentry_sdk.utils import ( | ||
safe_repr, | ||
to_string, | ||
|
@@ -14,7 +15,7 @@ | |
) | ||
from sentry_sdk.integrations import Integration | ||
|
||
from typing import TYPE_CHECKING, Tuple | ||
from typing import TYPE_CHECKING | ||
|
||
if TYPE_CHECKING: | ||
from collections.abc import MutableMapping | ||
|
@@ -36,6 +37,16 @@ | |
logging.CRITICAL: "fatal", # CRITICAL is same as FATAL | ||
} | ||
|
||
# Map logging level numbers to corresponding OTel level numbers | ||
SEVERITY_TO_OTEL_SEVERITY = { | ||
logging.CRITICAL: 21, # fatal | ||
logging.ERROR: 17, # error | ||
logging.WARNING: 13, # warn | ||
logging.INFO: 9, # info | ||
logging.DEBUG: 5, # debug | ||
} | ||
|
||
|
||
# Capturing events from those loggers causes recursion errors. We cannot allow | ||
# the user to unconditionally create events from those loggers under any | ||
# circumstances. | ||
|
@@ -312,21 +323,6 @@ def _breadcrumb_from_record(self, record): | |
} | ||
|
||
|
||
def _python_level_to_otel(record_level): | ||
# type: (int) -> Tuple[int, str] | ||
for py_level, otel_severity_number, otel_severity_text in [ | ||
(50, 21, "fatal"), | ||
(40, 17, "error"), | ||
(30, 13, "warn"), | ||
(20, 9, "info"), | ||
(10, 5, "debug"), | ||
(5, 1, "trace"), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This |
||
]: | ||
if record_level >= py_level: | ||
return otel_severity_number, otel_severity_text | ||
return 0, "default" | ||
|
||
|
||
class SentryLogsHandler(_BaseHandler): | ||
""" | ||
A logging handler that records Sentry logs for each Python log record. | ||
|
@@ -352,7 +348,9 @@ def emit(self, record): | |
|
||
def _capture_log_from_record(self, client, record): | ||
# type: (BaseClient, LogRecord) -> None | ||
otel_severity_number, otel_severity_text = _python_level_to_otel(record.levelno) | ||
otel_severity_number, otel_severity_text = _log_level_to_otel( | ||
record.levelno, SEVERITY_TO_OTEL_SEVERITY | ||
) | ||
project_root = client.options["project_root"] | ||
attrs = self._extra_from_record(record) # type: Any | ||
attrs["sentry.origin"] = "auto.logger.log" | ||
|
@@ -363,10 +361,7 @@ def _capture_log_from_record(self, client, record): | |
for i, arg in enumerate(record.args): | ||
attrs[f"sentry.message.parameter.{i}"] = ( | ||
arg | ||
if isinstance(arg, str) | ||
or isinstance(arg, float) | ||
or isinstance(arg, int) | ||
or isinstance(arg, bool) | ||
if isinstance(arg, (str, float, int, bool)) | ||
else safe_repr(arg) | ||
sentrivana marked this conversation as resolved.
Show resolved
Hide resolved
|
||
) | ||
if record.lineno: | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -6,6 +6,17 @@ | |||||||||||||
from sentry_sdk import get_client | ||||||||||||||
from sentry_sdk.utils import safe_repr | ||||||||||||||
|
||||||||||||||
OTEL_RANGES = [ | ||||||||||||||
# ((severity level range), severity text) | ||||||||||||||
# https://opentelemetry.io/docs/specs/otel/logs/data-model | ||||||||||||||
((1, 4), "trace"), | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [optional suggestion] This is completely fine as is, but if you want, you could make all of these into ranges, then rather than manually checking if the severity number is in between the bounds, you would just check if it is in the range.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer to keep as is, since that way the ranges correspond to OTel levels exactly as they're written in code (i.e., you don't need to make the extra effort in your head to decrement the last number of each range by one to arrive at the actual range) |
||||||||||||||
((5, 8), "debug"), | ||||||||||||||
((9, 12), "info"), | ||||||||||||||
((13, 16), "warn"), | ||||||||||||||
((17, 20), "error"), | ||||||||||||||
((21, 24), "fatal"), | ||||||||||||||
] | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def _capture_log(severity_text, severity_number, template, **kwargs): | ||||||||||||||
# type: (str, int, str, **Any) -> None | ||||||||||||||
|
@@ -52,3 +63,21 @@ def _capture_log(severity_text, severity_number, template, **kwargs): | |||||||||||||
warning = functools.partial(_capture_log, "warn", 13) | ||||||||||||||
error = functools.partial(_capture_log, "error", 17) | ||||||||||||||
fatal = functools.partial(_capture_log, "fatal", 21) | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def _otel_severity_text(otel_severity_number): | ||||||||||||||
# type: (int) -> str | ||||||||||||||
for (lower, upper), severity in OTEL_RANGES: | ||||||||||||||
if lower <= otel_severity_number <= upper: | ||||||||||||||
return severity | ||||||||||||||
Comment on lines
+70
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you take my suggestion about ranges
Suggested change
|
||||||||||||||
|
||||||||||||||
return "default" | ||||||||||||||
|
||||||||||||||
|
||||||||||||||
def _log_level_to_otel(level, mapping): | ||||||||||||||
# type: (int, dict[Any, int]) -> tuple[int, str] | ||||||||||||||
for py_level, otel_severity_number in sorted(mapping.items(), reverse=True): | ||||||||||||||
if level >= py_level: | ||||||||||||||
return otel_severity_number, _otel_severity_text(otel_severity_number) | ||||||||||||||
|
||||||||||||||
return 0, "default" |
Uh oh!
There was an error while loading. Please reload this page.