Skip to content

Commit 9894c83

Browse files
Support logging payload when sending to socket or error service. (#727)
1 parent 601253e commit 9894c83

File tree

6 files changed

+126
-3
lines changed

6 files changed

+126
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## Pending
44

55
### Added
6+
- Add `log_payload_content` to support logging the content of the message
7+
being sent to either the core agent socket or the error service.
8+
([Issue 724](https://github.com/scoutapp/scout_apm_python/issues/724))
69

710
### Fixed
811

src/scout_apm/core/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def log(self):
8181
"ignore",
8282
"key",
8383
"log_level",
84+
"log_payload_content",
8485
"monitor",
8586
"name",
8687
"revision_sha",
@@ -231,6 +232,7 @@ def __init__(self):
231232
"framework_version": "",
232233
"hostname": None,
233234
"key": "",
235+
"log_payload_content": False,
234236
"monitor": False,
235237
"name": "Python App",
236238
"revision_sha": self._git_revision_sha(),

src/scout_apm/core/error.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding=utf-8
22
from __future__ import absolute_import, division, print_function, unicode_literals
33

4+
import logging
45
import sys
56

67
from scout_apm.core.backtrace import capture_stacktrace
@@ -9,6 +10,7 @@
910
from scout_apm.core.tracked_request import TrackedRequest
1011
from scout_apm.core.web_requests import RequestComponents, filter_element
1112

13+
logger = logging.getLogger(__name__)
1214
text_type = str if sys.version_info[0] >= 3 else unicode # noqa: F821
1315

1416

@@ -80,4 +82,13 @@ def send(
8082
"revision_sha": scout_config.value("revision_sha"),
8183
}
8284

85+
if scout_config.value("log_payload_content"):
86+
logger.debug(
87+
"Sending error for request: %s. Payload: %r",
88+
tracked_request.request_id,
89+
error,
90+
)
91+
else:
92+
logger.debug("Sending error for request: %s.", tracked_request.request_id)
93+
8394
ErrorServiceThread.send(error=error)

src/scout_apm/core/tracked_request.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from scout_apm.core import backtrace, objtrace
1010
from scout_apm.core.agent.commands import BatchCommand
1111
from scout_apm.core.agent.socket import CoreAgentSocketThread
12+
from scout_apm.core.config import scout_config
1213
from scout_apm.core.n_plus_one_tracker import NPlusOneTracker
1314
from scout_apm.core.samplers.memory import get_rss_in_mb
1415
from scout_apm.core.samplers.thread import SamplersThread
@@ -151,8 +152,15 @@ def finish(self):
151152
self.tag("mem_delta", self._get_mem_delta())
152153
if not self.is_ignored() and not self.sent:
153154
self.sent = True
154-
logger.debug("Sending request: %s", self.request_id)
155155
batch_command = BatchCommand.from_tracked_request(self)
156+
if scout_config.value("log_payload_content"):
157+
logger.debug(
158+
"Sending request: %s. Payload: %s",
159+
self.request_id,
160+
batch_command.message(),
161+
)
162+
else:
163+
logger.debug("Sending request: %s.", self.request_id)
156164
CoreAgentSocketThread.send(batch_command)
157165
SamplersThread.ensure_started()
158166

tests/unit/core/test_error.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding=utf-8
22
from __future__ import absolute_import, division, print_function, unicode_literals
33

4+
import logging
45
import sys
56
from contextlib import contextmanager
67

@@ -168,6 +169,7 @@ def test_monitor(
168169
expected_error,
169170
tracked_request,
170171
error_monitor_errors,
172+
caplog,
171173
):
172174
with app_with_scout():
173175
tracked_request.request_id = "sample_id"
@@ -197,3 +199,49 @@ def test_monitor(
197199
assert line
198200
assert func_str == "in test_monitor"
199201
assert error == expected_error
202+
assert (
203+
"scout_apm.core.error",
204+
logging.DEBUG,
205+
"Sending error for request: sample_id.",
206+
) in caplog.record_tuples
207+
208+
209+
def test_monitor_with_logged_payload(
210+
tracked_request,
211+
error_monitor_errors,
212+
caplog,
213+
):
214+
with app_with_scout(scout_config={"log_payload_content": True}):
215+
tracked_request.request_id = "sample_id"
216+
tracked_request.tags["spam"] = "foo"
217+
exc_info = 0
218+
try:
219+
1 / 0
220+
except ZeroDivisionError:
221+
exc_info = sys.exc_info()
222+
ErrorMonitor.send(
223+
exc_info,
224+
request_components=RequestComponents("sample.app", "DataView", "detail"),
225+
request_path="/test/",
226+
)
227+
228+
assert len(error_monitor_errors) == 1
229+
230+
# Find the logged message.
231+
actual_message = None
232+
for module, level, message in caplog.record_tuples:
233+
if module == "scout_apm.core.error" and level == logging.DEBUG:
234+
if message.startswith("Sending error for request: sample_id. Payload: "):
235+
actual_message = message
236+
break
237+
assert actual_message
238+
239+
assert "ZeroDivisionError" in actual_message
240+
assert "division by zero" in actual_message
241+
assert (
242+
"tests/unit/core/test_error.py:219:in test_monitor_with_logged_payload"
243+
in actual_message
244+
)
245+
assert "sample.app" in actual_message
246+
assert "DataView" in actual_message
247+
assert "/test/" in actual_message

tests/unit/core/test_tracked_request.py

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
import logging
66
import sys
77

8+
import pytest
9+
810
from scout_apm.core import objtrace
11+
from scout_apm.core.config import scout_config
912
from scout_apm.core.tracked_request import TrackedRequest
1013
from tests.compat import copy_context, mock
1114
from tests.tools import (
@@ -15,6 +18,18 @@
1518
)
1619

1720

21+
@pytest.fixture
22+
def reset_config():
23+
"""
24+
Reset scout configuration after a test
25+
"""
26+
try:
27+
yield
28+
finally:
29+
# Reset Scout configuration.
30+
scout_config.reset_all()
31+
32+
1833
def test_tracked_request_repr(tracked_request):
1934
assert repr(tracked_request).startswith("<TrackedRequest(")
2035

@@ -214,7 +229,7 @@ def test_finish_log_request_info(tracked_request, caplog):
214229
assert (
215230
"scout_apm.core.tracked_request",
216231
logging.DEBUG,
217-
"Sending request: {}".format(tracked_request.request_id),
232+
"Sending request: {}.".format(tracked_request.request_id),
218233
) in caplog.record_tuples
219234

220235
assert (
@@ -237,6 +252,42 @@ def test_finish_log_request_info(tracked_request, caplog):
237252
) in caplog.record_tuples
238253

239254

255+
def test_finish_log_request_info_with_logged_payload(
256+
tracked_request, caplog, reset_config
257+
):
258+
scout_config.set(log_payload_content=True)
259+
tracked_request.is_real_request = True
260+
tracked_request.start_span(operation="Something")
261+
tracked_request.stop_span()
262+
263+
# Find the logged message.
264+
actual_message = None
265+
for module, level, message in caplog.record_tuples:
266+
if module == "scout_apm.core.tracked_request" and level == logging.DEBUG:
267+
if message.startswith(
268+
"Sending request: {}. Payload: ".format(tracked_request.request_id)
269+
):
270+
actual_message = message
271+
break
272+
assert actual_message
273+
# Verify the counts of the spans and the request id.
274+
assert actual_message.count("'StartRequest'") == 1
275+
assert actual_message.count("'FinishRequest'") == 1
276+
assert actual_message.count("'TagRequest'") == 1
277+
assert actual_message.count("'StartSpan'") == 1
278+
assert actual_message.count("'StopSpan'") == 1
279+
if objtrace.is_extension:
280+
assert actual_message.count("'TagSpan'") == 3
281+
total_requests = 8
282+
else:
283+
assert actual_message.count("'TagSpan'") == 0
284+
total_requests = 5
285+
# Verify each request id in the payload is the tracked request's.
286+
assert actual_message.count("'request_id'") == total_requests
287+
# The actual request id is also included in the log message after Sending request:
288+
assert actual_message.count(tracked_request.request_id) == total_requests + 1
289+
290+
240291
def test_finish_clears_context():
241292
tracked_request_1 = TrackedRequest.instance()
242293
tracked_request_1.is_real_request = True
@@ -273,7 +324,7 @@ def test_request_only_sent_once(tracked_request, caplog):
273324
sent_log = (
274325
"scout_apm.core.tracked_request",
275326
logging.DEBUG,
276-
"Sending request: {}".format(tracked_request.request_id),
327+
"Sending request: {}.".format(tracked_request.request_id),
277328
)
278329
info_log = (
279330
"scout_apm.core.tracked_request",

0 commit comments

Comments
 (0)