add labels and conntrack stats to prometheus output
This commit is contained in:
parent
5c5a309934
commit
dede33a5d0
@ -1,7 +1,9 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import dataclasses
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import sys
|
import typing
|
||||||
|
|
||||||
import trio
|
import trio
|
||||||
|
|
||||||
@ -11,18 +13,39 @@ import capport.utils.nft_set
|
|||||||
from . import cptypes
|
from . import cptypes
|
||||||
|
|
||||||
|
|
||||||
def print_metric(name: str, mtype: str, value, *, now: int | None = None, help: str | None = None):
|
@dataclasses.dataclass(kw_only=True, slots=True)
|
||||||
# no labels in our names for now, always print help and type
|
class MetricPrinter:
|
||||||
|
args: CliArguments
|
||||||
|
now: int | None = None
|
||||||
|
_known_names: set[str] = dataclasses.field(default_factory=set, init=None)
|
||||||
|
_now_str: str = dataclasses.field(init=False)
|
||||||
|
_label_str: str = dataclasses.field(init=False)
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
if not self.now is None:
|
||||||
|
self._now_str = f" {self.now}"
|
||||||
|
else:
|
||||||
|
self._now_str = ""
|
||||||
|
labels = []
|
||||||
|
if self.args.instance:
|
||||||
|
labels.append(f"instance=\"{self.args.instance}\"")
|
||||||
|
labels.append(f"interface=\"{self.args.interface}\"")
|
||||||
|
self._label_str = "{" + ",".join(labels) + "}"
|
||||||
|
|
||||||
|
def print_metric(self, *, name: str, mtype: str, value: typing.Any, help: str | None = None):
|
||||||
|
if not name in self._known_names:
|
||||||
|
self._known_names.add(name)
|
||||||
if help:
|
if help:
|
||||||
print(f"# HELP {name} {help}")
|
print(f"# HELP {name} {help}")
|
||||||
print(f"# TYPE {name} {mtype}")
|
print(f"# TYPE {name} {mtype}")
|
||||||
if now:
|
print(f"{name}{self._label_str} {value}{self._now_str}")
|
||||||
print(f"{name} {value} {now}")
|
|
||||||
else:
|
def print_gauge(self, name: str, value: int | float, help: str | None = None):
|
||||||
print(f"{name} {value}")
|
self.print_metric(name=name, mtype="gauge", value=value, help=help)
|
||||||
|
|
||||||
|
|
||||||
async def amain(client_ifname: str):
|
async def amain(args: CliArguments):
|
||||||
|
printer = MetricPrinter(args=args)
|
||||||
ns = capport.utils.nft_set.NftSet()
|
ns = capport.utils.nft_set.NftSet()
|
||||||
captive_allowed_entries: set[cptypes.MacAddress] = {entry["mac"] for entry in ns.list()}
|
captive_allowed_entries: set[cptypes.MacAddress] = {entry["mac"] for entry in ns.list()}
|
||||||
seen_allowed_entries: set[cptypes.MacAddress] = set()
|
seen_allowed_entries: set[cptypes.MacAddress] = set()
|
||||||
@ -33,7 +56,7 @@ async def amain(client_ifname: str):
|
|||||||
unique_ipv6 = set()
|
unique_ipv6 = set()
|
||||||
async with capport.utils.ipneigh.connect() as ipn:
|
async with capport.utils.ipneigh.connect() as ipn:
|
||||||
ipn.ip.strict_check = True
|
ipn.ip.strict_check = True
|
||||||
async for (mac, addr) in ipn.dump_neighbors(client_ifname):
|
async for (mac, addr) in ipn.dump_neighbors(args.interface):
|
||||||
if mac in captive_allowed_entries:
|
if mac in captive_allowed_entries:
|
||||||
seen_allowed_entries.add(mac)
|
seen_allowed_entries.add(mac)
|
||||||
unique_clients.add(mac)
|
unique_clients.add(mac)
|
||||||
@ -43,50 +66,74 @@ async def amain(client_ifname: str):
|
|||||||
else:
|
else:
|
||||||
total_ipv6 += 1
|
total_ipv6 += 1
|
||||||
unique_ipv6.add(mac)
|
unique_ipv6.add(mac)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_allowed_macs",
|
"capport_allowed_macs",
|
||||||
"gauge",
|
|
||||||
len(captive_allowed_entries),
|
len(captive_allowed_entries),
|
||||||
help="Number of allowed client mac addresses",
|
help="Number of allowed client mac addresses",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_allowed_neigh_macs",
|
"capport_allowed_neigh_macs",
|
||||||
"gauge",
|
|
||||||
len(seen_allowed_entries),
|
len(seen_allowed_entries),
|
||||||
help="Number of allowed client mac addresses seen in neighbor cache",
|
help="Number of allowed client mac addresses seen in neighbor cache",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_unique",
|
"capport_unique",
|
||||||
"gauge",
|
|
||||||
len(unique_clients),
|
len(unique_clients),
|
||||||
help="Number of clients (mac addresses) in client network seen in neighbor cache",
|
help="Number of clients (mac addresses) in client network seen in neighbor cache",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_unique_ipv4",
|
"capport_unique_ipv4",
|
||||||
"gauge",
|
|
||||||
len(unique_ipv4),
|
len(unique_ipv4),
|
||||||
help="Number of IPv4 clients (unique per mac) in client network seen in neighbor cache",
|
help="Number of IPv4 clients (unique per mac) in client network seen in neighbor cache",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_unique_ipv6",
|
"capport_unique_ipv6",
|
||||||
"gauge",
|
|
||||||
len(unique_ipv6),
|
len(unique_ipv6),
|
||||||
help="Number of IPv6 clients (unique per mac) in client network seen in neighbor cache",
|
help="Number of IPv6 clients (unique per mac) in client network seen in neighbor cache",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_total_ipv4",
|
"capport_total_ipv4",
|
||||||
"gauge",
|
|
||||||
total_ipv4,
|
total_ipv4,
|
||||||
help="Number of IPv4 addresses seen in neighbor cache",
|
help="Number of IPv4 addresses seen in neighbor cache",
|
||||||
)
|
)
|
||||||
print_metric(
|
printer.print_gauge(
|
||||||
"capport_total_ipv6",
|
"capport_total_ipv6",
|
||||||
"gauge",
|
|
||||||
total_ipv6,
|
total_ipv6,
|
||||||
help="Number of IPv6 addresses seen in neighbor cache",
|
help="Number of IPv6 addresses seen in neighbor cache",
|
||||||
)
|
)
|
||||||
|
with open('/proc/sys/net/netfilter/nf_conntrack_count') as f:
|
||||||
|
printer.print_gauge(
|
||||||
|
"nf_conntrack_count",
|
||||||
|
int(f.readline()),
|
||||||
|
help="Conntrack count",
|
||||||
|
)
|
||||||
|
with open('/proc/sys/net/netfilter/nf_conntrack_max') as f:
|
||||||
|
printer.print_gauge(
|
||||||
|
"nf_conntrack_max",
|
||||||
|
int(f.readline()),
|
||||||
|
help="Conntrack max",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclasses.dataclass
|
||||||
|
class CliArguments:
|
||||||
|
interface: str
|
||||||
|
instance: str | None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--interface",
|
||||||
|
required=True,
|
||||||
|
help="Name of network interface clients are connected to (to look for IP neighbors)",
|
||||||
|
)
|
||||||
|
parser.add_argument("--instance", help="Name of instance (to tag metrics with)")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
self.interface = args.interface
|
||||||
|
self.instance = args.instance
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
assert len(sys.argv) == 2, "Need name of client interface as argument"
|
args = CliArguments()
|
||||||
trio.run(amain, sys.argv[1])
|
trio.run(amain, args)
|
||||||
|
@ -16,7 +16,7 @@ fi
|
|||||||
targetname="/var/lib/prometheus/node-exporter/capport-${instance}.prom"
|
targetname="/var/lib/prometheus/node-exporter/capport-${instance}.prom"
|
||||||
tmpname="${targetname}.$$"
|
tmpname="${targetname}.$$"
|
||||||
|
|
||||||
if ./stats.sh "${ifname}" > "${tmpname}"; then
|
if ./stats.sh --instance "${instance}" --interface "${ifname}" > "${tmpname}"; then
|
||||||
mv "${tmpname}" "${targetname}"
|
mv "${tmpname}" "${targetname}"
|
||||||
else
|
else
|
||||||
rm "${tmpname}"
|
rm "${tmpname}"
|
||||||
|
Loading…
Reference in New Issue
Block a user