diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 696b7ff29f..571386da59 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -89,6 +89,7 @@ from openedx.core.djangoapps.external_auth.login_and_register import ( login as external_auth_login, register as external_auth_register ) +from openedx.core.djangoapps import monitoring_utils import track.views @@ -120,8 +121,6 @@ from openedx.core.djangoapps.embargo import api as embargo_api import analytics from eventtracking import tracker -import newrelic_custom_metrics - # Note that this lives in LMS, so this dependency should be refactored. from notification_prefs.views import enable_notifications @@ -654,7 +653,7 @@ def dashboard(request): # Record how many courses there are so that we can get a better # understanding of usage patterns on prod. - newrelic_custom_metrics.accumulate('num_courses', len(course_enrollments)) + monitoring_utils.accumulate('num_courses', len(course_enrollments)) # sort the enrollment pairs by the enrollment date course_enrollments.sort(key=lambda x: x.created, reverse=True) diff --git a/lms/djangoapps/courseware/user_state_client.py b/lms/djangoapps/courseware/user_state_client.py index c1dfe42b82..ac316b876f 100644 --- a/lms/djangoapps/courseware/user_state_client.py +++ b/lms/djangoapps/courseware/user_state_client.py @@ -12,7 +12,6 @@ try: except ImportError: import json -import newrelic_custom_metrics import dogstats_wrapper as dog_stats_api from django.contrib.auth.models import User from django.db import transaction @@ -20,6 +19,7 @@ from django.db.utils import IntegrityError from xblock.fields import Scope from courseware.models import StudentModule, BaseStudentModuleHistory from edx_user_state_client.interface import XBlockUserStateClient, XBlockUserState +from openedx.core.djangoapps import monitoring_utils log = logging.getLogger(__name__) @@ -136,7 +136,7 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient): """ Accumulate arbitrary NR stats (not specific to block types). """ - newrelic_custom_metrics.accumulate( + monitoring_utils.accumulate( self._nr_metric_name(function_name, stat_name), value ) @@ -151,11 +151,11 @@ class DjangoXBlockUserStateClient(XBlockUserStateClient): """ Accumulate NR stats related to block types. """ - newrelic_custom_metrics.accumulate( + monitoring_utils.accumulate( self._nr_metric_name(function_name, stat_name), value, ) - newrelic_custom_metrics.accumulate( + monitoring_utils.accumulate( self._nr_metric_name(function_name, stat_name, block_type=block_type), value, ) diff --git a/lms/envs/common.py b/lms/envs/common.py index 0f81a8c9c2..bb0fc9a00b 100644 --- a/lms/envs/common.py +++ b/lms/envs/common.py @@ -1109,7 +1109,7 @@ MIDDLEWARE_CLASSES = ( 'crum.CurrentRequestUserMiddleware', 'request_cache.middleware.RequestCache', - 'newrelic_custom_metrics.middleware.NewRelicCustomMetrics', + 'openedx.core.djangoapps.monitoring_utils.middleware.MonitoringCustomMetrics', 'mobile_api.middleware.AppVersionUpgrade', 'openedx.core.djangoapps.header_control.middleware.HeaderControlMiddleware', diff --git a/openedx/core/djangoapps/monitoring/README.rst b/openedx/core/djangoapps/monitoring/README.rst new file mode 100644 index 0000000000..4b7617d88b --- /dev/null +++ b/openedx/core/djangoapps/monitoring/README.rst @@ -0,0 +1,6 @@ +This djangoapp is incorrectly named 'monitoring'. + +The name is related to old functionality that used to be a part of this app. + +TODO: The current contents of this app should be joined with other generic +platform utilities and renamed appropriately. diff --git a/common/djangoapps/newrelic_custom_metrics/__init__.py b/openedx/core/djangoapps/monitoring_utils/__init__.py similarity index 61% rename from common/djangoapps/newrelic_custom_metrics/__init__.py rename to openedx/core/djangoapps/monitoring_utils/__init__.py index a695a4a5b0..0234646274 100644 --- a/common/djangoapps/newrelic_custom_metrics/__init__.py +++ b/openedx/core/djangoapps/monitoring_utils/__init__.py @@ -1,11 +1,12 @@ """ -This is an interface to the newrelic_custom_metrics middleware. Functions -defined in this module can be used to report custom metrics to New Relic. For -example: +This is an interface to the monitoring_utils middleware. Functions +defined in this module can be used to report monitoring custom metrics. - import newrelic_custom_metrics +Usage: + + from openedx.core.djangoapps import monitoring_utils ... - newrelic_custom_metrics.accumulate('xb_user_state.get_many.num_items', 4) + monitoring_utils.accumulate('xb_user_state.get_many.num_items', 4) There is no need to do anything else. The metrics are automatically cleared before the next request. @@ -14,24 +15,26 @@ We try to keep track of our custom metrics at: https://openedx.atlassian.net/wiki/display/PERF/Custom+Metrics+in+New+Relic +At this time, these custom metrics will only be reported to New Relic. + TODO: supply additional public functions for storing strings and booleans. + """ -from newrelic_custom_metrics import middleware - +from . import middleware def accumulate(name, value): """ - Accumulate custom New Relic metric for the current request. + Accumulate monitoring custom metric for the current request. The named metric is accumulated by a numerical amount using the sum. All metrics are queued up in the request_cache for this request. At the end of - the request, the newrelic_custom_metrics middleware will batch report all - queued accumulated metrics to NR. + the request, the monitoring_utils middleware will batch report all + queued accumulated metrics to the monitoring tool (e.g. New Relic). Arguments: name (str): The metric name. It should be period-delimited, and - increase in specificty from left to right. For example: + increase in specificity from left to right. For example: 'xb_user_state.get_many.num_items'. value (number): The amount to accumulate into the named metric. When accumulate() is called multiple times for a given metric name @@ -39,12 +42,12 @@ def accumulate(name, value): for that metric. For metrics which don't make sense to accumulate, make sure to only call this function once during a request. """ - middleware.NewRelicCustomMetrics.accumulate_metric(name, value) + middleware.MonitoringCustomMetrics.accumulate_metric(name, value) def increment(name): """ - Increment a custom New Relic metric representing a counter. + Increment a monitoring custom metric representing a counter. Here we simply accumulate a new custom metric with a value of 1, and the middleware should automatically aggregate this metric. diff --git a/common/djangoapps/newrelic_custom_metrics/middleware.py b/openedx/core/djangoapps/monitoring_utils/middleware.py similarity index 89% rename from common/djangoapps/newrelic_custom_metrics/middleware.py rename to openedx/core/djangoapps/monitoring_utils/middleware.py index 3d6bcd89f9..67155bb21f 100644 --- a/common/djangoapps/newrelic_custom_metrics/middleware.py +++ b/openedx/core/djangoapps/monitoring_utils/middleware.py @@ -1,10 +1,13 @@ """ -Middleware for handling the storage, aggregation, and reporing of custom New -Relic metrics. +Middleware for handling the storage, aggregation, and reporting of custom +metrics for monitoring. + +At this time, the custom metrics can only reported to New Relic. This middleware will only call on the newrelic agent if there are any metrics to report for this request, so it will not incur any processing overhead for request handlers which do not record custom metrics. + """ import logging log = logging.getLogger(__name__) @@ -16,10 +19,10 @@ except ImportError: import request_cache -REQUEST_CACHE_KEY = 'newrelic_custom_metrics' +REQUEST_CACHE_KEY = 'monitoring_custom_metrics' -class NewRelicCustomMetrics(object): +class MonitoringCustomMetrics(object): """ The middleware class. Make sure to add below the request cache in MIDDLEWARE_CLASSES. diff --git a/common/djangoapps/newrelic_custom_metrics/tests.py b/openedx/core/djangoapps/monitoring_utils/tests.py similarity index 58% rename from common/djangoapps/newrelic_custom_metrics/tests.py rename to openedx/core/djangoapps/monitoring_utils/tests.py index b1fc931b1a..4410e234a3 100644 --- a/common/djangoapps/newrelic_custom_metrics/tests.py +++ b/openedx/core/djangoapps/monitoring_utils/tests.py @@ -1,27 +1,28 @@ """ -Tests for newrelic custom metrics. +Tests for monitoring custom metrics. """ from django.test import TestCase from mock import patch, call -import newrelic_custom_metrics +from openedx.core.djangoapps import monitoring_utils +from openedx.core.djangoapps.monitoring_utils.middleware import MonitoringCustomMetrics -class TestNewRelicCustomMetrics(TestCase): +class TestMonitoringCustomMetrics(TestCase): """ - Test the newrelic_custom_metrics middleware and helpers + Test the monitoring_utils middleware and helpers """ @patch('newrelic.agent') - def test_cache_normal_contents(self, mock_newrelic_agent): + def test_custom_metrics_with_new_relic(self, mock_newrelic_agent): """ - Test normal usage of collecting and reporting custom New Relic metrics + Test normal usage of collecting custom metrics and reporting to New Relic """ - newrelic_custom_metrics.accumulate('hello', 10) - newrelic_custom_metrics.accumulate('world', 10) - newrelic_custom_metrics.accumulate('world', 10) - newrelic_custom_metrics.increment('foo') - newrelic_custom_metrics.increment('foo') + monitoring_utils.accumulate('hello', 10) + monitoring_utils.accumulate('world', 10) + monitoring_utils.accumulate('world', 10) + monitoring_utils.increment('foo') + monitoring_utils.increment('foo') # based on the metric data above, we expect the following calls to newrelic: nr_agent_calls_expected = [ @@ -31,7 +32,7 @@ class TestNewRelicCustomMetrics(TestCase): ] # fake a response to trigger metrics reporting - newrelic_custom_metrics.middleware.NewRelicCustomMetrics().process_response( + MonitoringCustomMetrics().process_response( 'fake request', 'fake response', )