Skip to content
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
2 changes: 1 addition & 1 deletion cms/templates/widgets/user_dropdown.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from django.conf import settings
from django.urls import reverse
from django.utils.translation import ugettext as _
from edx_django_utils.monitoring import set_custom_metric
from edx_django_utils.monitoring import set_custom_attribute
from student.roles import GlobalStaff
%>

Expand Down
4 changes: 2 additions & 2 deletions common/djangoapps/edxmako/shortcuts.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

from edx_django_utils.monitoring import set_custom_metric
from edx_django_utils.monitoring import set_custom_attribute
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
from openedx.core.djangoapps.theming.helpers import is_request_in_themed_site
from xmodule.util.xmodule_django import get_current_request_hostname
Expand Down Expand Up @@ -95,7 +95,7 @@ def marketing_link(name):
return reverse(link_map[name])
except NoReverseMatch:
log.debug(u"Cannot find corresponding link for name: %s", name)
set_custom_metric('unresolved_marketing_link', name)
set_custom_attribute('unresolved_marketing_link', name)
return '#'
else:
log.debug(u"Cannot find corresponding link for name: %s", name)
Expand Down
8 changes: 4 additions & 4 deletions common/djangoapps/student/views/management.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ def change_enrollment(request, check_access=True):

# Allow us to monitor performance of this transaction on a per-course basis since we often roll-out features
# on a per-course basis.
monitoring_utils.set_custom_metric('course_id', text_type(course_id))
monitoring_utils.set_custom_attribute('course_id', text_type(course_id))

if action == "enroll":
# Make sure the course exists
Expand Down Expand Up @@ -486,12 +486,12 @@ def activate_account(request, key):
"""
# If request is in Studio call the appropriate view
if theming_helpers.get_project_root_name().lower() == u'cms':
monitoring_utils.set_custom_metric('student_activate_account', 'cms')
monitoring_utils.set_custom_attribute('student_activate_account', 'cms')
return activate_account_studio(request, key)

# TODO: Use metric to determine if there are any `activate_account` calls for cms in Production.
# TODO: Use custom attribute to determine if there are any `activate_account` calls for cms in Production.
# If not, the templates wouldn't be needed for cms, but we still need a way to activate for cms tests.
monitoring_utils.set_custom_metric('student_activate_account', 'lms')
monitoring_utils.set_custom_attribute('student_activate_account', 'lms')
try:
registration = Registration.objects.get(activation_key=key)
except (Registration.DoesNotExist, Registration.MultipleObjectsReturned):
Expand Down
2 changes: 1 addition & 1 deletion common/djangoapps/third_party_auth/api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def has_permission(self, request, view):
return False


# TODO: Remove ApiKeyHeaderPermission. Check deprecated_api_key_header custom metric for active usage.
# TODO: Remove ApiKeyHeaderPermission. Check deprecated_api_key_header custom attribute for active usage.
_NOT_JWT_RESTRICTED_TPA_PERMISSIONS = (
C(NotJwtRestrictedApplication) &
(C(IsSuperuser) | ApiKeyHeaderPermission | C(IsStaff))
Expand Down
6 changes: 3 additions & 3 deletions lms/djangoapps/course_home_api/dates/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ def get(self, request, *args, **kwargs):
raise Http404

# Enable NR tracing for this view based on course
monitoring_utils.set_custom_metric('course_id', course_key_string)
monitoring_utils.set_custom_metric('user_id', request.user.id)
monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)
monitoring_utils.set_custom_attribute('course_id', course_key_string)
monitoring_utils.set_custom_attribute('user_id', request.user.id)
monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff)

course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)

Expand Down
6 changes: 3 additions & 3 deletions lms/djangoapps/course_home_api/outline/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ def get(self, request, *args, **kwargs):
raise Http404

# Enable NR tracing for this view based on course
monitoring_utils.set_custom_metric('course_id', course_key_string)
monitoring_utils.set_custom_metric('user_id', request.user.id)
monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)
monitoring_utils.set_custom_attribute('course_id', course_key_string)
monitoring_utils.set_custom_attribute('user_id', request.user.id)
monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff)

course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)

Expand Down
6 changes: 3 additions & 3 deletions lms/djangoapps/course_home_api/progress/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ def get(self, request, *args, **kwargs):
course_key = CourseKey.from_string(course_key_string)

# Enable NR tracing for this view based on course
monitoring_utils.set_custom_metric('course_id', course_key_string)
monitoring_utils.set_custom_metric('user_id', request.user.id)
monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)
monitoring_utils.set_custom_attribute('course_id', course_key_string)
monitoring_utils.set_custom_attribute('user_id', request.user.id)
monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff)

_, request.user = setup_masquerade(
request,
Expand Down
4 changes: 2 additions & 2 deletions lms/djangoapps/courseware/module_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.decorators.csrf import csrf_exempt
from edx_django_utils.cache import RequestCache
from edx_django_utils.monitoring import set_custom_metrics_for_course_key, set_monitoring_transaction_name
from edx_django_utils.monitoring import set_custom_attributes_for_course_key, set_monitoring_transaction_name
from edx_proctoring.api import get_attempt_status_summary
from edx_proctoring.services import ProctoringService
from edx_rest_framework_extensions.auth.jwt.authentication import JwtAuthentication
Expand Down Expand Up @@ -1159,7 +1159,7 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix, course
except InvalidKeyError:
raise Http404

set_custom_metrics_for_course_key(course_key)
set_custom_attributes_for_course_key(course_key)

with modulestore().bulk_operations(course_key):
try:
Expand Down
6 changes: 3 additions & 3 deletions lms/djangoapps/courseware/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3120,8 +3120,8 @@ def test_tab_redirects_if_not_enrolled_and_not_staff(self):
self.assertEqual(response.status_code, 200)

@RELATIVE_DATES_FLAG.override(active=True)
@patch('edx_django_utils.monitoring.set_custom_metric')
def test_defaults(self, mock_set_custom_metric):
@patch('edx_django_utils.monitoring.set_custom_attribute')
def test_defaults(self, mock_set_custom_attribute):
enrollment = CourseEnrollmentFactory(course_id=self.course.id, user=self.user, mode=CourseMode.VERIFIED)
now = datetime.now(utc)
with self.store.bulk_operations(self.course.id):
Expand Down Expand Up @@ -3169,7 +3169,7 @@ def test_defaults(self, mock_set_custom_metric):

response = self._get_response(self.course)

mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True)
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)
self.assertContains(response, subsection.display_name)
# Don't show the Verification Deadline for audit
self.assertNotContains(response, 'Verification Deadline')
Expand Down
4 changes: 2 additions & 2 deletions lms/djangoapps/courseware/views/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from django.views.decorators.cache import cache_control
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic import View
from edx_django_utils.monitoring import set_custom_metrics_for_course_key
from edx_django_utils.monitoring import set_custom_attributes_for_course_key
from opaque_keys import InvalidKeyError
from opaque_keys.edx.keys import CourseKey, UsageKey
from web_fragments.fragment import Fragment
Expand Down Expand Up @@ -134,7 +134,7 @@ def get(self, request, course_id, chapter=None, section=None, position=None):
self.url = request.path

try:
set_custom_metrics_for_course_key(self.course_key)
set_custom_attributes_for_course_key(self.course_key)
self._clean_position()
with modulestore().bulk_operations(self.course_key):

Expand Down
10 changes: 5 additions & 5 deletions lms/djangoapps/courseware/views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
from django.views.decorators.http import require_GET, require_http_methods, require_POST
from django.views.generic import View
from edx_django_utils import monitoring as monitoring_utils
from edx_django_utils.monitoring import set_custom_metrics_for_course_key
from edx_django_utils.monitoring import set_custom_attributes_for_course_key
from ipware.ip import get_ip
from markupsafe import escape
from opaque_keys import InvalidKeyError
Expand Down Expand Up @@ -604,7 +604,7 @@ def get(self, request, course_id, tab_type, **kwargs):
# Must come after masquerading on creation of page context
self.register_user_access_warning_messages(request, course)

set_custom_metrics_for_course_key(course_key)
set_custom_attributes_for_course_key(course_key)
return super(CourseTabView, self).get(request, course=course, page_context=page_context, **kwargs)
except Exception as exception: # pylint: disable=broad-except
return CourseTabView.handle_exceptions(request, course_key, course, exception)
Expand Down Expand Up @@ -1017,9 +1017,9 @@ def dates(request, course_id):
course_key = CourseKey.from_string(course_id)

# Enable NR tracing for this view based on course
monitoring_utils.set_custom_metric('course_id', text_type(course_key))
monitoring_utils.set_custom_metric('user_id', request.user.id)
monitoring_utils.set_custom_metric('is_staff', request.user.is_staff)
monitoring_utils.set_custom_attribute('course_id', text_type(course_key))
monitoring_utils.set_custom_attribute('user_id', request.user.id)
monitoring_utils.set_custom_attribute('is_staff', request.user.is_staff)

course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False)

Expand Down
6 changes: 3 additions & 3 deletions lms/djangoapps/grades/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db.utils import DatabaseError
from edx_django_utils.monitoring import set_custom_metric, set_custom_metrics_for_course_key
from edx_django_utils.monitoring import set_custom_attribute, set_custom_attributes_for_course_key
from opaque_keys.edx.keys import CourseKey, UsageKey
from opaque_keys.edx.locator import CourseLocator
from submissions import api as sub_api
Expand Down Expand Up @@ -213,8 +213,8 @@ def _recalculate_subsection_grade(self, **kwargs):

scored_block_usage_key = UsageKey.from_string(kwargs['usage_id']).replace(course_key=course_key)

set_custom_metrics_for_course_key(course_key)
set_custom_metric('usage_id', six.text_type(scored_block_usage_key))
set_custom_attributes_for_course_key(course_key)
set_custom_attribute('usage_id', six.text_type(scored_block_usage_key))

# The request cache is not maintained on celery workers,
# where this code runs. So we take the values from the
Expand Down
7 changes: 4 additions & 3 deletions lms/djangoapps/monitoring/README.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
This directory contains utilities for adding a code_owner custom metric for help with split-ownership of the LMS.
This directory contains utilities for adding a code_owner custom attribute for help with split-ownership of the LMS.

For details on the decision to implement the code_owner custom metric, see:
For details on the decision to implement the code_owner custom attribute, see:
lms/djangoapps/monitoring/docs/decisions/0001-monitoring-by-code-owner.rst

Originally, this directory contained the ``CodeOwnerMetricMiddleware``, but that has since been moved to:
Originally, this directory contained the ``CodeOwnerMetricMiddleware``, but that has since been moved to
https://github.com/edx/edx-django-utils/tree/master/edx_django_utils/monitoring/code_owner
and renamed ``CodeOwnerMonitoringMiddleware``.

This directory continues to contain scripts that can help generate the appropriate ownership mappings for the LMS.
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ It is currently difficult for different teams to have team-based on-calls rotati
Decision
========

We will implement a custom metric "code_owner" that can be used in NewRelic (or other monitoring solutions that are made pluggable).
We will implement a custom attribute "code_owner" that can be used in NewRelic (or other monitoring solutions that are made pluggable).

The new custom metric makes it simple to query NewRelic for all Transactions or TransactionErrors that are associated with requests with a specific owner. This enables a team to quickly identify data that they own, for use in NewRelic alerts or NewRelic dashboards.
The new custom attribute makes it simple to query NewRelic for all Transactions or TransactionErrors that are associated with requests with a specific owner. This enables a team to quickly identify data that they own, for use in NewRelic alerts or NewRelic dashboards.

To minimize maintenance, the value of the "code_owner" metric will be populated using the source-of-truth of ownership of various parts of edx-platform.
To minimize maintenance, the value of the "code_owner" attribute will be populated using the source-of-truth of ownership of various parts of edx-platform.

See `Rejected Alternatives`_ for details of the decision **not** to split the NewRelic application into multiple NewRelic applications.

Expand All @@ -27,9 +27,9 @@ Note: "owner" is a MySql reserved word, which NewRelic cautions against using, s
Consequences
============

This metric should be quickly available for use with custom alerts and custom dashboards.
This attribute should be quickly available for use with custom alerts and custom dashboards.

In the future, this metric could potentially be added to logging as well.
In the future, this attribute could potentially be added to logging as well.

Rejected Alternatives
=====================
Expand Down
6 changes: 3 additions & 3 deletions lms/envs/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1677,10 +1677,10 @@ def _make_locale_paths(settings): # pylint: disable=missing-function-docstring

# A newer and safer request cache.
'edx_django_utils.cache.middleware.RequestCacheMiddleware',
'edx_django_utils.monitoring.middleware.MonitoringCustomMetricsMiddleware',
'edx_django_utils.monitoring.middleware.CachedCustomMonitoringMiddleware',

# Generate code ownership metrics. Keep this immediately after RequestCacheMiddleware.
'edx_django_utils.monitoring.code_owner.middleware.CodeOwnerMetricMiddleware',
# Generate code ownership attributes. Keep this immediately after RequestCacheMiddleware.
'edx_django_utils.monitoring.code_owner.middleware.CodeOwnerMonitoringMiddleware',

# Cookie monitoring
'openedx.core.lib.request_utils.CookieMetricsMiddleware',
Expand Down
8 changes: 4 additions & 4 deletions openedx/core/djangoapps/oauth_dispatch/adapters/dot.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Adapter to isolate django-oauth-toolkit dependencies
"""

from edx_django_utils.monitoring import set_custom_metric
from edx_django_utils.monitoring import set_custom_attribute
from oauth2_provider import models

from openedx.core.djangoapps.oauth_dispatch.models import RestrictedApplication
Expand Down Expand Up @@ -123,8 +123,8 @@ def _add_org_relation_filters_to_set(self, application, filter_set):
filter_set_before_orgs = filter_set.copy()
filter_set.update([org_relation.to_jwt_filter_claim() for org_relation in application.organizations.all()])

set_custom_metric('filter_set_before_orgs', list(filter_set_before_orgs))
set_custom_metric('filter_set_after_orgs', list(filter_set))
set_custom_metric('filter_set_difference', list(filter_set.difference(filter_set_before_orgs)))
set_custom_attribute('filter_set_before_orgs', list(filter_set_before_orgs))
set_custom_attribute('filter_set_after_orgs', list(filter_set))
set_custom_attribute('filter_set_difference', list(filter_set.difference(filter_set_before_orgs)))

return filter_set
6 changes: 3 additions & 3 deletions openedx/core/djangoapps/oauth_dispatch/jwt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from time import time

from django.conf import settings
from edx_django_utils.monitoring import set_custom_metric
from edx_django_utils.monitoring import set_custom_attribute
from edx_rbac.utils import create_role_auth_claim_for_user
from jwkest import jwk
from jwkest.jws import JWS
Expand Down Expand Up @@ -146,7 +146,7 @@ def _compute_time_fields(expires_in):
"""
now = int(time())
expires_in = expires_in or settings.JWT_AUTH['JWT_EXPIRATION']
set_custom_metric('jwt_expires_in', expires_in)
set_custom_attribute('jwt_expires_in', expires_in)
return now, now + expires_in


Expand Down Expand Up @@ -195,7 +195,7 @@ def _attach_profile_claim(payload, user):

def _encode_and_sign(payload, use_asymmetric_key, secret):
"""Encode and sign the provided payload."""
set_custom_metric('jwt_is_asymmetric', use_asymmetric_key)
set_custom_attribute('jwt_is_asymmetric', use_asymmetric_key)
keys = jwk.KEYS()

if use_asymmetric_key:
Expand Down
12 changes: 6 additions & 6 deletions openedx/core/djangoapps/oauth_dispatch/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,18 +233,18 @@ def test_jwt_access_token_from_parameter_not_header(self, client_attr):
(None, 'no_token_type_supplied'),
)
@ddt.unpack
@patch('edx_django_utils.monitoring.set_custom_metric')
def test_access_token_metrics(self, token_type, expected_token_type, mock_set_custom_metric):
@patch('edx_django_utils.monitoring.set_custom_attribute')
def test_access_token_metrics(self, token_type, expected_token_type, mock_set_custom_attribute):
response = self._post_request(self.user, self.dot_app, token_type=token_type)
self.assertEqual(response.status_code, 200)
expected_calls = [
call('oauth_token_type', expected_token_type),
call('oauth_grant_type', 'password'),
]
mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True)
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)

@patch('edx_django_utils.monitoring.set_custom_metric')
def test_access_token_metrics_for_bad_request(self, mock_set_custom_metric):
@patch('edx_django_utils.monitoring.set_custom_attribute')
def test_access_token_metrics_for_bad_request(self, mock_set_custom_attribute):
grant_type = dot_models.Application.GRANT_PASSWORD
invalid_body = {
'grant_type': grant_type.replace('-', '_'),
Expand All @@ -255,7 +255,7 @@ def test_access_token_metrics_for_bad_request(self, mock_set_custom_metric):
call('oauth_token_type', 'no_token_type_supplied'),
call('oauth_grant_type', 'password'),
]
mock_set_custom_metric.assert_has_calls(expected_calls, any_order=True)
mock_set_custom_attribute.assert_has_calls(expected_calls, any_order=True)

def test_restricted_jwt_access_token(self):
"""
Expand Down
6 changes: 3 additions & 3 deletions openedx/core/djangoapps/oauth_dispatch/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def get_adapter(self, request):
Returns the appropriate adapter based on the OAuth client linked to the request.
"""
client_id = self._get_client_id(request)
monitoring_utils.set_custom_metric('oauth_client_id', client_id)
monitoring_utils.set_custom_attribute('oauth_client_id', client_id)

return self.dot_adapter

Expand Down Expand Up @@ -92,8 +92,8 @@ def dispatch(self, request, *args, **kwargs):

token_type = request.POST.get('token_type',
request.META.get('HTTP_X_TOKEN_TYPE', 'no_token_type_supplied')).lower()
monitoring_utils.set_custom_metric('oauth_token_type', token_type)
monitoring_utils.set_custom_metric('oauth_grant_type', request.POST.get('grant_type', ''))
monitoring_utils.set_custom_attribute('oauth_token_type', token_type)
monitoring_utils.set_custom_attribute('oauth_grant_type', request.POST.get('grant_type', ''))

if response.status_code == 200 and token_type == 'jwt':
response.content = self._build_jwt_response_from_access_token_response(request, response)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ def test_resolver_send(self, mock_ace):

@ddt.data(1, 10, 100)
@patch.object(tasks, 'ace')
@patch.object(resolvers, 'set_custom_metric')
@patch.object(resolvers, 'set_custom_attribute')
def test_schedule_bin(self, schedule_count, mock_metric, mock_ace):
with patch.object(self.task, 'async_send_task') as mock_schedule_send:
current_day, offset, target_day, upgrade_deadline = self._get_dates()
Expand Down
Loading