Skip to content

Commit c927d34

Browse files
authored
Group captured warnings under separate issues (#1324)
Prior to https://bugs.python.org/issue46557 being addressed, warnings captured by logging.captureWarnings(True) were logged with logger.warning("%s", s) which caused them to be grouped under the same issue. This change adds special handling for creating separate issues for captured warnings arriving with the %s format string by using args[0] as the message instead of the msg arg.
1 parent 0c6241e commit c927d34

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

sentry_sdk/integrations/logging.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,27 @@ def _emit(self, record):
222222

223223
event["level"] = _logging_to_event_level(record.levelname)
224224
event["logger"] = record.name
225-
event["logentry"] = {"message": to_string(record.msg), "params": record.args}
225+
226+
# Log records from `warnings` module as separate issues
227+
record_caputured_from_warnings_module = (
228+
record.name == "py.warnings" and record.msg == "%s"
229+
)
230+
if record_caputured_from_warnings_module:
231+
# use the actual message and not "%s" as the message
232+
# this prevents grouping all warnings under one "%s" issue
233+
msg = record.args[0] # type: ignore
234+
235+
event["logentry"] = {
236+
"message": msg,
237+
"params": (),
238+
}
239+
240+
else:
241+
event["logentry"] = {
242+
"message": to_string(record.msg),
243+
"params": record.args,
244+
}
245+
226246
event["extra"] = _extra_from_record(record)
227247

228248
hub.capture_event(event, hint=hint)

tests/integrations/logging/test_logging.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import pytest
44
import logging
5+
import warnings
56

67
from sentry_sdk.integrations.logging import LoggingIntegration, ignore_logger
78

@@ -136,6 +137,36 @@ def filter(self, record):
136137
assert event["logentry"]["message"] == "hi"
137138

138139

140+
def test_logging_captured_warnings(sentry_init, capture_events, recwarn):
141+
sentry_init(
142+
integrations=[LoggingIntegration(event_level="WARNING")],
143+
default_integrations=False,
144+
)
145+
events = capture_events()
146+
147+
logging.captureWarnings(True)
148+
warnings.warn("first")
149+
warnings.warn("second")
150+
logging.captureWarnings(False)
151+
152+
warnings.warn("third")
153+
154+
assert len(events) == 2
155+
156+
assert events[0]["level"] == "warning"
157+
# Captured warnings start with the path where the warning was raised
158+
assert "UserWarning: first" in events[0]["logentry"]["message"]
159+
assert events[0]["logentry"]["params"] == []
160+
161+
assert events[1]["level"] == "warning"
162+
assert "UserWarning: second" in events[1]["logentry"]["message"]
163+
assert events[1]["logentry"]["params"] == []
164+
165+
# Using recwarn suppresses the "third" warning in the test output
166+
assert len(recwarn) == 1
167+
assert str(recwarn[0].message) == "third"
168+
169+
139170
def test_ignore_logger(sentry_init, capture_events):
140171
sentry_init(integrations=[LoggingIntegration()], default_integrations=False)
141172
events = capture_events()

0 commit comments

Comments
 (0)