Merge pull request #3175 from matrix-org/erikj/escape_metric_values
Escape label values in prometheus metricspull/3183/head
commit
53a5fdf312
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
import logging
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -56,8 +57,7 @@ class BaseMetric(object):
|
||||||
return not len(self.labels)
|
return not len(self.labels)
|
||||||
|
|
||||||
def _render_labelvalue(self, value):
|
def _render_labelvalue(self, value):
|
||||||
# TODO: escape backslashes, quotes and newlines
|
return '"%s"' % (_escape_label_value(value),)
|
||||||
return '"%s"' % (value)
|
|
||||||
|
|
||||||
def _render_key(self, values):
|
def _render_key(self, values):
|
||||||
if self.is_scalar():
|
if self.is_scalar():
|
||||||
|
@ -299,3 +299,29 @@ class MemoryUsageMetric(object):
|
||||||
"process_psutil_rss:total %d" % sum_rss,
|
"process_psutil_rss:total %d" % sum_rss,
|
||||||
"process_psutil_rss:count %d" % len_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)
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
from tests import unittest
|
from tests import unittest
|
||||||
|
|
||||||
from synapse.metrics.metric import (
|
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:size{name="cache_name"} 1',
|
||||||
'cache:evicted_size{name="cache_name"} 2',
|
'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"),
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue