From 696d9c1864ccdd809c676dcc25e6751c97e24e82 Mon Sep 17 00:00:00 2001 From: Fredrik Ekre Date: Mon, 6 Nov 2023 13:08:38 +0100 Subject: [PATCH] Exposition: escape special characters in help and label values. --- src/Prometheus.jl | 19 +++++++++++++++++-- test/runtests.jl | 15 +++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/Prometheus.jl b/src/Prometheus.jl index 4e559c1..cdbaf49 100644 --- a/src/Prometheus.jl +++ b/src/Prometheus.jl @@ -612,8 +612,21 @@ struct Metric samples::Union{Sample, Vector{Sample}} end +function print_escaped(io::IO, help::String, esc) + for c in help + if c in esc + c == '\n' ? print(io, "\\n") : print(io, '\\', c) + else + print(io, c) + end + end + return +end + function expose_metric(io::IO, metric::Metric) - println(io, "# HELP ", metric.metric_name, " ", metric.help) + print(io, "# HELP ", metric.metric_name, " ") + print_escaped(io, metric.help, ('\\', '\n')) + println(io) println(io, "# TYPE ", metric.metric_name, " ", metric.type) labelnames = metric.labelnames samples = metric.samples @@ -641,7 +654,9 @@ function expose_metric(io::IO, metric::Metric) print(io, "{") for (name, value) in zip(labelnames.labelnames, labels.labelvalues) first || print(io, ",") - print(io, name, "=\"", value, "\"") + print(io, name, "=\"") + print_escaped(io, value, ('\\', '\"', '\n')) + print(io, "\"") first = false end print(io, "}") diff --git a/test/runtests.jl b/test/runtests.jl index af468cc..ed35536 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -422,6 +422,21 @@ end end end +@testset "Character escaping in exposition" begin + counter = Prometheus.Family{Prometheus.Counter}( + "counter_name", "Help with slash \\ and newline \n", ("label_name", ); + registry = nothing, + ) + Prometheus.inc(Prometheus.labels(counter, ("backslash \\, quote \", newline \n", ))) + metric = first(Prometheus.collect(counter)) + @test sprint(Prometheus.expose_metric, metric) == + """ + # HELP counter_name Help with slash \\\\ and newline \\n + # TYPE counter_name counter + counter_name{label_name="backslash \\\\, quote \\", newline \\n"} 1 + """ +end + @testset "Prometheus.expose(::Union{String, IO})" begin r = Prometheus.DEFAULT_REGISTRY empty!(r.collectors)