diff options
author | Erik Johnston <erikj@jki.re> | 2018-05-03 10:01:04 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-05-03 10:01:04 +0100 |
commit | 53a5fdf312e509618539c2a133ef63a9e75cf2ee (patch) | |
tree | 0726fe9c81eb30cb9795d9cff9ecfa07fb959ec8 | |
parent | Merge pull request #3170 from matrix-org/rav/more_logcontext_leaks (diff) | |
parent | Make _escape_character take MatchObject (diff) | |
download | synapse-53a5fdf312e509618539c2a133ef63a9e75cf2ee.tar.xz |
Merge pull request #3175 from matrix-org/erikj/escape_metric_values
Escape label values in prometheus metrics
-rw-r--r-- | synapse/metrics/metric.py | 30 | ||||
-rw-r--r-- | tests/metrics/test_metric.py | 21 |
2 files changed, 48 insertions, 3 deletions
diff --git a/synapse/metrics/metric.py b/synapse/metrics/metric.py index 89bd47c3f7..fbba94e633 100644 --- a/synapse/metrics/metric.py +++ b/synapse/metrics/metric.py @@ -16,6 +16,7 @@ from itertools import chain import logging +import re logger = logging.getLogger(__name__) @@ -56,8 +57,7 @@ class BaseMetric(object): return not len(self.labels) def _render_labelvalue(self, value): - # TODO: escape backslashes, quotes and newlines - return '"%s"' % (value) + return '"%s"' % (_escape_label_value(value),) def _render_key(self, values): if self.is_scalar(): @@ -299,3 +299,29 @@ class MemoryUsageMetric(object): "process_psutil_rss:total %d" % sum_rss, "process_psutil_rss:count %d" % len_rss, ] + + +def _escape_character(m): + """Replaces a single character with its escape sequence. + + Args: + m (re.MatchObject): A match object whose first group is the single + character to replace + + Returns: + str + """ + c = m.group(1) + if c == "\\": + return "\\\\" + elif c == "\"": + return "\\\"" + elif c == "\n": + return "\\n" + return c + + +def _escape_label_value(value): + """Takes a label value and escapes quotes, newlines and backslashes + """ + return re.sub(r"([\n\"\\])", _escape_character, value) diff --git a/tests/metrics/test_metric.py b/tests/metrics/test_metric.py index 39bde6e3f8..069c0be762 100644 --- a/tests/metrics/test_metric.py +++ b/tests/metrics/test_metric.py @@ -16,7 +16,8 @@ from tests import unittest from synapse.metrics.metric import ( - CounterMetric, CallbackMetric, DistributionMetric, CacheMetric + CounterMetric, CallbackMetric, DistributionMetric, CacheMetric, + _escape_label_value, ) @@ -171,3 +172,21 @@ class CacheMetricTestCase(unittest.TestCase): 'cache:size{name="cache_name"} 1', 'cache:evicted_size{name="cache_name"} 2', ]) + + +class LabelValueEscapeTestCase(unittest.TestCase): + def test_simple(self): + string = "safjhsdlifhyskljfksdfh" + self.assertEqual(string, _escape_label_value(string)) + + def test_escape(self): + self.assertEqual( + "abc\\\"def\\nghi\\\\", + _escape_label_value("abc\"def\nghi\\"), + ) + + def test_sequence_of_escapes(self): + self.assertEqual( + "abc\\\"def\\nghi\\\\\\n", + _escape_label_value("abc\"def\nghi\\\n"), + ) |