1
0
Fork 0
promscripts/prom.awk

122 lines
3.7 KiB
Awk
Raw Normal View History

# Library for generation of Prometheus metrics in GNU Awk
#
# Copyright (C) 2021 Mike Gerwitz
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This library is not written for my particular uses (and style) and is not
# comprehensive.
# Declare a counter of the name NAME with the help string HELP.
function prom_declare_counter(name, help) {
_prom_declare_metric(name, "counter", help)
}
# Declare a gauge of the name NAME with the help string HELP.
function prom_declare_gauge(name, help) {
_prom_declare_metric(name, "gauge", help)
}
# Declare a metric of the name NAME with the type TYPE and the help string
# HELP.
#
# Prometheus metric names (NAME) must follow the pattern
# `[a-zA-Z_:][a-zA-Z0-9_:]*`, but colons are reserved for user-defined
# metrics (e.g. rules), and should not be used by exporters (like us).
function _prom_declare_metric(name, type, help) {
# Omit colons (see docblock) when verifying name.
if (!(name ~ /^[a-zA_Z_][a-zA-Z0-9_]*/)) {
_prom_fatal("invalid metric name: " name)
}
PROM_TYPE[name] = type
PROM_HELP[name] = help
# Whether we've output this metric yet (so we can determine whether to
# output the HELP and TYPE lines)
PROM_OUT[name] = 0
}
# Output a metric NAME with the numeric value VALUE and labels specified by
# the associative array LABELS.
#
# The metric must have previously been declared to ensure that its `HELP`
# and `TYPE` lines will be properly output the first time this function is
# invoked for that NAME.
#
# The keys of LABELS ought to be hard-coded to ensure that they are both
# valid and bounded.
function prom_metric(name, value, labels) {
if (PROM_OUT[name] != 1) {
printf "# HELP %s %s\n", name, PROM_HELP[name]
printf "# TYPE %s %s\n", name, PROM_TYPE[name]
PROM_OUT[name] = 1
}
printf "%s{%s} %d\n", name, _prom_labels(labels), value
}
# Serialize and escape associative array of labels LABELS.
#
# Prometheus label names must be of the form `[a-zA-Z_][a-zA-Z0-9_]*`, with
# a leading `__` reserved for internal use (though this does not bother
# checking for leading underscores). Labels not matching that pattern will
# be rejected in error rather than reformatting, since it surely represents
# a bug and I don't need my database polluted with garbage values.
function _prom_labels(labels, _delim, _result) {
_delim=""
for (name in labels) {
_result = _result sprintf("%s%s=\"%s\"",
_delim,
_prom_assert_valid_label(name),
_prom_label_escape(labels[name]))
_delim=", "
}
return _result
}
# Exit with non-zero status and error message if label name NAME is not
# valid (see `_prom_labels`).
function _prom_assert_valid_label(name) {
if (!(name ~ /^[a-zA-Z_][a-zA-Z0-9_]*/)) {
_prom_fatal("invalid label name: " name)
}
return name
}
# Escape double quotes in label value VALUE and return the result.
function _prom_label_escape(value) {
return gensub(/"/, "\\\\\"", "g", value)
}
# Display error message MSG and exit with non-zero status STATUS
# (default 1).
function _prom_fatal(msg, status) {
printf "error: prom: %s\n", msg > "/dev/stderr"
exit status ? status : 1
}