fix(unifi): the Overview's history buckets on Postgres; devices name their state (#5207)
#5207 "UniFi Overview tab: func.strftime is SQLite-only": the WAN and client sparklines bucketed with strftime('%s'), which Postgres lacks, so /plugins/unifi/rows failed. Traefik's date_bin bucket moves to core/time_range.time_bucket and both plugins use it. Devices list offline and failing first, and a state other than online is named (Upgrading, Adopting, Heartbeat missed...) instead of drawn as Down. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import time
|
||||
|
||||
from steward.auth.middleware import require_role
|
||||
from steward.models.users import UserRole
|
||||
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
||||
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample, time_bucket
|
||||
from steward.core.formatting import cert_left, status_class
|
||||
from steward.models.metrics import PluginMetricLatest
|
||||
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
|
||||
@@ -430,15 +430,6 @@ async def widget_access_log():
|
||||
summary=summary, widget_id=widget_id)
|
||||
|
||||
|
||||
def _time_bucket(column, seconds: int):
|
||||
"""The start of the `seconds`-wide window a timestamp falls in, as
|
||||
host_agent/metrics_query.py buckets. Integer epoch / int rendered as
|
||||
numeric division (no two scrapes shared a bucket) and overflowed int4
|
||||
after 2038 (#5256)."""
|
||||
return func.date_bin(func.make_interval(0, 0, 0, 0, 0, 0, int(seconds)), column,
|
||||
func.to_timestamp(0)).label("bucket")
|
||||
|
||||
|
||||
# A rows or widget request past this logs where its time went, phase by
|
||||
# phase, so a slow query names itself (#5355: 8 s on every poll, warm).
|
||||
SLOW_PAGE_SECONDS = 1.0
|
||||
@@ -473,7 +464,7 @@ async def router_history(db, names: list[str], since, bucket_secs: int) -> dict[
|
||||
history: dict[str, list] = {n: [] for n in names}
|
||||
if not history:
|
||||
return history
|
||||
bucket_col = _time_bucket(TraefikMetric.scraped_at, bucket_secs)
|
||||
bucket_col = time_bucket(TraefikMetric.scraped_at, bucket_secs)
|
||||
result = await db.execute(
|
||||
select(
|
||||
TraefikMetric.router_name,
|
||||
@@ -509,7 +500,7 @@ async def request_history(db, since, bucket_seconds: int) -> list[dict]:
|
||||
.group_by(TraefikMetric.scraped_at)
|
||||
.subquery()
|
||||
)
|
||||
bucket_col = _time_bucket(per_scrape.c.at, bucket_seconds)
|
||||
bucket_col = time_bucket(per_scrape.c.at, bucket_seconds)
|
||||
rows = (await db.execute(
|
||||
select(
|
||||
func.avg(per_scrape.c.req).label("req_rate"),
|
||||
|
||||
Reference in New Issue
Block a user