Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: switch code owner middleware to signals #866

Merged
merged 2 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ Change Log

Unreleased
~~~~~~~~~~

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

Added
-----
* Adds search script datadog_search.py, for searching Datadog monitors and dashboards.
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 @@ -4,6 +4,7 @@
import logging

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 @@ -141,6 +142,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, request=None, **kwargs):
"""
Adds datadog monitoring at monitoring process response time.
"""
if request:
set_code_owner_attribute(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, request=None, **kwargs):
"""
Adds datadog monitoring at monitoring process exception time.
"""
if request:
set_code_owner_attribute(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
Loading