Comparison

util/openmetrics.lua @ 11929:85d51bfcf56b

mod_http_openmetrics: Imported from prosody-modules mod_prometheus @df2246b15075 This version has several changes from the earlier mod_prometheus: - Conversion of metrics into the text-based OpenMetrics format is moved to util.openmetrics - Support for IP-based access control - Compatibility with earlier Prosody versions removed
author Matthew Wild <mwild1@gmail.com>
date Wed, 24 Nov 2021 16:03:05 +0000
parent 11600:a02c277eb97a
child 12387:05c250fa335a
comparison
equal deleted inserted replaced
11928:16cf863b36c0 11929:85d51bfcf56b
23 local select = select; 23 local select = select;
24 local array = require "util.array"; 24 local array = require "util.array";
25 local log = require "util.logger".init("util.openmetrics"); 25 local log = require "util.logger".init("util.openmetrics");
26 local new_multitable = require "util.multitable".new; 26 local new_multitable = require "util.multitable".new;
27 local iter_multitable = require "util.multitable".iter; 27 local iter_multitable = require "util.multitable".iter;
28 local t_concat, t_insert = table.concat, table.insert;
28 local t_pack, t_unpack = require "util.table".pack, table.unpack or unpack; --luacheck: ignore 113/unpack 29 local t_pack, t_unpack = require "util.table".pack, table.unpack or unpack; --luacheck: ignore 113/unpack
29 30
30 -- BEGIN of Utility: "metric proxy" 31 -- BEGIN of Utility: "metric proxy"
31 -- This allows to wrap a MetricFamily in a proxy which only provides the 32 -- This allows to wrap a MetricFamily in a proxy which only provides the
32 -- `with_labels` and `with_partial_label` methods. This allows to pre-set one 33 -- `with_labels` and `with_partial_label` methods. This allows to pre-set one
49 end 50 end
50 } 51 }
51 end 52 end
52 53
53 -- END of Utility: "metric proxy" 54 -- END of Utility: "metric proxy"
55
56 -- BEGIN Rendering helper functions (internal)
57
58 local function escape(text)
59 return text:gsub("\\", "\\\\"):gsub("\"", "\\\""):gsub("\n", "\\n");
60 end
61
62 local function escape_name(name)
63 return name:gsub("/", "__"):gsub("[^A-Za-z0-9_]", "_"):gsub("^[^A-Za-z_]", "_%1");
64 end
65
66 local function repr_help(metric, docstring)
67 docstring = docstring:gsub("\\", "\\\\"):gsub("\n", "\\n");
68 return "# HELP "..escape_name(metric).." "..docstring.."\n";
69 end
70
71 local function repr_unit(metric, unit)
72 if not unit then
73 unit = ""
74 else
75 unit = unit:gsub("\\", "\\\\"):gsub("\n", "\\n");
76 end
77 return "# UNIT "..escape_name(metric).." "..unit.."\n";
78 end
79
80 -- local allowed_types = { counter = true, gauge = true, histogram = true, summary = true, untyped = true };
81 -- local allowed_types = { "counter", "gauge", "histogram", "summary", "untyped" };
82 local function repr_type(metric, type_)
83 -- if not allowed_types:contains(type_) then
84 -- return;
85 -- end
86 return "# TYPE "..escape_name(metric).." "..type_.."\n";
87 end
88
89 local function repr_label(key, value)
90 return key.."=\""..escape(value).."\"";
91 end
92
93 local function repr_labels(labelkeys, labelvalues, extra_labels)
94 local values = {}
95 if labelkeys then
96 for i, key in ipairs(labelkeys) do
97 local value = labelvalues[i]
98 t_insert(values, repr_label(escape_name(key), escape(value)));
99 end
100 end
101 if extra_labels then
102 for key, value in pairs(extra_labels) do
103 t_insert(values, repr_label(escape_name(key), escape(value)));
104 end
105 end
106 if #values == 0 then
107 return "";
108 end
109 return "{"..t_concat(values, ",").."}";
110 end
111
112 local function repr_sample(metric, labelkeys, labelvalues, extra_labels, value)
113 return escape_name(metric)..repr_labels(labelkeys, labelvalues, extra_labels).." "..string.format("%.17g", value).."\n";
114 end
115
116 -- END Rendering helper functions (internal)
54 117
55 local function render_histogram_le(v) 118 local function render_histogram_le(v)
56 if v == 1/0 then 119 if v == 1/0 then
57 -- I-D-00: 4.1.2.2.1: 120 -- I-D-00: 4.1.2.2.1:
58 -- Exposers MUST produce output for positive infinity as +Inf. 121 -- Exposers MUST produce output for positive infinity as +Inf.
284 347
285 function metric_registry_mt:get_metric_families() 348 function metric_registry_mt:get_metric_families()
286 return self.families 349 return self.families
287 end 350 end
288 351
352 function metric_registry_mt:render()
353 local answer = {};
354 for metric_family_name, metric_family in pairs(self:get_metric_families()) do
355 t_insert(answer, repr_help(metric_family_name, metric_family.description))
356 t_insert(answer, repr_unit(metric_family_name, metric_family.unit))
357 t_insert(answer, repr_type(metric_family_name, metric_family.type_))
358 for labelset, metric in metric_family:iter_metrics() do
359 for suffix, extra_labels, value in metric:iter_samples() do
360 t_insert(answer, repr_sample(metric_family_name..suffix, metric_family.label_keys, labelset, extra_labels, value))
361 end
362 end
363 end
364 t_insert(answer, "# EOF\n")
365 return t_concat(answer, "");
366 end
367
289 -- END of MetricRegistry implementation 368 -- END of MetricRegistry implementation
290 369
291 -- BEGIN of general helpers for implementing high-level APIs on top of OpenMetrics 370 -- BEGIN of general helpers for implementing high-level APIs on top of OpenMetrics
292 371
293 local function timed(metric) 372 local function timed(metric)