mirror of
https://github.com/openwrt/packages.git
synced 2026-07-12 22:44:28 +04:00
prometheus-node-exporter-ucode: add nat_traffic collector
Add a nat_traffic collector for prometheus-node-exporter-ucode, ported from the equivalent Lua collector in prometheus-node-exporter-lua. Reads /proc/net/nf_conntrack and exports per-(src, dst) pair byte totals (both directions summed) as node_nat_traffic gauge metrics. Also includes a ucode-based unit test with a fixture file that can be run locally with: ucode test/nat_traffic.uc Signed-off-by: Ricard Nacher <ricard.nacher@midokura.com>
This commit is contained in:
committed by
Etienne Champetier
parent
45c9d0b9c8
commit
ab26c76ed6
@@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=prometheus-node-exporter-ucode
|
||||
PKG_VERSION:=2024.02.07
|
||||
PKG_RELEASE:=2
|
||||
PKG_RELEASE:=3
|
||||
|
||||
PKG_MAINTAINER:=Andre Heider <a.heider@gmail.com>
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
@@ -65,6 +65,7 @@ define Collector
|
||||
endef
|
||||
|
||||
$(eval $(call Collector,dnsmasq,Dnsmasq collector,@dnsmasq))
|
||||
$(eval $(call Collector,nat_traffic,NAT traffic collector,))
|
||||
$(eval $(call Collector,ltq-dsl,Lantiq/Intel/MaxLinear DSL collector,@ltq-dsl-app))
|
||||
$(eval $(call Collector,netstat,netstat collector,))
|
||||
$(eval $(call Collector,openwrt,OpenWrt collector,))
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
let f = fs.open("/proc/net/nf_conntrack");
|
||||
if (!f)
|
||||
return false;
|
||||
|
||||
let nat = {};
|
||||
let nat_metric = gauge("node_nat_traffic");
|
||||
|
||||
let line;
|
||||
while ((line = nextline(f)) != null) {
|
||||
const fields = wsplit(line);
|
||||
let src, dst;
|
||||
let bytes = 0;
|
||||
|
||||
for (let field in fields) {
|
||||
if (src == null && substr(field, 0, 4) == "src=")
|
||||
src = substr(field, 4);
|
||||
else if (dst == null && substr(field, 0, 4) == "dst=")
|
||||
dst = substr(field, 4);
|
||||
else if (substr(field, 0, 6) == "bytes=")
|
||||
bytes += +substr(field, 6);
|
||||
}
|
||||
|
||||
if (src == null || dst == null)
|
||||
continue;
|
||||
|
||||
if (nat[src] == null)
|
||||
nat[src] = {};
|
||||
|
||||
nat[src][dst] = (nat[src][dst] || 0) + bytes;
|
||||
}
|
||||
|
||||
f.close();
|
||||
|
||||
for (let src in nat)
|
||||
for (let dst in nat[src])
|
||||
nat_metric({ src, dst }, nat[src][dst]);
|
||||
@@ -1,3 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
prometheus-node-exporter-ucode time
|
||||
case "$1" in
|
||||
prometheus-node-exporter-ucode-nat_traffic)
|
||||
[ -f /proc/net/nf_conntrack ] && prometheus-node-exporter-ucode nat_traffic
|
||||
;;
|
||||
*)
|
||||
prometheus-node-exporter-ucode time
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
ipv4 2 tcp 6 431999 ESTABLISHED src=192.168.1.2 dst=1.2.3.4 sport=49152 dport=443 packets=10 bytes=1234 src=1.2.3.4 dst=192.168.1.2 sport=443 dport=49152 packets=8 bytes=5678 [ASSURED] mark=0 use=2
|
||||
ipv4 2 tcp 6 120 TIME_WAIT src=192.168.1.2 dst=1.2.3.4 sport=49153 dport=80 packets=5 bytes=100 src=1.2.3.4 dst=192.168.1.2 sport=80 dport=49153 packets=3 bytes=200 mark=0 use=2
|
||||
ipv4 2 tcp 6 431999 ESTABLISHED src=192.168.1.3 dst=1.2.3.4 sport=49154 dport=443 packets=2 bytes=300 src=1.2.3.4 dst=192.168.1.3 sport=443 dport=49154 packets=1 bytes=400 [ASSURED] mark=0 use=2
|
||||
ipv4 2 udp 17 30 src=192.168.1.2 dst=8.8.8.8 sport=12345 dport=53 packets=1 bytes=60 src=8.8.8.8 dst=192.168.1.2 sport=53 dport=12345 packets=1 bytes=120 mark=0 use=2
|
||||
@@ -0,0 +1,77 @@
|
||||
'use strict';
|
||||
|
||||
import * as real_fs from "fs";
|
||||
|
||||
const fixture = "./test/fixtures/nf_conntrack";
|
||||
const collector_path = "./files/extra/nat_traffic.uc";
|
||||
|
||||
// Capture metric emissions
|
||||
let metrics = {};
|
||||
|
||||
function gauge(name) {
|
||||
let func;
|
||||
func = function(labels, value) {
|
||||
let key = name;
|
||||
if (labels && length(labels)) {
|
||||
let parts = [];
|
||||
for (let k in labels)
|
||||
push(parts, k + '="' + labels[k] + '"');
|
||||
key += "{" + join(",", parts) + "}";
|
||||
}
|
||||
metrics[key] = value;
|
||||
return func;
|
||||
};
|
||||
return func;
|
||||
}
|
||||
|
||||
// Redirect /proc/net/nf_conntrack to fixture file
|
||||
const fs = {
|
||||
open: function(path) {
|
||||
if (path == "/proc/net/nf_conntrack")
|
||||
return real_fs.open(fixture);
|
||||
return real_fs.open(path);
|
||||
}
|
||||
};
|
||||
|
||||
function wsplit(line) {
|
||||
return split(line, /\s+/);
|
||||
}
|
||||
|
||||
function nextline(f) {
|
||||
return rtrim(f.read("line"), "\n");
|
||||
}
|
||||
|
||||
let func;
|
||||
try {
|
||||
func = loadfile(collector_path, { strict_declarations: true, raw_mode: true });
|
||||
} catch(e) {
|
||||
die("Failed to load collector: " + e.message + "\n");
|
||||
}
|
||||
|
||||
if (call(func, null, { fs, gauge, wsplit, nextline, config: {} }) == false)
|
||||
die("Collector returned false — is the fixture file missing?\n");
|
||||
|
||||
// Assertions
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
function assert_eq(key, expected) {
|
||||
const actual = metrics[key];
|
||||
if (actual == expected) {
|
||||
print("PASS: " + key + " == " + expected + "\n");
|
||||
passed++;
|
||||
} else {
|
||||
print("FAIL: " + key + ": expected " + expected + ", got " + actual + "\n");
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
// line1 (1234+5678=6912) + line2 (100+200=300) share same src/dst => aggregated to 7212
|
||||
assert_eq('node_nat_traffic{src="192.168.1.2",dst="1.2.3.4"}', 7212);
|
||||
// line3 (300+400=700)
|
||||
assert_eq('node_nat_traffic{src="192.168.1.3",dst="1.2.3.4"}', 700);
|
||||
// line4 (60+120=180)
|
||||
assert_eq('node_nat_traffic{src="192.168.1.2",dst="8.8.8.8"}', 180);
|
||||
|
||||
print("\n" + passed + " passed, " + failed + " failed\n");
|
||||
exit(failed > 0 ? 1 : 0);
|
||||
Reference in New Issue
Block a user