Skip to content

Commit 3110a05

Browse files
authored
ARCHBOM-1490: fix custom monitoring accumulate (#58)
* fix custom monitoring accumulate The accumulate method wasn't accumulating, and the unit test wasn't working as expected. Also, adds a custom attribute in case of failures. ARCHBOM-1490
1 parent b01b24f commit 3110a05

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ Change Log
1515
Unreleased
1616
~~~~~~~~~~
1717

18+
[3.7.4] - 2020-08-29
19+
~~~~~~~~~~~~~~~~~~~~
20+
21+
* Fix to custom monitoring accumulate to actually accumulate rather than overwrite.
22+
1823
[3.7.3] - 2020-08-12
1924
~~~~~~~~~~~~~~~~~~~~
2025

edx_django_utils/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
EdX utilities for Django Application development..
33
"""
44

5-
__version__ = "3.7.3"
5+
__version__ = "3.7.4"
66

77
default_app_config = (
88
"edx_django_utils.apps.EdxDjangoUtilsConfig"

edx_django_utils/monitoring/middleware.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,21 @@ def accumulate_metric(cls, name, value):
6060
Accumulate a custom metric (name and value) in the metrics cache.
6161
"""
6262
metrics_cache = cls._get_metrics_cache()
63-
metrics_cache.setdefault(name, 0)
64-
metrics_cache.set(name, value)
63+
cached_response = metrics_cache.get_cached_response(name)
64+
if cached_response.is_found:
65+
try:
66+
accumulated_value = value + cached_response.value
67+
except TypeError:
68+
_set_custom_attribute(
69+
'error_adding_accumulated_metric',
70+
'name={}, new_value={}, cached_value={}'.format(
71+
name, repr(value), repr(cached_response.value)
72+
)
73+
)
74+
return
75+
else:
76+
accumulated_value = value
77+
metrics_cache.set(name, accumulated_value)
6578

6679
@classmethod
6780
def _batch_report(cls):
@@ -72,7 +85,7 @@ def _batch_report(cls):
7285
return
7386
metrics_cache = cls._get_metrics_cache()
7487
for key, value in metrics_cache.data.items():
75-
newrelic.agent.add_custom_parameter(key, value)
88+
_set_custom_attribute(key, value)
7689

7790
# Whether or not there was an exception, report any custom NR metrics that
7891
# may have been collected.
@@ -91,6 +104,16 @@ def process_exception(self, request, exception):
91104
self._batch_report()
92105

93106

107+
def _set_custom_attribute(key, value):
108+
"""
109+
Sets monitoring custom attribute.
110+
111+
Note: Can't use public method in ``utils.py`` due to circular reference.
112+
"""
113+
if newrelic: # pragma: no cover
114+
newrelic.agent.add_custom_parameter(key, value)
115+
116+
94117
class MonitoringMemoryMiddleware(MiddlewareMixin):
95118
"""
96119
Middleware for monitoring memory usage.

edx_django_utils/monitoring/tests/test_monitoring.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,24 @@
55
from mock import call, patch
66

77
from edx_django_utils import monitoring
8+
from edx_django_utils.cache import RequestCache
89
from edx_django_utils.monitoring.middleware import MonitoringCustomMetricsMiddleware, MonitoringMemoryMiddleware
910

1011

1112
class TestMonitoringCustomMetrics(TestCase):
1213
"""
1314
Test the monitoring_utils middleware and helpers
1415
"""
16+
def setUp(self):
17+
super(TestMonitoringCustomMetrics, self).setUp()
18+
RequestCache.clear_all_namespaces()
1519

1620
@patch('newrelic.agent')
1721
@override_settings(MIDDLEWARE=[
1822
'edx_django_utils.cache.middleware.RequestCacheMiddleware',
1923
'edx_django_utils.monitoring.middleware.MonitoringCustomMetricsMiddleware',
2024
])
21-
def test_custom_metrics_with_new_relic(self, mock_newrelic_agent):
25+
def test_accumulate_and_increment(self, mock_newrelic_agent):
2226
"""
2327
Test normal usage of collecting custom metrics and reporting to New Relic
2428
"""
@@ -48,7 +52,39 @@ def test_custom_metrics_with_new_relic(self, mock_newrelic_agent):
4852

4953
# Assert call args to newrelic.agent.add_custom_parameter(). Due to
5054
# the nature of python dicts, call order is undefined.
51-
mock_newrelic_agent.add_custom_parameter.has_calls(nr_agent_calls_expected, any_order=True)
55+
mock_newrelic_agent.add_custom_parameter.assert_has_calls(nr_agent_calls_expected, any_order=True)
56+
57+
@patch('newrelic.agent')
58+
@override_settings(MIDDLEWARE=[
59+
'edx_django_utils.cache.middleware.RequestCacheMiddleware',
60+
'edx_django_utils.monitoring.middleware.MonitoringCustomMetricsMiddleware',
61+
])
62+
def test_accumulate_with_illegal_value(self, mock_newrelic_agent):
63+
"""
64+
Test monitoring accumulate with illegal value that can't be added.
65+
"""
66+
monitoring.accumulate('hello', None)
67+
monitoring.accumulate('hello', 10)
68+
69+
# based on the metric data above, we expect the following calls to newrelic:
70+
nr_agent_calls_expected = [
71+
call('hello', None),
72+
call('error_adding_accumulated_metric', 'name=hello, new_value=10, cached_value=None'),
73+
]
74+
75+
# fake a response to trigger metrics reporting
76+
MonitoringCustomMetricsMiddleware().process_response(
77+
'fake request',
78+
'fake response',
79+
)
80+
81+
# Assert call counts to newrelic.agent.add_custom_parameter()
82+
expected_call_count = len(nr_agent_calls_expected)
83+
measured_call_count = mock_newrelic_agent.add_custom_parameter.call_count
84+
self.assertEqual(expected_call_count, measured_call_count)
85+
86+
# Assert call args to newrelic.agent.add_custom_parameter().
87+
mock_newrelic_agent.add_custom_parameter.assert_has_calls(nr_agent_calls_expected, any_order=True)
5288

5389
@override_settings(MIDDLEWARE=[
5490
'edx_django_utils.cache.middleware.RequestCacheMiddleware',

0 commit comments

Comments
 (0)