Skip to content

Commit

Permalink
feat!: switch code owner middleware to signals
Browse files Browse the repository at this point in the history
Initial rollout of moving code_owner monitoring code from
edx-django-utils proved that the new
CodeOwnerMonitoringMiddleware was not added high enough
in the middleware stack. Instead, we have added signals
to edx-django-utils's MonitoringSupportMiddleware, and
this datadog_monitoring plugin now listens to those
signals in order to automatically add code_owner custom
span tags for django requests.

BREAKING CHANGE: Removes CodeOwnerMonitoringMiddleware.

See #784
  • Loading branch information
robrap committed Dec 4, 2024
1 parent 2f09b97 commit 2f18d15
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 259 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ Added
-----
* Adds search script datadog_search.py, for searching Datadog monitors and dashboards.

[6.0.0] - 2024-11-05
~~~~~~~~~~~~~~~~~~~~
Removed
-------
- Removes CodeOwnerMonitoringMiddleware, in favor of using new signals semt from edx-django-utils's MonitoringSupportMiddleware.

[5.1.0] - 2024-11-21
~~~~~~~~~~~~~~~~~~~~
Added
Expand Down
2 changes: 1 addition & 1 deletion edx_arch_experiments/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
A plugin to include applications under development by the architecture team at 2U.
"""

__version__ = '5.1.0'
__version__ = '6.0.0'
89 changes: 0 additions & 89 deletions edx_arch_experiments/datadog_monitoring/code_owner/middleware.py

This file was deleted.

57 changes: 57 additions & 0 deletions edx_arch_experiments/datadog_monitoring/code_owner/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import re

from django.conf import settings
from django.urls import resolve
from edx_django_utils.monitoring import set_custom_attribute

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -147,6 +148,62 @@ def set_code_owner_custom_attributes(code_owner):
set_custom_attribute('code_owner_2_squad', squad)


def set_code_owner_attribute(request):
"""
Sets the code_owner_2 custom attribute for the request.
"""
code_owner = None
module = _get_module_from_request(request)
if module:
code_owner = get_code_owner_from_module(module)

if code_owner:
set_code_owner_custom_attributes(code_owner)


def _get_module_from_request(request):
"""
Get the module from the request path or the current transaction.
Side-effects:
Sets code_owner_2_module custom attribute, used to determine code_owner_2.
If module was not found, may set code_owner_2_path_error custom attribute
if applicable.
Returns:
str: module name or None if not found
"""
if not is_code_owner_mappings_configured():
return None

module, path_error = _get_module_from_request_path(request)
if module:
set_custom_attribute('code_owner_2_module', module)
return module

# monitor errors if module was not found
if path_error:
set_custom_attribute('code_owner_2_path_error', path_error)
return None


def _get_module_from_request_path(request):
"""
Uses the request path to get the view_func module.
Returns:
(str, str): (module, error_message), where at least one of these should be None
"""
try:
view_func, _, _ = resolve(request.path)
module = view_func.__module__
return module, None
except Exception as e: # pragma: no cover, pylint: disable=broad-exception-caught
return None, str(e)


def clear_cached_mappings():
"""
Clears the cached code owner mappings. Useful for testing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,19 @@ If you want to learn more about custom span tags in general, see `Enhanced Monit
.. _ADR on monitoring by code owner: https://github.com/openedx/edx-platform/blob/master/lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst
.. _Enhanced Monitoring and Custom Attributes: https://edx.readthedocs.io/projects/edx-django-utils/en/latest/monitoring/how_tos/using_custom_attributes.html

Setting up the Middleware
-------------------------
What gets code_owner span tags
------------------------------

You simply need to add ``edx_arch_experiments.datadog_monitoring.code_owner.middleware.CodeOwnerMonitoringMiddleware`` to get code owner span tags on Django requests.
Simply by installing the datadog_monitoring plugin, code owner span tags will automatically be added for:

Handling celery tasks
---------------------

For celery tasks, this plugin will automatically detect and add code owner span tags to any span with ``operation_name:celery.run``.

This is accomplished by receiving signals from celery's worker_process_init for each process, and then adding a custom Datadog span processor to add the span tags as appropriate.
* ``operation_name:django.request``: tags are added by using edx-django-utils monitoring signals, which are sent by its MonitoringSupportMiddleware.
* ``operation_name:celery.run``: tags are added using celery's ``worker_process_init`` signal, and then adding a custom Datadog span processor to add the span tags as appropriate.

Configuring your app settings
-----------------------------

Once the Middleware is made available, simply set the Django Settings ``CODE_OWNER_MAPPINGS`` and ``CODE_OWNER_THEMES`` appropriately.

The following example shows how you can include an optional config for a catch-all using ``'*'``. Although you might expect this example to use Python, it is intentionally illustrated in YAML because the catch-all requires special care in YAML.

::

# YAML format of example CODE_OWNER_MAPPINGS
Expand All @@ -50,7 +44,7 @@ The following example shows how you can include an optional config for a catch-a
- xblock_django
- openedx.core.djangoapps.xblock
theme-x-team-blue:
- '*' # IMPORTANT: you must surround * with quotes in yml
- lms

# YAML format of example CODE_OWNER_THEMES
CODE_OWNER_THEMES:
Expand Down
32 changes: 31 additions & 1 deletion edx_arch_experiments/datadog_monitoring/signals/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,43 @@

from celery.signals import worker_process_init
from django.dispatch import receiver
from edx_django_utils.monitoring.signals import (
monitoring_support_process_exception,
monitoring_support_process_request,
monitoring_support_process_response,
)

from edx_arch_experiments.datadog_monitoring.code_owner.datadog import CeleryCodeOwnerSpanProcessor
from edx_arch_experiments.datadog_monitoring.code_owner.utils import set_code_owner_attribute

log = logging.getLogger(__name__)


@receiver(worker_process_init)
@receiver(monitoring_support_process_response, dispatch_uid=f"datadog_monitoring_support_process_response")
def datadog_monitoring_support_process_response(sender, **kwargs):
"""
Adds datadog monitoring at monitoring process response time.
"""
if 'request' in kwargs:
set_code_owner_attribute(kwargs['request'])
else:
log.warning('monitoring_support_process_response sent without '
'expected parameter: request.')


@receiver(monitoring_support_process_exception, dispatch_uid=f"datadog_monitoring_support_process_exception")
def datadog_monitoring_support_process_exception(sender, **kwargs):
"""
Adds datadog monitoring at monitoring process exception time.
"""
if 'request' in kwargs:
set_code_owner_attribute(kwargs['request'])
else:
log.warning('monitoring_support_process_exception sent without '
'expected parameter: request.')


@receiver(worker_process_init, dispatch_uid=f"datadog_span_processor_worker_process_init")
def init_worker_process(sender, **kwargs):
"""
Adds a Datadog span processor to each worker process.
Expand Down
Loading

0 comments on commit 2f18d15

Please sign in to comment.