From 4e893efa819d70fc35af13c8b09aee9ef3270592 Mon Sep 17 00:00:00 2001 From: Diana Huang Date: Thu, 10 Oct 2024 15:00:57 -0400 Subject: [PATCH] feat: Add implementation for set_monitoring_transaction_name in DD. This also refactors the existing NewRelic implementation to use the backends framework. Also added comments about not porting ignore_transactions. This way of ignoring spans is not supported by Datadog. --- CHANGELOG.rst | 6 ++++++ edx_django_utils/__init__.py | 2 +- edx_django_utils/monitoring/README.rst | 6 +++++- edx_django_utils/monitoring/__init__.py | 5 +++-- .../monitoring/internal/backends.py | 18 ++++++++++++++++++ .../monitoring/internal/transactions.py | 16 ++++------------ edx_django_utils/monitoring/internal/utils.py | 13 +++++++++++++ 7 files changed, 50 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 458901c7..61ee87c2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,12 @@ Change Log .. There should always be an "Unreleased" section for changes pending release. +[6.1.0] - 2024-10-15 +--------------------- +Changed +~~~~~~~ +* Added Datadog implementation of ``set_monitoring_transaction_name`` and refactored the functionality. + [6.0.0] - 2024-10-09 --------------------- Added diff --git a/edx_django_utils/__init__.py b/edx_django_utils/__init__.py index f9e1f6ff..0c900198 100644 --- a/edx_django_utils/__init__.py +++ b/edx_django_utils/__init__.py @@ -2,7 +2,7 @@ EdX utilities for Django Application development.. """ -__version__ = "6.0.0" +__version__ = "6.1.0" default_app_config = ( "edx_django_utils.apps.EdxDjangoUtilsConfig" diff --git a/edx_django_utils/monitoring/README.rst b/edx_django_utils/monitoring/README.rst index 4a882d9c..90125270 100644 --- a/edx_django_utils/monitoring/README.rst +++ b/edx_django_utils/monitoring/README.rst @@ -32,7 +32,11 @@ Feature support matrix for built-in telemetry backends: - ✅ - ❌ - ✅ - * - Retrieve and manipulate spans (``get_current_transaction``, ``ignore_transaction``, ``set_monitoring_transaction_name``) + * - Set local root span name (``set_monitoring_transaction_name``) + - ✅ + - ❌ + - ✅ + * - Retrieve and manipulate spans (``get_current_transaction``, ``ignore_transaction``) - ✅ - ❌ - ❌ diff --git a/edx_django_utils/monitoring/__init__.py b/edx_django_utils/monitoring/__init__.py index 92b4d0d0..fd4069a9 100644 --- a/edx_django_utils/monitoring/__init__.py +++ b/edx_django_utils/monitoring/__init__.py @@ -18,7 +18,7 @@ MonitoringMemoryMiddleware, MonitoringSupportMiddleware ) -from .internal.transactions import get_current_transaction, ignore_transaction, set_monitoring_transaction_name +from .internal.transactions import get_current_transaction, ignore_transaction from .internal.utils import ( accumulate, background_task, @@ -26,7 +26,8 @@ increment, record_exception, set_custom_attribute, - set_custom_attributes_for_course_key + set_custom_attributes_for_course_key, + set_monitoring_transaction_name ) # "set_custom_metric*" methods are deprecated from .utils import set_custom_metric, set_custom_metrics_for_course_key diff --git a/edx_django_utils/monitoring/internal/backends.py b/edx_django_utils/monitoring/internal/backends.py index 7113a1e0..d257abbe 100644 --- a/edx_django_utils/monitoring/internal/backends.py +++ b/edx_django_utils/monitoring/internal/backends.py @@ -70,6 +70,12 @@ def tag_root_span_with_error(self, exception): be implemented for OTEL. """ + @abstractmethod + def set_local_root_span_name(self, name, group=None, priority=None): + """ + Sets the name, group, and priority for a span. + """ + class NewRelicBackend(TelemetryBackend): """ @@ -108,6 +114,9 @@ def tag_root_span_with_error(self, exception): # Does not need to be implemented for NewRelic, because it is handled automatically. pass + def set_local_root_span_name(self, name, group=None, priority=None): + newrelic.agent.set_transaction_name(name, group, priority) + class OpenTelemetryBackend(TelemetryBackend): """ @@ -137,6 +146,10 @@ def tag_root_span_with_error(self, exception): # Currently, this is not implemented for OTel pass + def set_local_root_span_name(self, name, group=None, priority=None): + # Currently this is not implemented + pass + class DatadogBackend(TelemetryBackend): """ @@ -165,6 +178,11 @@ def tag_root_span_with_error(self, exception): root_span = self.dd_tracer.current_root_span() root_span.set_exc_info(type(exception), exception, exception.__traceback__) + def set_local_root_span_name(self, name, group=None, priority=None): + # For Datadog, this updates the 'resource_name' to the given name. + local_root_span = self.dd_tracer.current_root_span() + local_root_span.resource = name + # We're using an lru_cache instead of assigning the result to a variable on # module load. With the default settings (pointing to a TelemetryBackend diff --git a/edx_django_utils/monitoring/internal/transactions.py b/edx_django_utils/monitoring/internal/transactions.py index 50111da9..739ba4e8 100644 --- a/edx_django_utils/monitoring/internal/transactions.py +++ b/edx_django_utils/monitoring/internal/transactions.py @@ -16,24 +16,16 @@ newrelic = None # pylint: disable=invalid-name -def set_monitoring_transaction_name(name, group=None, priority=None): - """ - Sets the transaction name for monitoring. - - This is not cached, and only support reporting to New Relic. - - """ - if newrelic: # pragma: no cover - newrelic.agent.set_transaction_name(name, group, priority) - - def ignore_transaction(): """ - Ignore the transaction in monitoring + Ignore the transaction in monitoring. Only works for NewRelic. This allows us to ignore code paths that are unhelpful to include, such as `/health/` checks. + """ + # Note: This is not being ported over to backends, because we don't have + # an equivalent for Datadog. For Datadog, use filter/ignore rules. if newrelic: # pragma: no cover newrelic.agent.ignore_transaction() diff --git a/edx_django_utils/monitoring/internal/utils.py b/edx_django_utils/monitoring/internal/utils.py index 649a95a6..288fb435 100644 --- a/edx_django_utils/monitoring/internal/utils.py +++ b/edx_django_utils/monitoring/internal/utils.py @@ -112,6 +112,19 @@ def function_trace(function_name): yield +def set_monitoring_transaction_name(name, group=None, priority=None): + """ + Sets the name, group, and priority for the current root span. + + Current root span refers to the most ancestral span in the current process, rather than + to the trace root, which may be outside of the process. + + Group and priority may not be supported by all backends. + """ + for backend in configured_backends(): + backend.set_local_root_span_name(name, group=group, priority=priority) + + def background_task(*args, **kwargs): """ Handles monitoring for background tasks that are not passed in through the web server like