Skip to content

Commit 9a9d000

Browse files
committed
feat: configurable logging integration
also refactor entire test suite setup
1 parent 9d58e11 commit 9a9d000

8 files changed

Lines changed: 131 additions & 68 deletions

File tree

pytest.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[pytest]
22
DJANGO_SETTINGS_MODULE = tests.integrations.django.myapp.settings
3+
addopts = --boxed

sentry_sdk/integrations/logging.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,14 @@
1515
_master_handler = None
1616

1717

18-
def install(client):
18+
def install(client, level=logging.INFO, event_level=None):
1919
global _installed
2020
global _master_handler
2121
with _installer_lock:
2222
if _installed:
2323
return
2424

25-
_master_handler = SentryHandler()
26-
_master_handler.setLevel(logging.INFO) # TODO: make configurable
25+
_master_handler = SentryHandler(level=level, event_level=event_level)
2726

2827
old_callhandlers = logging.Logger.callHandlers
2928

@@ -37,6 +36,13 @@ def sentry_patched_callhandlers(self, record):
3736

3837

3938
class SentryHandler(logging.Handler, object):
39+
def __init__(self, level, event_level):
40+
logging.Handler.__init__(self, level)
41+
if event_level is None:
42+
self._event_level = None
43+
else:
44+
self._event_level = logging._checkLevel(event_level)
45+
4046
def emit(self, record):
4147
with _internal_exceptions():
4248
self.format(record)
@@ -56,7 +62,7 @@ def _breadcrumb_from_record(self, record):
5662
def _emit(self, record):
5763
add_breadcrumb(self._breadcrumb_from_record(record))
5864

59-
if not self._should_Event(record):
65+
if not self._should_create_event(record):
6066
return
6167

6268
if not self.can_record(record):
@@ -85,8 +91,5 @@ def _emit(self, record):
8591
def _logging_to_event_level(self, levelname):
8692
return {"critical": "fatal"}.get(levelname.lower(), levelname.lower())
8793

88-
def _should_Event(self, record):
89-
# TODO: make configurable
90-
if record.levelno in (logging.ERROR, logging.CRITICAL):
91-
return True
92-
return False
94+
def _should_create_event(self, record):
95+
return self._event_level is not None and record.levelno >= self._event_level
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
11
import pytest
2-
from sentry_sdk import Client, get_current_hub
32

43
pytest.importorskip("celery")
54

65
from celery import Celery
76

8-
get_current_hub().bind_client(Client(integrations=["celery"]))
9-
107

118
@pytest.fixture
12-
def celery():
9+
def celery(sentry_init):
10+
sentry_init(integrations=["celery"])
1311
celery = Celery(__name__)
1412
celery.conf.CELERY_ALWAYS_EAGER = True
1513
return celery
1614

1715

1816
def test_simple(capture_events, celery):
17+
18+
events = capture_events()
19+
1920
@celery.task(name="dummy_task")
2021
def dummy_task(x, y):
2122
return x / y
2223

2324
dummy_task.delay(1, 2)
2425
dummy_task.delay(1, 0)
25-
event, = capture_events
26+
event, = events
2627
assert event["transaction"] == "dummy_task"
2728

2829
exception, = event["exception"]["values"]
2930
assert exception["type"] == "ZeroDivisionError"
3031

3132

3233
def test_ignore_expected(capture_events, celery):
34+
events = capture_events()
35+
3336
@celery.task(name="dummy_task", throws=(ZeroDivisionError,))
3437
def dummy_task(x, y):
3538
return x / y
3639

3740
dummy_task.delay(1, 2)
3841
dummy_task.delay(1, 0)
39-
assert not capture_events
42+
assert not events

tests/integrations/conftest.py

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,21 @@
55
from sentry_sdk.client import Transport
66

77

8+
@pytest.fixture
9+
def monkeypatch_test_transport(monkeypatch):
10+
return lambda client: monkeypatch.setattr(client, "_transport", TestTransport())
11+
12+
13+
@pytest.fixture
14+
def sentry_init(monkeypatch_test_transport):
15+
def inner(*a, **kw):
16+
client = sentry_sdk.Client(*a, **kw)
17+
monkeypatch_test_transport(client)
18+
sentry_sdk.Hub.current.bind_client(client)
19+
20+
return inner
21+
22+
823
class TestTransport(Transport):
924
def __init__(self):
1025
pass
@@ -21,13 +36,6 @@ def capture_event(self, event):
2136
dsn = "LOL"
2237

2338

24-
@pytest.fixture(autouse=True)
25-
def set_test_transport(monkeypatch):
26-
test_client = sentry_sdk.Hub.current.client
27-
if test_client:
28-
monkeypatch.setattr(test_client, "_transport", TestTransport())
29-
30-
3139
@pytest.fixture(autouse=True)
3240
def reraise_internal_exceptions(monkeypatch):
3341
def capture_internal_exception(error=None):
@@ -44,18 +52,26 @@ def capture_internal_exception(error=None):
4452

4553
@pytest.fixture
4654
def capture_exceptions(monkeypatch):
47-
errors = []
55+
def inner():
56+
errors = []
57+
58+
def capture_exception(error=None):
59+
errors.append(error or sys.exc_info()[1])
4860

49-
def capture_exception(error=None):
50-
errors.append(error or sys.exc_info()[1])
61+
monkeypatch.setattr(
62+
sentry_sdk.Hub.current, "capture_exception", capture_exception
63+
)
64+
return errors
5165

52-
monkeypatch.setattr(sentry_sdk.Hub.current, "capture_exception", capture_exception)
53-
return errors
66+
return inner
5467

5568

5669
@pytest.fixture
5770
def capture_events(monkeypatch):
58-
events = []
59-
test_client = sentry_sdk.Hub.current.client
60-
monkeypatch.setattr(test_client._transport, "capture_event", events.append)
61-
return events
71+
def inner():
72+
events = []
73+
test_client = sentry_sdk.Hub.current.client
74+
monkeypatch.setattr(test_client._transport, "capture_event", events.append)
75+
return events
76+
77+
return inner

tests/integrations/django/test_basic.py

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sys
21
import pytest
32

43
django = pytest.importorskip("django")
@@ -15,36 +14,30 @@
1514

1615

1716
@pytest.fixture
18-
def client():
17+
def client(monkeypatch_test_transport):
18+
monkeypatch_test_transport(Hub.current.client)
1919
return Client()
2020

2121

22-
@pytest.fixture
23-
def capture_exceptions(monkeypatch):
24-
errors = []
25-
26-
def capture_exception(error=None):
27-
errors.append(error or sys.exc_info()[1])
28-
29-
monkeypatch.setattr(Hub.current, "capture_exception", capture_exception)
30-
return errors
31-
32-
3322
def test_scope_working(client):
3423
response = client.get(reverse("self_check"))
3524
assert response.status_code == 200
3625

3726

3827
def test_view_exceptions(client, capture_exceptions):
28+
exceptions = capture_exceptions()
3929
with pytest.raises(ZeroDivisionError) as exc:
4030
client.get(reverse("view_exc"))
41-
assert capture_exceptions == [exc.value]
31+
32+
assert exceptions == [exc.value]
4233

4334

4435
def test_middleware_exceptions(client, capture_exceptions):
36+
exceptions = capture_exceptions()
4537
with pytest.raises(ZeroDivisionError) as exc:
4638
client.get(reverse("middleware_exc"))
47-
assert capture_exceptions == [exc.value]
39+
40+
assert exceptions == [exc.value]
4841

4942

5043
def test_get_dsn(client):
@@ -53,10 +46,11 @@ def test_get_dsn(client):
5346

5447

5548
def test_request_captured(client, capture_events):
49+
events = capture_events()
5650
response = client.get(reverse("message"))
5751
assert response.content == b"ok"
5852

59-
event, = capture_events
53+
event, = events
6054
assert event["request"] == {
6155
"cookies": {},
6256
"env": {

0 commit comments

Comments
 (0)