-
Notifications
You must be signed in to change notification settings - Fork 3
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: refactor code_owner code from edx-dajango-utils #838
base: main
Are you sure you want to change the base?
Changes from 1 commit
bd1cb6b
d9566de
4908ac8
1d3af1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Datadog Monitoring | ||
################### | ||
|
||
When installed in the LMS as a plugin app, the ``datadog_monitoring`` app adds additional monitoring. | ||
|
||
This is where our code_owner_2 monitoring code lives, for example. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" | ||
App for 2U-specific edx-platform Datadog monitoring. | ||
""" | ||
|
||
import logging | ||
|
||
from django.apps import AppConfig | ||
|
||
from .code_owner.utils import get_code_owner_from_module | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
class DatadogMonitoringSpanProcessor: | ||
"""Datadog span processor that adds custom monitoring (e.g. code owner tags).""" | ||
|
||
def on_span_start(self, span): | ||
if not span or not getattr(span, 'name') or not getattr(span, 'resource'): | ||
return | ||
|
||
if span.name == 'celery.run': | ||
# We can use this for celery spans, because the resource name is more predictable | ||
# and available from the start. For django requests, we'll instead continue to use | ||
# django middleware for setting code owner. | ||
get_code_owner_from_module(span.resource) | ||
|
||
def on_span_finish(self, span): | ||
pass | ||
|
||
def shutdown(self, _timeout): | ||
pass | ||
|
||
|
||
class DatadogMonitoring(AppConfig): | ||
""" | ||
Django application to handle 2U-specific Datadog monitoring. | ||
""" | ||
name = 'edx_arch_experiments.datadog_monitoring' | ||
|
||
# Mark this as a plugin app | ||
plugin_app = {} | ||
|
||
def ready(self): | ||
try: | ||
from ddtrace import tracer # pylint: disable=import-outside-toplevel | ||
# QUESTION: Do we want to publish a base constraint that avoids DD major changes without first testing them? | ||
tracer._span_processors.append(DatadogMonitoringSpanProcessor()) # pylint: disable=protected-access | ||
log.info("Attached DatadogMonitoringSpanProcessor") | ||
except ImportError: | ||
log.warning( | ||
"Unable to attach DatadogMonitoringSpanProcessor" | ||
" -- ddtrace module not found." | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,13 @@ | ||
""" | ||
Utilities for monitoring code_owner | ||
Utilities for monitoring code_owner_2 | ||
""" | ||
import logging | ||
import re | ||
from functools import wraps | ||
|
||
from django.conf import settings | ||
|
||
from ..utils import set_custom_attribute | ||
from edx_django_utils.monitoring import set_custom_attribute | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
@@ -88,7 +88,9 @@ def get_code_owner_mappings(): | |
# .. setting_description: Used for monitoring and reporting of ownership. Use a | ||
# dict with keys of code owner name and value as a list of dotted path | ||
# module names owned by the code owner. | ||
code_owner_mappings = getattr(settings, 'CODE_OWNER_MAPPINGS', {}) | ||
code_owner_mappings = getattr(settings, 'CODE_OWNER_MAPPINGS', None) | ||
if code_owner_mappings is None: | ||
return None | ||
Comment on lines
+90
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for Reviewer: A bug was found in this code, because there was a bug in the original test for this that didn't catch this problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What impact would this have had? |
||
|
||
try: | ||
for code_owner in code_owner_mappings: | ||
|
@@ -110,73 +112,54 @@ def get_code_owner_mappings(): | |
return _PATH_TO_CODE_OWNER_MAPPINGS | ||
|
||
|
||
def _get_catch_all_code_owner(): | ||
""" | ||
If the catch-all module "*" is configured, return the code_owner. | ||
|
||
Returns: | ||
(str): code_owner or None if no catch-all configured. | ||
|
||
""" | ||
try: | ||
code_owner = get_code_owner_from_module('*') | ||
return code_owner | ||
except Exception as e: # pragma: no cover | ||
# will remove broad exceptions after ensuring all proper cases are covered | ||
set_custom_attribute('deprecated_broad_except___get_module_from_current_transaction', e.__class__) | ||
return None | ||
|
||
|
||
def set_code_owner_attribute_from_module(module): | ||
""" | ||
Updates the code_owner and code_owner_module custom attributes. | ||
Updates the code_owner_2 and code_owner_2_module custom attributes. | ||
|
||
Celery tasks or other non-web functions do not use middleware, so we need | ||
an alternative way to set the code_owner custom attribute. | ||
an alternative way to set the code_owner_2 custom attribute. | ||
|
||
Note: These settings will be overridden by the CodeOwnerMonitoringMiddleware. | ||
This method can't be used to override web functions at this time. | ||
|
||
Usage:: | ||
|
||
set_code_owner_attribute_from_module(__name__) | ||
set_code_owner_2_attribute_from_module(__name__) | ||
|
||
""" | ||
set_custom_attribute('code_owner_module', module) | ||
set_custom_attribute('code_owner_2_module', module) | ||
code_owner = get_code_owner_from_module(module) | ||
if not code_owner: | ||
code_owner = _get_catch_all_code_owner() | ||
|
||
if code_owner: | ||
set_code_owner_custom_attributes(code_owner) | ||
|
||
|
||
def set_code_owner_custom_attributes(code_owner): | ||
""" | ||
Sets custom metrics for code_owner, code_owner_theme, and code_owner_squad | ||
Sets custom metrics for code_owner_2, code_owner_2_theme, and code_owner_2_squad | ||
""" | ||
if not code_owner: # pragma: no cover | ||
return | ||
set_custom_attribute('code_owner', code_owner) | ||
set_custom_attribute('code_owner_2', code_owner) | ||
theme = _get_theme_from_code_owner(code_owner) | ||
if theme: | ||
set_custom_attribute('code_owner_theme', theme) | ||
set_custom_attribute('code_owner_2_theme', theme) | ||
squad = _get_squad_from_code_owner(code_owner) | ||
if squad: | ||
set_custom_attribute('code_owner_squad', squad) | ||
set_custom_attribute('code_owner_2_squad', squad) | ||
|
||
|
||
def set_code_owner_attribute(wrapped_function): | ||
""" | ||
Decorator to set the code_owner and code_owner_module custom attributes. | ||
Decorator to set the code_owner_2 and code_owner_2_module custom attributes. | ||
|
||
Celery tasks or other non-web functions do not use middleware, so we need | ||
an alternative way to set the code_owner custom attribute. | ||
an alternative way to set the code_owner_2 custom attribute. | ||
|
||
Usage:: | ||
|
||
@task() | ||
@set_code_owner_attribute | ||
@set_code_owner_2_attribute | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unneeded change here -- can just delete these functions, though. |
||
def example_task(): | ||
... | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be
set_code_owner_attribute_from_module
?