add option for metric prefix

This commit is contained in:
illustris 2023-10-02 14:20:36 +05:30
parent ce4c98cbcb
commit 23e6a59758
Signed by: illustris
GPG Key ID: 56C8FC0B899FEFA3

View File

@ -10,54 +10,48 @@ import pexpect
DEFAULT_PORT = 9116 DEFAULT_PORT = 9116
DEFAULT_INTERVAL = 10 DEFAULT_INTERVAL = 10
DEFAULT_PREFIX = "pve"
gauge_settings = [ gauge_settings = [
('pve_kvm_cpu', 'CPU time for VM', ['id', 'mode']), ('kvm_cpu', 'CPU time for VM', ['id', 'mode']),
('pve_kvm_vcores', 'vCores allocated to the VM', ['id']), ('kvm_vcores', 'vCores allocated to the VM', ['id']),
('pve_kvm_maxmem', 'Maximum memory (bytes) allocated to the VM', ['id']), ('kvm_maxmem', 'Maximum memory (bytes) allocated to the VM', ['id']),
('pve_kvm_memory_percent', 'Percentage of host memory used by VM', ['id']), ('kvm_memory_percent', 'Percentage of host memory used by VM', ['id']),
('pve_kvm_memory_extended', 'Detailed memory metrics for VM', ['id', 'type']), ('kvm_memory_extended', 'Detailed memory metrics for VM', ['id', 'type']),
('pve_kvm_threads', 'Threads used by the KVM process', ['id']), ('kvm_threads', 'Threads used by the KVM process', ['id']),
('pve_kvm_io_read_count', 'Number of read system calls made by the KVM process', ['id']), ('kvm_io_read_count', 'Number of read system calls made by the KVM process', ['id']),
('pve_kvm_io_read_bytes', 'Number of bytes read from disk', ['id']), ('kvm_io_read_bytes', 'Number of bytes read from disk', ['id']),
('pve_kvm_io_read_chars', 'Number of bytes read including buffers', ['id']), ('kvm_io_read_chars', 'Number of bytes read including buffers', ['id']),
('pve_kvm_ctx_switches', 'Context switches', ['id', 'type']), ('kvm_ctx_switches', 'Context switches', ['id', 'type']),
('pve_kvm_io_write_count', 'Number of write system calls made by the KVM process', ['id']), ('kvm_io_write_count', 'Number of write system calls made by the KVM process', ['id']),
('pve_kvm_io_write_bytes', 'Number of bytes written to disk', ['id']), ('kvm_io_write_bytes', 'Number of bytes written to disk', ['id']),
('pve_kvm_io_write_chars', 'Number of bytes written including buffers', ['id']), ('kvm_io_write_chars', 'Number of bytes written including buffers', ['id']),
('pve_kvm_nic_queues', 'Number of queues in multiqueue config', ['id', 'ifname']), ('kvm_nic_queues', 'Number of queues in multiqueue config', ['id', 'ifname']),
] ]
gauge_dict = {} gauge_dict = {}
info_dict = {}
for name, description, labels in gauge_settings:
gauge_dict[name] = Gauge(name, description, labels)
label_flags = [ "-id", "-name", "-cpu" ] label_flags = [ "-id", "-name", "-cpu" ]
get_label_name = lambda flag: flag[1:] get_label_name = lambda flag: flag[1:]
info_settings = [ info_settings = [
('pve_kvm', 'information for each KVM process'), ('kvm', 'information for each KVM process'),
] ]
info_dict = {}
for name, description in info_settings:
info_dict[name] = Info(name, description)
flag_to_label_value = lambda args, match: next((args[i+1] for i, x in enumerate(args[:-1]) if x == match), "unknown").split(",")[0] flag_to_label_value = lambda args, match: next((args[i+1] for i, x in enumerate(args[:-1]) if x == match), "unknown").split(",")[0]
dynamic_gauges = {} dynamic_gauges = {}
def create_or_get_gauge(metric_name, labels): def create_or_get_gauge(metric_name, labels):
if metric_name not in dynamic_gauges: if metric_name not in dynamic_gauges:
dynamic_gauges[metric_name] = Gauge(metric_name, f'{metric_name} for KVM process', labels) dynamic_gauges[metric_name] = Gauge(f"{prefix}_{metric_name}", f'{metric_name} for KVM process', labels)
return dynamic_gauges[metric_name] return dynamic_gauges[metric_name]
dynamic_infos = {} dynamic_infos = {}
def create_or_get_info(info_name, labels): def create_or_get_info(info_name, labels):
if (info_name,str(labels)) not in dynamic_infos: if (info_name,str(labels)) not in dynamic_infos:
dynamic_infos[(info_name,str(labels))] = Info(info_name, f'{info_name} for {str(labels)}', labels) dynamic_infos[(info_name,str(labels))] = Info(f"{prefix}_{info_name}", f'{info_name} for {str(labels)}', labels)
return dynamic_infos[(info_name,str(labels))] return dynamic_infos[(info_name,str(labels))]
def extract_nic_info_from_monitor(vm_id): def extract_nic_info_from_monitor(vm_id):
@ -121,13 +115,13 @@ def collect_kvm_metrics():
# Extract vm labels from cmdline # Extract vm labels from cmdline
info_label_dict = {get_label_name(l): flag_to_label_value(cmdline,l) for l in label_flags} info_label_dict = {get_label_name(l): flag_to_label_value(cmdline,l) for l in label_flags}
info_label_dict['pid']=str(proc.pid) info_label_dict['pid']=str(proc.pid)
info_dict["pve_kvm"].info(info_label_dict) info_dict["kvm"].info(info_label_dict)
d = { d = {
"pve_kvm_vcores": flag_to_label_value(cmdline,"-smp"), "kvm_vcores": flag_to_label_value(cmdline,"-smp"),
"pve_kvm_maxmem": int(flag_to_label_value(cmdline,"-m"))*1024, "kvm_maxmem": int(flag_to_label_value(cmdline,"-m"))*1024,
"pve_kvm_memory_percent": proc.info['memory_percent'], "kvm_memory_percent": proc.info['memory_percent'],
"pve_kvm_threads": proc.info['num_threads'], "kvm_threads": proc.info['num_threads'],
} }
for k, v in d.items(): for k, v in d.items():
@ -135,34 +129,34 @@ def collect_kvm_metrics():
cpu_times = proc.cpu_times() cpu_times = proc.cpu_times()
for mode in ['user', 'system', 'iowait']: for mode in ['user', 'system', 'iowait']:
gauge_dict["pve_kvm_cpu"].labels(id=id, mode=mode).set(getattr(cpu_times, mode)) gauge_dict["kvm_cpu"].labels(id=id, mode=mode).set(getattr(cpu_times, mode))
io = proc.io_counters() io = proc.io_counters()
for io_type, attr in itertools.product(['read', 'write'], ['count', 'bytes', 'chars']): for io_type, attr in itertools.product(['read', 'write'], ['count', 'bytes', 'chars']):
gauge = globals()["gauge_dict"][f'pve_kvm_io_{io_type}_{attr}'] gauge = globals()["gauge_dict"][f'kvm_io_{io_type}_{attr}']
gauge.labels(id=id).set(getattr(io, f"{io_type}_{attr}")) gauge.labels(id=id).set(getattr(io, f"{io_type}_{attr}"))
for type in [ "voluntary", "involuntary" ]: for type in [ "voluntary", "involuntary" ]:
gauge_dict["pve_kvm_ctx_switches"].labels(id=id, type=type).set(getattr(proc.num_ctx_switches(),type)) gauge_dict["kvm_ctx_switches"].labels(id=id, type=type).set(getattr(proc.num_ctx_switches(),type))
for attr in dir(proc.memory_full_info()): for attr in dir(proc.memory_full_info()):
if not attr.startswith('_'): if not attr.startswith('_'):
value = getattr(proc.memory_full_info(), attr) value = getattr(proc.memory_full_info(), attr)
if not callable(value): if not callable(value):
gauge_dict["pve_kvm_memory_extended"].labels(id=id, type=attr).set(value) gauge_dict["kvm_memory_extended"].labels(id=id, type=attr).set(value)
for nic_info in extract_nic_info_from_monitor(id): for nic_info in extract_nic_info_from_monitor(id):
queues = nic_info["queues"] queues = nic_info["queues"]
del nic_info["queues"] del nic_info["queues"]
nic_labels = {"id": id, "ifname": nic_info["ifname"]} nic_labels = {"id": id, "ifname": nic_info["ifname"]}
prom_nic_info = create_or_get_info("pve_kvm_nic", nic_labels.keys()) prom_nic_info = create_or_get_info("kvm_nic", nic_labels.keys())
prom_nic_info.labels(**nic_labels).info({k: v for k, v in nic_info.items() if k not in nic_labels.keys()}) prom_nic_info.labels(**nic_labels).info({k: v for k, v in nic_info.items() if k not in nic_labels.keys()})
gauge_dict["pve_kvm_nic_queues"].labels(**nic_labels).set(queues) gauge_dict["kvm_nic_queues"].labels(**nic_labels).set(queues)
interface_stats = read_interface_stats(nic_info["ifname"]) interface_stats = read_interface_stats(nic_info["ifname"])
for filename, value in interface_stats.items(): for filename, value in interface_stats.items():
metric_name = f"pve_kvm_nic_{filename}" metric_name = f"kvm_nic_{filename}"
gauge = create_or_get_gauge(metric_name, nic_labels.keys()) gauge = create_or_get_gauge(metric_name, nic_labels.keys())
gauge.labels(**nic_labels).set(value) gauge.labels(**nic_labels).set(value)
@ -173,9 +167,19 @@ def main():
parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Port for the exporter to listen on') parser.add_argument('--port', type=int, default=DEFAULT_PORT, help='Port for the exporter to listen on')
parser.add_argument('--interval', type=int, default=DEFAULT_INTERVAL, help='Interval between metric collections in seconds') parser.add_argument('--interval', type=int, default=DEFAULT_INTERVAL, help='Interval between metric collections in seconds')
parser.add_argument('--collect-running-vms', type=str, default='true', help='Enable or disable collecting running VMs metric (true/false)') parser.add_argument('--collect-running-vms', type=str, default='true', help='Enable or disable collecting running VMs metric (true/false)')
parser.add_argument('--metrics-prefix', type=str, default=DEFAULT_PREFIX, help='<prefix>_ will be prepended to each metric name')
args = parser.parse_args() args = parser.parse_args()
global prefix
prefix = args.metrics_prefix
for name, description, labels in gauge_settings:
gauge_dict[name] = Gauge(f"{prefix}_{name}", description, labels)
for name, description in info_settings:
info_dict[name] = Info(f"{prefix}_{name}", description)
start_http_server(args.port) start_http_server(args.port)
while True: while True: