Escape label values in prometheus metrics

pull/3175/head
Erik Johnston 2018-05-02 16:52:42 +01:00
parent a8d8bf92e0
commit 32015e1109
2 changed files with 40 additions and 3 deletions

View File

@ -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,21 @@ 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(c):
"""Replaces a single character with its escape sequence.
"""
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\"\\])", lambda m: _escape_character(m.group(1)), value)

View File

@ -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"),
)