Skip to content

Commit d062836

Browse files
committed
chore(telemetry): replace add_error by add_error_log
1 parent 1bb0cd3 commit d062836

File tree

3 files changed

+28
-48
lines changed

3 files changed

+28
-48
lines changed

ddtrace/internal/telemetry/logging.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,4 @@ def emit(self, record: logging.LogRecord) -> None:
1414
- Log all records with a level of ERROR or higher with telemetry
1515
"""
1616
if record.levelno >= logging.ERROR:
17-
# Capture start up errors
18-
full_file_name = os.path.join(record.pathname, record.filename)
19-
self.telemetry_writer.add_error(1, record.msg, full_file_name, record.lineno)
17+
self.telemetry_writer.add_error_log(record.msg, record.exc_info)

ddtrace/internal/telemetry/writer.py

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -163,10 +163,6 @@ def __init__(self, is_periodic=True, agentless=None):
163163
self._periodic_count = 0
164164
self._is_periodic = is_periodic
165165
self._integrations_queue = dict() # type: Dict[str, Dict]
166-
# Currently telemetry only supports reporting a single error.
167-
# If we'd like to report multiple errors in the future
168-
# we could hack it in by xor-ing error codes and concatenating strings
169-
self._error = (0, "") # type: Tuple[int, str]
170166
self._namespace = MetricNamespace()
171167
self._logs = set() # type: Set[Dict[str, Any]]
172168
self._forked = False # type: bool
@@ -301,15 +297,6 @@ def add_integration(self, integration_name, patched, auto_patched=None, error_ms
301297
self._integrations_queue[integration_name]["compatible"] = error_msg == ""
302298
self._integrations_queue[integration_name]["error"] = error_msg
303299

304-
def add_error(self, code, msg, filename, line_number):
305-
# type: (int, str, Optional[str], Optional[int]) -> None
306-
"""Add an error to be submitted with an event.
307-
Note that this overwrites any previously set errors.
308-
"""
309-
if filename and line_number is not None:
310-
msg = "%s:%s: %s" % (filename, line_number, msg)
311-
self._error = (code, msg)
312-
313300
def _app_started(self, register_app_shutdown=True):
314301
# type: (bool) -> None
315302
"""Sent when TelemetryWriter is enabled or forks"""
@@ -330,10 +317,6 @@ def _app_started(self, register_app_shutdown=True):
330317

331318
payload = {
332319
"configuration": self._flush_configuration_queue(),
333-
"error": {
334-
"code": self._error[0],
335-
"message": self._error[1],
336-
},
337320
"products": products,
338321
} # type: Dict[str, Union[Dict[str, Any], List[Any]]]
339322
# Add time to value telemetry metrics for single step instrumentation
@@ -343,9 +326,6 @@ def _app_started(self, register_app_shutdown=True):
343326
"install_type": config.INSTALL_TYPE,
344327
"install_time": config.INSTALL_TIME,
345328
}
346-
347-
# Reset the error after it has been reported.
348-
self._error = (0, "")
349329
self.add_event(payload, "app-started")
350330

351331
def _app_heartbeat_event(self):
@@ -524,18 +504,21 @@ def add_log(self, level, message, stack_trace="", tags=None):
524504
# Logs are hashed using the message, level, tags, and stack_trace. This should prevent duplicatation.
525505
self._logs.add(data)
526506

527-
def add_error_log(self, msg: str, exc: BaseException) -> None:
507+
def add_error_log(self, msg: str, exc: Union[BaseException, tuple, None]) -> None:
528508
if config.LOG_COLLECTION_ENABLED:
529-
stack_trace = self._format_stack_trace(exc)
509+
stack_trace = None if exc is None else self._format_stack_trace(exc)
530510

531511
self.add_log(
532512
TELEMETRY_LOG_LEVEL.ERROR,
533513
msg,
534514
stack_trace=stack_trace if stack_trace is not None else "",
535515
)
536516

537-
def _format_stack_trace(self, exc: BaseException) -> Optional[str]:
538-
exc_type, _, exc_traceback = type(exc), exc, getattr(exc, "__traceback__", None)
517+
def _format_stack_trace(self, exc: Union[BaseException, tuple]) -> Optional[str]:
518+
if isinstance(exc, tuple) and len(exc) == 3:
519+
exc_type, _, exc_traceback = exc
520+
else:
521+
exc_type, _, exc_traceback = type(exc), exc, getattr(exc, "__traceback__", None)
539522

540523
if not exc_traceback:
541524
return None
@@ -759,7 +742,8 @@ def _telemetry_excepthook(self, tp, value, root_traceback):
759742

760743
lineno = traceback.tb_frame.f_code.co_firstlineno
761744
filename = traceback.tb_frame.f_code.co_filename
762-
self.add_error(1, str(value), filename, lineno)
745+
746+
self.add_error_log("Unhandled exception from ddtrace code", (tp, None, root_traceback))
763747

764748
dir_parts = filename.split(os.path.sep)
765749
# Check if exception was raised in the `ddtrace.contrib` package

tests/telemetry/test_telemetry.py

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import os
2-
import re
3-
42
import pytest
53

64

@@ -173,16 +171,13 @@ def process_trace(self, trace):
173171

174172
app_started_events = [event for event in events if event["request_type"] == "app-started"]
175173
assert len(app_started_events) == 1
176-
assert app_started_events[0]["payload"]["error"]["code"] == 1
177-
assert (
178-
"error applying processor <__main__.FailingFilture object at"
179-
not in app_started_events[0]["payload"]["error"]["message"]
180-
)
181-
assert "error applying processor %r" in app_started_events[0]["payload"]["error"]["message"]
182-
pattern = re.compile(".*ddtrace/_trace/processor/__init__.py/__init__.py:[0-9]+: " "error applying processor %r")
183-
assert pattern.match(app_started_events[0]["payload"]["error"]["message"]), app_started_events[0]["payload"][
184-
"error"
185-
]["message"]
174+
175+
logs_event = test_agent_session.get_events("logs", subprocess=True)
176+
error_log = logs_event[0]["payload"]["logs"][0]
177+
assert error_log["message"] == "error applying processor %r to trace %d"
178+
assert error_log["level"] == "ERROR"
179+
assert "in on_span_finish" in error_log["stack_trace"]
180+
assert "spans = tp.process_trace(spans) or []" in error_log["stack_trace"]
186181

187182

188183
def test_register_telemetry_excepthook_after_another_hook(test_agent_session, run_python_code_in_subprocess):
@@ -211,11 +206,11 @@ def pre_ddtrace_exc_hook(exctype, value, traceback):
211206

212207
app_starteds = test_agent_session.get_events("app-started", subprocess=True)
213208
assert len(app_starteds) == 1
214-
# app-started captures unhandled exceptions raised in application code
215-
assert app_starteds[0]["payload"]["error"]["code"] == 1
216-
assert re.search(r"test\.py:\d+:\sbad_code$", app_starteds[0]["payload"]["error"]["message"]), app_starteds[0][
217-
"payload"
218-
]["error"]["message"]
209+
210+
# the tracer should not capture logs from non ddtrace code
211+
# i will not test further as it will be removed in next PR
212+
logs_event = test_agent_session.get_events("logs", subprocess=True)
213+
assert len(logs_event) == 1
219214

220215

221216
def test_handled_integration_error(test_agent_session, run_python_code_in_subprocess):
@@ -271,9 +266,12 @@ def test_unhandled_integration_error(test_agent_session, ddtrace_run_python_code
271266

272267
app_started_event = test_agent_session.get_events("app-started", subprocess=True)
273268
assert len(app_started_event) == 1
274-
assert app_started_event[0]["payload"]["error"]["code"] == 1
275-
assert "ddtrace/contrib/internal/flask/patch.py" in app_started_event[0]["payload"]["error"]["message"]
276-
assert "not enough values to unpack (expected 2, got 0)" in app_started_event[0]["payload"]["error"]["message"]
269+
270+
logs_event = test_agent_session.get_events("logs", subprocess=True)
271+
error_log = logs_event[0]["payload"]["logs"][0]
272+
assert error_log["message"] == "Unhandled exception from ddtrace code"
273+
assert error_log["level"] == "ERROR"
274+
assert "patched_wsgi_app" in error_log["stack_trace"]
277275

278276
integration_events = test_agent_session.get_events("app-integrations-change", subprocess=True)
279277
integrations = integration_events[0]["payload"]["integrations"]

0 commit comments

Comments
 (0)