1
0
Fork 0
promscripts/prom.awk

122 lines
3.7 KiB
Awk
Raw Permalink Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

# 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
}