-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
36bc403
commit ed51eb0
Showing
25 changed files
with
313 additions
and
694 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,3 +8,5 @@ build/ | |
.coverage | ||
dist/ | ||
/pii_report/*.yaml | ||
docs/_build | ||
venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,74 +0,0 @@ | ||
""" | ||
App for emitting additional diagnostic information for the Datadog integration. | ||
""" | ||
|
||
import logging | ||
|
||
from django.apps import AppConfig | ||
from django.conf import settings | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
# .. toggle_name: DATADOG_DIAGNOSTICS_ENABLE | ||
# .. toggle_implementation: DjangoSetting | ||
# .. toggle_default: True | ||
# .. toggle_description: Enables logging of Datadog diagnostics information. | ||
# .. toggle_use_cases: circuit_breaker | ||
# .. toggle_creation_date: 2024-07-11 | ||
# .. toggle_tickets: https://github.com/edx/edx-arch-experiments/issues/692 | ||
DATADOG_DIAGNOSTICS_ENABLE = getattr(settings, 'DATADOG_DIAGNOSTICS_ENABLE', True) | ||
|
||
# .. setting_name: DATADOG_DIAGNOSTICS_MAX_SPANS | ||
# .. setting_default: 100 | ||
# .. setting_description: Limit of how many spans to hold onto and log | ||
# when diagnosing Datadog tracing issues. This limits memory consumption | ||
# avoids logging more data than is actually needed for diagnosis. | ||
DATADOG_DIAGNOSTICS_MAX_SPANS = getattr(settings, 'DATADOG_DIAGNOSTICS_MAX_SPANS', 100) | ||
|
||
|
||
class MissingSpanProcessor: | ||
"""Datadog span processor that logs unfinished spans at shutdown.""" | ||
|
||
def __init__(self): | ||
self.spans_started = 0 | ||
self.spans_finished = 0 | ||
self.open_spans = {} | ||
|
||
def on_span_start(self, span): | ||
self.spans_started += 1 | ||
if len(self.open_spans) < DATADOG_DIAGNOSTICS_MAX_SPANS: | ||
self.open_spans[span.span_id] = span | ||
|
||
def on_span_finish(self, span): | ||
self.spans_finished += 1 | ||
self.open_spans.pop(span.span_id, None) # "delete if present" | ||
|
||
def shutdown(self, _timeout): | ||
log.info(f"Spans created = {self.spans_started}; spans finished = {self.spans_finished}") | ||
for span in self.open_spans.values(): | ||
log.error(f"Span created but not finished: {span._pprint()}") # pylint: disable=protected-access | ||
|
||
|
||
class DatadogDiagnostics(AppConfig): | ||
""" | ||
Django application to log diagnostic information for Datadog. | ||
""" | ||
name = 'edx_arch_experiments.datadog_diagnostics' | ||
|
||
# Mark this as a plugin app | ||
plugin_app = {} | ||
|
||
def ready(self): | ||
if not DATADOG_DIAGNOSTICS_ENABLE: | ||
return | ||
|
||
try: | ||
from ddtrace import tracer # pylint: disable=import-outside-toplevel | ||
tracer._span_processors.append(MissingSpanProcessor()) # pylint: disable=protected-access | ||
log.info("Attached MissingSpanProcessor for Datadog diagnostics") | ||
except ImportError: | ||
log.warning( | ||
"Unable to attach MissingSpanProcessor for Datadog diagnostics" | ||
" -- ddtrace module not found." | ||
) | ||
This file was deleted.
Oops, something went wrong.
Empty file.
51 changes: 0 additions & 51 deletions
51
edx_arch_experiments/datadog_diagnostics/tests/test_app.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +0,0 @@ | ||
""" | ||
Tests for plugin app. | ||
""" | ||
|
||
from unittest.mock import patch | ||
|
||
from django.test import TestCase | ||
|
||
from .. import apps | ||
|
||
|
||
class FakeSpan: | ||
"""A fake Span instance that just carries a span_id.""" | ||
def __init__(self, span_id): | ||
self.span_id = span_id | ||
|
||
def _pprint(self): | ||
return f"span_id={self.span_id}" | ||
|
||
|
||
class TestMissingSpanProcessor(TestCase): | ||
"""Tests for MissingSpanProcessor.""" | ||
|
||
@patch.object(apps, 'DATADOG_DIAGNOSTICS_MAX_SPANS', new=3) | ||
def test_metrics(self): | ||
proc = apps.MissingSpanProcessor() | ||
ids = [2, 4, 6, 8, 10] | ||
|
||
for span_id in ids: | ||
proc.on_span_start(FakeSpan(span_id)) | ||
|
||
assert {(sk, sv.span_id) for sk, sv in proc.open_spans.items()} == {(2, 2), (4, 4), (6, 6)} | ||
assert proc.spans_started == 5 | ||
assert proc.spans_finished == 0 | ||
|
||
for span_id in ids: | ||
proc.on_span_finish(FakeSpan(span_id)) | ||
|
||
assert proc.open_spans.keys() == set() | ||
assert proc.spans_started == 5 | ||
assert proc.spans_finished == 5 | ||
|
||
@patch('edx_arch_experiments.datadog_diagnostics.apps.log.info') | ||
@patch('edx_arch_experiments.datadog_diagnostics.apps.log.error') | ||
def test_logging(self, mock_log_error, mock_log_info): | ||
proc = apps.MissingSpanProcessor() | ||
proc.on_span_start(FakeSpan(17)) | ||
proc.shutdown(0) | ||
|
||
mock_log_info.assert_called_once_with("Spans created = 1; spans finished = 0") | ||
mock_log_error.assert_called_once_with("Span created but not finished: span_id=17") | ||
Oops, something went wrong.