From 4e0852965fd564aeb3ded78cfb17e51aab4034fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 24 Jul 2024 14:37:57 +0200 Subject: [PATCH 1/2] stats-prometheus: fix label escaping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://prometheus.io/docs/instrumenting/exposition_formats/#text-format-details Signed-off-by: László Várady --- lib/stats/stats-prometheus.c | 47 +++++++++++++++++++++++-- lib/stats/tests/test_stats_prometheus.c | 30 +++++++++++++++- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/lib/stats/stats-prometheus.c b/lib/stats/stats-prometheus.c index 75af7c90bb..5635721062 100644 --- a/lib/stats/stats-prometheus.c +++ b/lib/stats/stats-prometheus.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2023 László Várady + * Copyright (c) 2024 Axoflow + * Copyright (c) 2023-2024 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,16 +26,56 @@ #include "stats/stats-cluster.h" #include "stats/stats-counter.h" #include "timeutils/unixtime.h" -#include "utf8utils.h" +#include "str-utils.h" #include "scratch-buffers.h" #include + +/* Exposition format: + * + * A label value can be any sequence of UTF-8 characters, but the + * backslash (\), double-quote ("), and line feed (\n) characters have to be + * escaped as \\, \", and \n, respectively. + */ static gchar * stats_format_prometheus_sanitize_label_value(const gchar *value) { GString *sanitized_value = scratch_buffers_alloc(); - append_unsafe_utf8_as_escaped_binary(sanitized_value, value, -1, "\""); + + const gchar *value_end = value + strlen(value); + + while (value < value_end) + { + gunichar uchar = g_utf8_get_char_validated(value, value_end - value); + + if (G_UNLIKELY(uchar == (gunichar) -1 || uchar == (gunichar) -2)) + { + /* double backslash to conform to the format */ + g_string_append_printf(sanitized_value, "\\\\x%02x", *(guint8 *) value); + value++; + continue; + } + + switch (uchar) + { + case '\\': + g_string_append(sanitized_value, "\\\\"); + break; + case '"': + g_string_append(sanitized_value, "\\\""); + break; + case '\n': + g_string_append(sanitized_value, "\\n"); + break; + default: + g_string_append_unichar_optimized(sanitized_value, uchar); + break; + } + + value = g_utf8_next_char(value); + } + return sanitized_value->str; } diff --git a/lib/stats/tests/test_stats_prometheus.c b/lib/stats/tests/test_stats_prometheus.c index 55d0ade64b..2894778320 100644 --- a/lib/stats/tests/test_stats_prometheus.c +++ b/lib/stats/tests/test_stats_prometheus.c @@ -1,5 +1,6 @@ /* - * Copyright (c) 2023 László Várady + * Copyright (c) 2024 Axoflow + * Copyright (c) 2023-2024 László Várady * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -164,6 +165,33 @@ Test(stats_prometheus, test_prometheus_format_sanitize) stats_cluster_free(cluster); } +Test(stats_prometheus, test_prometheus_format_label_escaping) +{ + /* Exposition format: + * + * A label value can be any sequence of UTF-8 characters, but the + * backslash (\), double-quote ("), and line feed (\n) characters have to be + * escaped as \\, \", and \n, respectively. + */ + + StatsClusterLabel labels[] = + { + stats_cluster_label("control_chars", "a\a\tb\nc"), + stats_cluster_label("backslashes", "a\\a\\t\\nb"), + stats_cluster_label("quotes", "\"\"hello\""), + stats_cluster_label("invalid_utf8", "a\xfa"), + }; + StatsCluster *cluster = test_single_cluster("test_name", labels, G_N_ELEMENTS(labels)); + + assert_prometheus_format(cluster, SC_TYPE_SINGLE_VALUE, + "syslogng_test_name{control_chars=\"a\a\tb\\nc\"," + "backslashes=\"a\\\\a\\\\t\\\\nb\"," + "quotes=\"\\\"\\\"hello\\\"\"," + "invalid_utf8=\"a\\\\xfa\"} 0\n"); + + stats_cluster_free(cluster); +} + gchar *stats_format_prometheus_format_value(const StatsClusterKey *key, const StatsCounterItem *counter); Test(stats_prometheus, test_prometheus_format_value) From 24657006f93707aa9ccbf3f050c65355d11a6637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A1szl=C3=B3=20V=C3=A1rady?= Date: Wed, 24 Jul 2024 15:28:45 +0200 Subject: [PATCH 2/2] news: add bugfix entry for #224 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: László Várady --- news/bugfix-224.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 news/bugfix-224.md diff --git a/news/bugfix-224.md b/news/bugfix-224.md new file mode 100644 index 0000000000..1bacb113fa --- /dev/null +++ b/news/bugfix-224.md @@ -0,0 +1,4 @@ +`syslog-ng-ctl`: fix escaping of `stats prometheus` + +Metric labels (for example, the ones produced by `metrics-probe()`) may contain control characters, invalid UTF-8 or `\` +characters. In those specific rare cases, the escaping of the `stats prometheus` output was incorrect.