From fa22d40ba35519453adbfb3fa900035f30e7c1d6 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 24 Nov 2021 16:03:05 +0000 Subject: 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 --- util/openmetrics.lua | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) (limited to 'util/openmetrics.lua') diff --git a/util/openmetrics.lua b/util/openmetrics.lua index a3ef827b..2fb8b967 100644 --- a/util/openmetrics.lua +++ b/util/openmetrics.lua @@ -25,6 +25,7 @@ local array = require "util.array"; local log = require "util.logger".init("util.openmetrics"); local new_multitable = require "util.multitable".new; local iter_multitable = require "util.multitable".iter; +local t_concat, t_insert = table.concat, table.insert; local t_pack, t_unpack = require "util.table".pack, table.unpack or unpack; --luacheck: ignore 113/unpack -- BEGIN of Utility: "metric proxy" @@ -52,6 +53,68 @@ end -- END of Utility: "metric proxy" +-- BEGIN Rendering helper functions (internal) + +local function escape(text) + return text:gsub("\\", "\\\\"):gsub("\"", "\\\""):gsub("\n", "\\n"); +end + +local function escape_name(name) + return name:gsub("/", "__"):gsub("[^A-Za-z0-9_]", "_"):gsub("^[^A-Za-z_]", "_%1"); +end + +local function repr_help(metric, docstring) + docstring = docstring:gsub("\\", "\\\\"):gsub("\n", "\\n"); + return "# HELP "..escape_name(metric).." "..docstring.."\n"; +end + +local function repr_unit(metric, unit) + if not unit then + unit = "" + else + unit = unit:gsub("\\", "\\\\"):gsub("\n", "\\n"); + end + return "# UNIT "..escape_name(metric).." "..unit.."\n"; +end + +-- local allowed_types = { counter = true, gauge = true, histogram = true, summary = true, untyped = true }; +-- local allowed_types = { "counter", "gauge", "histogram", "summary", "untyped" }; +local function repr_type(metric, type_) + -- if not allowed_types:contains(type_) then + -- return; + -- end + return "# TYPE "..escape_name(metric).." "..type_.."\n"; +end + +local function repr_label(key, value) + return key.."=\""..escape(value).."\""; +end + +local function repr_labels(labelkeys, labelvalues, extra_labels) + local values = {} + if labelkeys then + for i, key in ipairs(labelkeys) do + local value = labelvalues[i] + t_insert(values, repr_label(escape_name(key), escape(value))); + end + end + if extra_labels then + for key, value in pairs(extra_labels) do + t_insert(values, repr_label(escape_name(key), escape(value))); + end + end + if #values == 0 then + return ""; + end + return "{"..t_concat(values, ",").."}"; +end + +local function repr_sample(metric, labelkeys, labelvalues, extra_labels, value) + return escape_name(metric)..repr_labels(labelkeys, labelvalues, extra_labels).." "..string.format("%.17g", value).."\n"; +end + +-- END Rendering helper functions (internal) + local function render_histogram_le(v) if v == 1/0 then -- I-D-00: 4.1.2.2.1: @@ -286,6 +349,22 @@ function metric_registry_mt:get_metric_families() return self.families end +function metric_registry_mt:render() + local answer = {}; + for metric_family_name, metric_family in pairs(self:get_metric_families()) do + t_insert(answer, repr_help(metric_family_name, metric_family.description)) + t_insert(answer, repr_unit(metric_family_name, metric_family.unit)) + t_insert(answer, repr_type(metric_family_name, metric_family.type_)) + for labelset, metric in metric_family:iter_metrics() do + for suffix, extra_labels, value in metric:iter_samples() do + t_insert(answer, repr_sample(metric_family_name..suffix, metric_family.label_keys, labelset, extra_labels, value)) + end + end + end + t_insert(answer, "# EOF\n") + return t_concat(answer, ""); +end + -- END of MetricRegistry implementation -- BEGIN of general helpers for implementing high-level APIs on top of OpenMetrics -- cgit v1.2.3