36 lines
2.0 KiB
Plaintext
36 lines
2.0 KiB
Plaintext
# Rate calculation happens BEFORE Kafka: replay cannot corrupt counter deltas.
|
|
# State is per measurement + complete tag set; counters never mix across devices.
|
|
state = {}
|
|
COUNTERS = {
|
|
"diskio": ["read_bytes", "write_bytes", "reads", "writes", "read_time", "write_time", "io_time"],
|
|
"net": ["bytes_recv", "bytes_sent", "packets_recv", "packets_sent", "err_in", "err_out", "drop_in", "drop_out"],
|
|
"kernel": ["context_switches", "interrupts", "processes_forked"],
|
|
"swap": ["in", "out"],
|
|
}
|
|
|
|
def apply(metric):
|
|
identity = metric.name + "|" + str(sorted(metric.tags.items()))
|
|
if metric.name in COUNTERS:
|
|
previous = state.get(identity)
|
|
current = {}
|
|
for field in COUNTERS[metric.name]:
|
|
if field in metric.fields:
|
|
current[field] = metric.fields[field]
|
|
if previous != None and metric.time > previous[0]:
|
|
elapsed = (metric.time - previous[0]) / 1000000000.0
|
|
# Suppress gaps and resets: never turn them into false rate spikes.
|
|
if elapsed <= 120.0:
|
|
for field in current:
|
|
if field in previous[1] and current[field] >= previous[1][field]:
|
|
metric.fields[field + "_per_sec"] = (current[field] - previous[1][field]) / elapsed
|
|
if metric.name == "diskio" and "io_time_per_sec" in metric.fields:
|
|
metric.fields["io_busy_percent"] = min(100.0, metric.fields["io_time_per_sec"] / 10.0)
|
|
if previous == None or metric.time > previous[0]:
|
|
state[identity] = (metric.time, current)
|
|
# Human-readable series distinguish same-named devices on different hosts.
|
|
device = metric.tags.get("path", metric.tags.get("interface", metric.tags.get("name", metric.tags.get("cpu", "host"))))
|
|
metric.tags["series"] = metric.tags.get("host", "unknown") + " / " + device
|
|
if metric.name == "system" and metric.fields.get("n_cpus", 0) > 0:
|
|
metric.fields["load1_per_cpu"] = metric.fields.get("load1", 0.0) / metric.fields["n_cpus"]
|
|
return metric
|