feat(metrics): add timeframe/bucket math and series aggregation

This commit is contained in:
2026-06-21 20:59:23 +05:00
parent 3a2c87bd0a
commit 3d55b1ab8d
2 changed files with 77 additions and 0 deletions

View File

@@ -45,3 +45,49 @@ def aggregate_fsinfo(disks):
used = sum(int(d.get("used", 0) or 0) for d in disks or [])
total = sum(int(d.get("total", 0) or 0) for d in disks or [])
return used, total
_TIMEFRAME_SECONDS = {
"hour": 3600,
"day": 86400,
"week": 7 * 86400,
"month": 30 * 86400,
}
def timeframe_to_range(timeframe, now_ts):
"""Convert timeframe string to (from_ts, to_ts) tuple."""
span = _TIMEFRAME_SECONDS.get(timeframe, 3600)
return now_ts - span, now_ts
def pick_bucket_seconds(from_ts, to_ts, target_points=150, floor=15):
"""Calculate bucket size in seconds for time-series aggregation."""
span = max(1, to_ts - from_ts)
ideal = span // max(1, target_points)
return max(floor, int(ideal))
def aggregate_series(rows, from_ts, bucket, fields):
"""Aggregate time-series data into buckets, averaging numeric fields."""
if not rows:
return []
buckets: dict[int, dict] = {}
order: list[int] = []
for r in rows:
b = from_ts + ((int(r["time"]) - from_ts) // bucket) * bucket
if b not in buckets:
buckets[b] = {f: [] for f in fields}
order.append(b)
for f in fields:
v = r.get(f)
if v is not None:
buckets[b][f].append(float(v))
out = []
for b in order:
point = {"time": b}
for f in fields:
vals = buckets[b][f]
point[f] = (sum(vals) / len(vals)) if vals else None
out.append(point)
return out