commit a79d253686b6aeac9d6dff4caac38e350ae5f01b Author: Justine Date: Sun Jul 3 16:18:15 2022 +0200 First commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..09ce044 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Description + +This is a prometheus exporter for knot dns (the authoritative server, not knot-resolver !). It gets all of its values from the mod-stats of knot, which can be set this way in knot's conf: + +```INI +#/etc/knot/knot.conf +template: + - id: default + storage: "/var/lib/knot" + file: "%s.zone" + global-module: mod-rrl/default + global-module: mod-stats/default +``` + +It gives knot's default stats, plus the rrl stats. For other modules, you'll have to add them yourself; have a look at the get_stats and gen_metrics functions. + +# Installation + +I don't know yet; might create a .deb + + diff --git a/knot-prom.py b/knot-prom.py new file mode 100644 index 0000000..559e96d --- /dev/null +++ b/knot-prom.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +#coding: utf-8 +import subprocess +from prometheus_client import start_http_server, Gauge +from time import sleep + + +def get_stats(): + ''' + Get the knot stats, return them in a dict + ''' + # Getting info + results = subprocess.run(["knotc", "stats"], capture_output=True).stdout + results = results.decode('utf-8') + results = results.split("\n") + results.remove("") + stats = {} + + for result in results: + result = result.split(" = ") + statname = result[0] + statname = statname.replace("-", "_") + statname = statname.replace(".", "_") + statname = statname.replace("[", "_") + statname = statname.replace("]", "") + stats[statname] = int(result[1]) + + return stats + +def gen_metrics(): + ''' + Generate all the prometheus metrics + Return them as a list + ''' + metrics = [ + Gauge('server_zone_count', 'Number of zones'), + Gauge('mod_rrl_slipped', 'Queries that were truncated because of response rate limiting'), + Gauge('mod_rrl_dropped', 'Queries that were dropped because of response rate limiting'), + Gauge('mod_stats_request_protocol_udp4', 'requests via udp in ipv4'), + Gauge('mod_stats_request_protocol_tcp4', 'requests via tcp in ipv4'), + Gauge('mod_stats_server_operation_query', 'Total number of incoming queries'), + Gauge('mod_stats_server_operation_axfr', 'Total number of incoming complete transfer requests'), + Gauge('mod_stats_server_operation_ixfr', 'Total number of incoming incremental transfer requests'), + Gauge('mod_stats_server_operation_invalid', 'Invalid requests received'), + Gauge('mod_stats_request_bytes_query', 'Bytes received responding to queries'), + Gauge('mod_stats_request_bytes_other', 'Bytes received responding to other things'), + Gauge('mod_stats_response_bytes_reply', 'Bytes sent responding to queries'), + Gauge('mod_stats_response_bytes_transfer', 'Bytes sent responding to transfers'), + Gauge('mod_stats_response_bytes_other', 'Bytes sent responding to other'), + Gauge('mod_stats_edns_presence_request', 'DNS Extension (EDNS) present in request'), + Gauge('mod_stats_edns_presence_response', 'DNS Extension (EDNS) present in response'), + Gauge('mod_stats_flag_presence_DO', 'Flag DNSSEC OK present in request'), + Gauge('mod_stats_flag_presence_TC', 'Truncated Answer in response'), + Gauge('mod_stats_response_code_NOERROR', 'outgoing response code NOERROR'), + Gauge('mod_stats_response_code_FORMERR', 'outgoing response code FORMERR'), + Gauge('mod_stats_response_code_NXDOMAIN', 'outgoing response code NXDOMAIN'), + Gauge('mod_stats_response_code_NOTIMPL', 'outgoing response code NOTIMPL'), + Gauge('mod_stats_response_code_REFUSED', 'outgoing response code REFUSED'), + Gauge('mod_stats_response_code_NOTAUTH', 'outgoing response code NOTAUTH'), + Gauge('mod_stats_request_edns_option_NSID', 'Extended DNS (EDNS) option NSID in request'), + Gauge('mod_stats_request_edns_option_EDNS_CLIENT_SUBNET', 'Extended DNS (EDNS) option CLIENT_SUBNET in request'), + Gauge('mod_stats_request_edns_option_COOKIE', 'Extended DNS (EDNS) option COOKIE in request'), + Gauge('mod_stats_response_edns_option_NSID', 'Extended DNS (EDNS) option NSID in response'), + Gauge('mod_stats_reply_nodata_A', 'RFC 2308 Nodata A in reply'), + Gauge('mod_stats_reply_nodata_AAAA', 'RFC 2308 Nodata AAAA in reply'), + Gauge('mod_stats_reply_nodata_other', 'RFC 2308 Nodata other in reply'), + Gauge('mod_stats_query_type_A', 'Number of A queries'), + Gauge('mod_stats_query_type_NS', 'Number of A queries'), + Gauge('mod_stats_query_type_CNAME', 'Number of A queries'), + Gauge('mod_stats_query_type_SOA', 'Number of A queries'), + Gauge('mod_stats_query_type_MX', 'Number of A queries'), + Gauge('mod_stats_query_type_TXT', 'Number of A queries'), + Gauge('mod_stats_query_type_AAAA', 'Number of A queries'), + Gauge('mod_stats_query_type_SRV', 'Number of A queries'), + Gauge('mod_stats_query_type_DNAME', 'Number of A queries'), + Gauge('mod_stats_query_type_DS', 'Number of A queries'), + Gauge('mod_stats_query_type_RRSIG', 'Number of A queries'), + Gauge('mod_stats_query_type_DNSKEY', 'Number of A queries'), + Gauge('mod_stats_query_type_TLSA', 'Number of A queries'), + Gauge('mod_stats_query_type_HTTPS', 'Number of A queries'), + Gauge('mod_stats_query_type_ANY', 'Number of A queries'), + Gauge('mod_stats_query_type_CAA', 'Number of A queries') + ] + return metrics + +def populate_metrics(stats, metrics): + ''' + Take dict of stats and list of metrics (all summaries) + Populate the metrics with the stats + Return the metrics + ''' + for statname in stats: + for metric in metrics: + if statname == metric._name: + metric.set(stats[statname]) + + return metrics + + +def main(): + metrics = gen_metrics() + start_http_server(8001) + while True: + stats = get_stats() + metrics = populate_metrics(stats, metrics) + sleep(5) + +if __name__ == '__main__': + main() + diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a0753df --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +prometheus_client