Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
02ad9fb
fix: Add management command monitoring pipeline
ktyagiapphelix2u Mar 27, 2026
1c76575
fix: Add management command monitoring pipeline
ktyagiapphelix2u Mar 27, 2026
59a6f4a
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 20, 2026
75ceb43
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 22, 2026
fa0c178
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 22, 2026
2d7cff4
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 23, 2026
cbf2c90
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 28, 2026
4fb153c
fix: Add management command monitoring pipeline
ktyagiapphelix2u Jul 30, 2026
f576d94
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 3, 2026
d898455
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 3, 2026
f85f733
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 6, 2026
f158b15
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 6, 2026
aa5521e
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 7, 2026
5ea2b55
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 7, 2026
79aec8c
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 11, 2026
5e28326
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 11, 2026
94c8d4a
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 12, 2026
58369d5
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 12, 2026
137b948
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 28, 2026
3964f01
fix: Add management command monitoring pipeline
ktyagiapphelix2u Aug 28, 2026
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
1 change: 1 addition & 0 deletions edx_filters_pipelines/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Management command filter pipeline integrations."""
1 change: 1 addition & 0 deletions edx_filters_pipelines/management/pipelines/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Pipeline steps for management command integrations."""
154 changes: 154 additions & 0 deletions edx_filters_pipelines/management/pipelines/monitoring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
"""Pipeline steps for management command observability."""

import logging
import os
import time
from contextlib import contextmanager, nullcontext

from edx_django_utils.monitoring import (
function_trace,
set_custom_attribute,
set_monitoring_transaction_name,
)
from openedx_filters import PipelineStep

from edx_filters_pipelines.waffle import ENABLE_MANAGEMENT_COMMAND_MONITORING

log = logging.getLogger(__name__)

DEFAULT_OPERATION_NAME = 'django.management.command'


@contextmanager
def monitor_management_command(
command_name,
service_variant,
operation_name=DEFAULT_OPERATION_NAME,
):
"""
Wrap a management command execution with monitoring metadata and logging.

The operation name identifies the type of operation, while the resource
name identifies the specific management command being executed.
"""
resource_name = f'{service_variant}.management.{command_name}'

set_monitoring_transaction_name(resource_name)
set_custom_attribute('management_command.name', command_name)
set_custom_attribute('management_command.service_variant', service_variant)

github_run_url = os.getenv('EDX_MC_GITHUB_RUN_URL', '').strip()
if github_run_url:
set_custom_attribute('management_command.github_run_url', github_run_url)

log.info(
'Starting management command: %s service_variant=%s '
'operation_name=%s resource_name=%s',
command_name,
service_variant,
operation_name,
resource_name,
)

start_time = time.monotonic()
status = 'failure'

try:
with function_trace(resource_name, operation_name=operation_name):
yield

Comment thread
ktyagiapphelix2u marked this conversation as resolved.
status = 'success'

except SystemExit as exc:
if exc.code in (0, None):
status = 'success'
else:
set_custom_attribute('management_command.exception_class', exc.__class__.__name__)
set_custom_attribute('management_command.exit_code', exc.code)
set_custom_attribute('management_command.exception_message', str(exc))
log.exception(
'Management command failed: %s service_variant=%s '
'operation_name=%s resource_name=%s exit_code=%s error=%s',
command_name,
service_variant,
operation_name,
resource_name,
exc.code,
exc,
)
raise

except Exception as exc:
set_custom_attribute('management_command.exception_class', exc.__class__.__name__)
set_custom_attribute('management_command.exception_message', str(exc))
log.exception(
'Management command failed: %s service_variant=%s '
'operation_name=%s resource_name=%s exception_class=%s error=%s',
command_name,
service_variant,
operation_name,
resource_name,
exc.__class__.__name__,
exc,
)
raise

finally:
duration = time.monotonic() - start_time
set_custom_attribute('management_command.status', status)
set_custom_attribute('management_command.duration_seconds', duration)
log.info(
'Finished management command: %s service_variant=%s '
'operation_name=%s resource_name=%s status=%s duration_seconds=%s',
command_name,
service_variant,
operation_name,
resource_name,
status,
duration,
)


class ManagementCommandMonitoringPipelineStep(PipelineStep):
"""
Add monitoring around Django management command execution.
"""

def run_filter(
self,
command_contextmanager,
command_name,
service_variant,
): # pylint: disable=arguments-differ
"""
Return a wrapped context manager that applies monitoring when enabled.
"""
operation_name = self.extra_config.get('operation_name', DEFAULT_OPERATION_NAME)

@contextmanager
def wrapped_contextmanager():
monitor_contextmanager = nullcontext()

try:
if ENABLE_MANAGEMENT_COMMAND_MONITORING.is_enabled():
monitor_contextmanager = monitor_management_command(
command_name,
service_variant,
operation_name,
)
except Exception: # pylint: disable=broad-except
log.exception(
'Failed to initialize management command monitoring '
'for %s; continuing without monitoring.',
command_name,
)

with monitor_contextmanager:
with command_contextmanager:
yield

return {
'command_contextmanager': wrapped_contextmanager(),
'command_name': command_name,
'service_variant': service_variant,
}
17 changes: 15 additions & 2 deletions edx_filters_pipelines/waffle.py
Comment thread
ktyagiapphelix2u marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
waffle flags used in the filters_pipelines app.
Feature toggles used in the filters_pipelines app.
"""
from edx_toggles.toggles import WaffleFlag
from edx_toggles.toggles import SettingToggle, WaffleFlag

WAFFLE_NAMESPACE = 'filters_pipelines'

Expand All @@ -14,3 +14,16 @@
# .. toggle_target_removal_date: None because this is a long-term feature
# .. toggle_warning: When the flag is ON, recaptcha validation is enabled on registration.
ENABLE_RECAPTCHA_VALIDATION = WaffleFlag(f'{WAFFLE_NAMESPACE}.enable_registration_recaptcha_validation', __name__)

# .. toggle_name: FILTERS_PIPELINES_ENABLE_MANAGEMENT_COMMAND_MONITORING
# .. toggle_implementation: SettingToggle
# .. toggle_default: False
# .. toggle_description: Settings toggle to enable Datadog monitoring for Django management commands.
# .. toggle_use_cases: opt_in
Comment thread
ktyagiapphelix2u marked this conversation as resolved.
# .. toggle_creation_date: 2026-03-26
# .. toggle_target_removal_date: None because this is a long-term feature
# .. toggle_warning: When the setting is True, management command execution is wrapped with Datadog monitoring.
ENABLE_MANAGEMENT_COMMAND_MONITORING = SettingToggle(
'FILTERS_PIPELINES_ENABLE_MANAGEMENT_COMMAND_MONITORING',
default=False,
)
Comment thread
Copilot marked this conversation as resolved.
1 change: 1 addition & 0 deletions requirements/test.in
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

pytest
pytest-cov # pytest extension for code coverage statistics
pytest-mock # pytest plugin providing mocker fixture
edx-lint
pylint-celery
setuptools
2 changes: 2 additions & 0 deletions requirements/test.txt

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In base.in, you could add a minimum requirement with a comment based on: "Requires edx-django-utils 8.1.0+ for operation_name support.".

@ktyagiapphelix2u ktyagiapphelix2u Aug 28, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked this and agree with the intent, but CI currently cannot resolve edx-django-utils>=8.1.0 from the available package index (latest visible there is 8.0.1), so adding that minimum in base.in causes install failures. I have not added the 8.1.0 floor for now to keep the pipeline green.

Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ pytest-cov==6.2.1
# via
# -r requirements/base.txt
# -r requirements/test.in
pytest-mock
# via -r requirements/test.in
Comment thread
ktyagiapphelix2u marked this conversation as resolved.
python-slugify==8.0.4
# via
# -r requirements/base.txt
Expand Down
Loading
Loading