diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5b60c7b0..bbc8900f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,19 @@ Change Log Unreleased ~~~~~~~~~~ +[3.13.0] - 2020-11-18 +~~~~~~~~~~~~~~~~~~~~~ + +Added +_____ + +* Added record_exception to monitor caught exceptions. + +Updated +_______ + +* Added additional details to the `deprecated_monitoring_utils` custom attribute values to make it simpler to track down usage. + [3.12.0] - 2020-11-17 ~~~~~~~~~~~~~~~~~~~~~ diff --git a/edx_django_utils/__init__.py b/edx_django_utils/__init__.py index 6654226c..72ec8011 100644 --- a/edx_django_utils/__init__.py +++ b/edx_django_utils/__init__.py @@ -2,7 +2,7 @@ EdX utilities for Django Application development.. """ -__version__ = "3.12.0" +__version__ = "3.13.0" default_app_config = ( "edx_django_utils.apps.EdxDjangoUtilsConfig" diff --git a/edx_django_utils/monitoring/README.rst b/edx_django_utils/monitoring/README.rst index ffa324cf..a26c8b80 100644 --- a/edx_django_utils/monitoring/README.rst +++ b/edx_django_utils/monitoring/README.rst @@ -3,6 +3,8 @@ Monitoring Utils This is our primary abstraction from 3rd party monitoring libraries such as newrelic.agent. It includes middleware and utility methods for adding custom attributes and for better monitoring memory consumption. +See ``__init__.py`` for a list of everything included in the public API. + If, for some reason, you need low level access to the newrelic agent, please extend this library to implement the feature that you want. Applications should never include ``import newrelic.agent`` directly. Using Custom Attributes diff --git a/edx_django_utils/monitoring/__init__.py b/edx_django_utils/monitoring/__init__.py index a929a1b2..191f5b0c 100644 --- a/edx_django_utils/monitoring/__init__.py +++ b/edx_django_utils/monitoring/__init__.py @@ -16,6 +16,12 @@ ignore_transaction, set_monitoring_transaction_name ) -from .internal.utils import accumulate, increment, set_custom_attribute, set_custom_attributes_for_course_key +from .internal.utils import ( + accumulate, + increment, + record_exception, + set_custom_attribute, + set_custom_attributes_for_course_key +) # "set_custom_metric*" methods are deprecated from .utils import set_custom_metric, set_custom_metrics_for_course_key diff --git a/edx_django_utils/monitoring/internal/utils.py b/edx_django_utils/monitoring/internal/utils.py index 3990890f..f026cf65 100644 --- a/edx_django_utils/monitoring/internal/utils.py +++ b/edx_django_utils/monitoring/internal/utils.py @@ -21,7 +21,7 @@ try: import newrelic.agent -except ImportError: +except ImportError: # pragma: no cover newrelic = None # pylint: disable=invalid-name @@ -80,3 +80,19 @@ def set_custom_attribute(key, value): if newrelic: # pragma: no cover # note: parameter is new relic's older name for attributes newrelic.agent.add_custom_parameter(key, value) + + +def record_exception(): + """ + Records a caught exception to the monitoring system. + + Note: By default, only unhandled exceptions are monitored. This function + can be called to record exceptions as monitored errors, even if you handle + the exception gracefully from a user perspective. + + For more details, see: + https://docs.newrelic.com/docs/agents/python-agent/python-agent-api/recordexception-python-agent-api + + """ + if newrelic: # pragma: no cover + newrelic.agent.record_exception() diff --git a/edx_django_utils/monitoring/tests/test_monitoring.py b/edx_django_utils/monitoring/tests/test_monitoring.py index 25ba40c5..f969a54e 100644 --- a/edx_django_utils/monitoring/tests/test_monitoring.py +++ b/edx_django_utils/monitoring/tests/test_monitoring.py @@ -6,7 +6,13 @@ from mock import call, patch from edx_django_utils.cache import RequestCache -from edx_django_utils.monitoring import CachedCustomMonitoringMiddleware, accumulate, get_current_transaction, increment +from edx_django_utils.monitoring import ( + CachedCustomMonitoringMiddleware, + accumulate, + get_current_transaction, + increment, + record_exception +) from ..middleware import CachedCustomMonitoringMiddleware as DeprecatedCachedCustomMonitoringMiddleware from ..middleware import MonitoringCustomMetricsMiddleware as DeprecatedMonitoringCustomMetricsMiddleware @@ -137,3 +143,8 @@ def test_deprecated_set_custom_attribute(self, mock_set_custom_attribute): def test_deprecated_set_custom_attributes_for_course_key(self, mock_set_custom_attributes_for_course_key): deprecated_set_custom_attributes_for_course_key('key') mock_set_custom_attributes_for_course_key.assert_called_with('key') + + @patch('newrelic.agent.record_exception') + def test_record_exception(self, mock_record_exception): + record_exception() + mock_record_exception.assert_called_once() diff --git a/edx_django_utils/monitoring/utils.py b/edx_django_utils/monitoring/utils.py index 357d9b8d..efbdbb3b 100644 --- a/edx_django_utils/monitoring/utils.py +++ b/edx_django_utils/monitoring/utils.py @@ -19,7 +19,7 @@ def accumulate(name, value): """ msg = "Use 'monitoring.accumulate' in place of 'monitoring.utils.accumulate'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'accumulate') + internal_set_custom_attribute('deprecated_monitoring_utils', 'accumulate[{}]'.format(name)) internal_accumulate(name, value) @@ -29,7 +29,7 @@ def increment(name): """ msg = "Use 'monitoring.increment' in place of 'monitoring.utils.increment'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'increment') + internal_set_custom_attribute('deprecated_monitoring_utils', 'increment[{}]'.format(name)) internal_increment(name) @@ -39,7 +39,7 @@ def set_custom_attribute(key, value): """ msg = "Use 'monitoring.set_custom_attribute' in place of 'monitoring.utils.set_custom_attribute'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_attribute') + internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_attribute[{}]'.format(key)) internal_set_custom_attribute(key, value) @@ -50,7 +50,10 @@ def set_custom_attributes_for_course_key(course_key): msg = "Use 'monitoring.set_custom_attributes_for_course_key' in place of " \ "'monitoring.utils.set_custom_attributes_for_course_key'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_attributes_for_course_key') + internal_set_custom_attribute( + 'deprecated_monitoring_utils', + 'set_custom_attributes_for_course_key[{}]'.format(str(course_key)) + ) internal_set_custom_attributes_for_course_key(course_key) @@ -60,7 +63,7 @@ def set_custom_metric(key, value): # pragma: no cover """ msg = "Use 'set_custom_attribute' in place of 'set_custom_metric'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_metric') + internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_metric[{}]'.format(key)) internal_set_custom_attribute(key, value) @@ -70,5 +73,8 @@ def set_custom_metrics_for_course_key(course_key): # pragma: no cover """ msg = "Use 'set_custom_attributes_for_course_key' in place of 'set_custom_metrics_for_course_key'." warnings.warn(msg, DeprecationWarning) - internal_set_custom_attribute('deprecated_monitoring_utils', 'set_custom_metrics_for_course_key') + internal_set_custom_attribute( + 'deprecated_monitoring_utils', + 'set_custom_metrics_for_course_key[{}]'.format(str(course_key)) + ) internal_set_custom_attributes_for_course_key(course_key)