Skip to content

Commit 2ef80d6

Browse files
add observability to checkmate test (#854)
* add observability to checkmate test * add observability to checkmate test * update format and lint
1 parent 4ab3fe4 commit 2ef80d6

2 files changed

Lines changed: 131 additions & 6 deletions

File tree

tests/unit/viahtml/views/status_test.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from unittest.mock import create_autospec
23

34
import pytest
@@ -82,6 +83,84 @@ def test_it_sends_test_messages_to_sentry(self, context, view, capture_message):
8283
"Test message from Via HTML's status view"
8384
)
8485

86+
def test_it_logs_checkmate_failure_details(self, context, view, checkmate, caplog):
87+
exc = CheckmateException("Connection timed out")
88+
checkmate.check_url.side_effect = exc
89+
context.query_params = {"include-checkmate": [""]}
90+
91+
with caplog.at_level(logging.ERROR, logger="viahtml.views.status"):
92+
view(context)
93+
94+
assert any(
95+
"Checkmate status check failed" in record.message
96+
and "Connection timed out" in record.message
97+
for record in caplog.records
98+
), f"Expected checkmate failure log, got: {[r.message for r in caplog.records]}"
99+
100+
def test_it_logs_checkmate_success(self, context, view, caplog):
101+
context.query_params = {"include-checkmate": [""]}
102+
103+
with caplog.at_level(logging.INFO, logger="viahtml.views.status"):
104+
view(context)
105+
106+
assert any(
107+
"Checkmate status check succeeded" in record.message
108+
for record in caplog.records
109+
), f"Expected checkmate success log, got: {[r.message for r in caplog.records]}"
110+
111+
def test_it_creates_sentry_span_on_checkmate_failure(
112+
self, context, view, checkmate, sentry_start_span, sentry_capture_exception
113+
): # pylint:disable=too-many-arguments
114+
exc = CheckmateException("Connection timed out")
115+
checkmate.check_url.side_effect = exc
116+
context.query_params = {"include-checkmate": [""]}
117+
118+
view(context)
119+
120+
sentry_start_span.assert_called_once_with(
121+
op="checkmate.status_check",
122+
name="Check Checkmate health via check_url",
123+
)
124+
span = sentry_start_span.return_value.__enter__.return_value
125+
span.set_status.assert_called_once_with("internal_error")
126+
span.set_data.assert_any_call("error.type", "CheckmateException")
127+
span.set_data.assert_any_call("error.message", "Connection timed out")
128+
sentry_capture_exception.assert_called_once_with(exc)
129+
130+
def test_it_creates_sentry_span_on_checkmate_success(
131+
self, context, view, sentry_start_span, sentry_capture_exception
132+
):
133+
context.query_params = {"include-checkmate": [""]}
134+
135+
view(context)
136+
137+
sentry_start_span.assert_called_once_with(
138+
op="checkmate.status_check",
139+
name="Check Checkmate health via check_url",
140+
)
141+
span = sentry_start_span.return_value.__enter__.return_value
142+
span.set_status.assert_called_once_with("ok")
143+
sentry_capture_exception.assert_not_called()
144+
145+
def test_it_adds_sentry_breadcrumb_on_checkmate_failure(
146+
self, context, view, checkmate, sentry_add_breadcrumb
147+
):
148+
exc = CheckmateException("Connection timed out")
149+
checkmate.check_url.side_effect = exc
150+
context.query_params = {"include-checkmate": [""]}
151+
152+
view(context)
153+
154+
sentry_add_breadcrumb.assert_called_once_with(
155+
category="checkmate",
156+
message="Checkmate status check failed: Connection timed out",
157+
level="error",
158+
data={
159+
"exception_type": "CheckmateException",
160+
"exception_message": "Connection timed out",
161+
},
162+
)
163+
85164
@pytest.fixture
86165
def checkmate(self):
87166
return create_autospec(CheckmateClient, instance=True, spec_set=True)
@@ -95,6 +174,18 @@ def context(self, context):
95174
def view(self, checkmate):
96175
return StatusView(checkmate)
97176

177+
@pytest.fixture(autouse=True)
178+
def sentry_start_span(self, patch):
179+
return patch("viahtml.views.status.sentry_sdk.start_span")
180+
181+
@pytest.fixture(autouse=True)
182+
def sentry_capture_exception(self, patch):
183+
return patch("viahtml.views.status.sentry_sdk.capture_exception")
184+
185+
@pytest.fixture(autouse=True)
186+
def sentry_add_breadcrumb(self, patch):
187+
return patch("viahtml.views.status.sentry_sdk.add_breadcrumb")
188+
98189

99190
@pytest.fixture(autouse=True)
100191
def capture_message(patch):

viahtml/views/status.py

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
import logging
2+
import traceback
13
from http import HTTPStatus
24

5+
import sentry_sdk
36
from checkmatelib import CheckmateException
47
from sentry_sdk import capture_message
58

9+
LOG = logging.getLogger(__name__)
10+
611

712
class StatusView:
813
def __init__(self, checkmate):
@@ -22,12 +27,7 @@ def __call__(self, context):
2227
http_status = HTTPStatus.OK
2328

2429
if "include-checkmate" in context.query_params:
25-
try:
26-
self._checkmate.check_url("https://example.com/")
27-
except CheckmateException:
28-
body["down"] = ["checkmate"]
29-
else:
30-
body["okay"] = ["checkmate"]
30+
self._check_checkmate(body)
3131

3232
# If any of the components checked above were down then report the
3333
# status check as a whole as being down.
@@ -44,3 +44,37 @@ def __call__(self, context):
4444
http_status=http_status,
4545
headers={"Cache-Control": "max-age=0, must-revalidate, no-cache, no-store"},
4646
)
47+
48+
def _check_checkmate(self, body):
49+
with sentry_sdk.start_span(
50+
op="checkmate.status_check",
51+
name="Check Checkmate health via check_url",
52+
) as span:
53+
LOG.info("Checking checkmate status via check_url")
54+
try:
55+
self._checkmate.check_url("https://example.com/")
56+
except CheckmateException as exc:
57+
LOG.error(
58+
"Checkmate status check failed: %s: %s\n%s",
59+
type(exc).__name__,
60+
exc,
61+
traceback.format_exc(),
62+
)
63+
span.set_status("internal_error")
64+
span.set_data("error.type", type(exc).__name__)
65+
span.set_data("error.message", str(exc))
66+
sentry_sdk.add_breadcrumb(
67+
category="checkmate",
68+
message=f"Checkmate status check failed: {exc}",
69+
level="error",
70+
data={
71+
"exception_type": type(exc).__name__,
72+
"exception_message": str(exc),
73+
},
74+
)
75+
sentry_sdk.capture_exception(exc)
76+
body["down"] = ["checkmate"]
77+
else:
78+
LOG.info("Checkmate status check succeeded")
79+
span.set_status("ok")
80+
body["okay"] = ["checkmate"]

0 commit comments

Comments
 (0)