feat: better cache stats
This commit is contained in:
@@ -441,10 +441,53 @@ class CacheEngine:
|
||||
"SELECT source, COUNT(*) FROM cache GROUP BY source"
|
||||
).fetchall()
|
||||
)
|
||||
# Source × Status cross-tabulation
|
||||
source_status = conn.execute(
|
||||
"SELECT source, status, COUNT(*) FROM cache GROUP BY source, status"
|
||||
).fetchall()
|
||||
# Confidence buckets (only for positive statuses)
|
||||
confidence_rows = conn.execute(
|
||||
"SELECT confidence FROM cache WHERE status IN (?, ?)",
|
||||
(
|
||||
CacheStatus.SUCCESS_SYNCED.value,
|
||||
CacheStatus.SUCCESS_UNSYNCED.value,
|
||||
),
|
||||
).fetchall()
|
||||
|
||||
# Build source×status table: {source: {status: count}}
|
||||
source_status_table: dict[str, dict[str, int]] = {}
|
||||
for src, status, count in source_status:
|
||||
source_status_table.setdefault(src, {})[status] = count
|
||||
|
||||
# Build confidence buckets
|
||||
buckets = {
|
||||
"legacy (NULL)": 0,
|
||||
"0-24": 0,
|
||||
"25-49": 0,
|
||||
"50-79": 0,
|
||||
"80-99": 0,
|
||||
"100": 0,
|
||||
}
|
||||
for (conf,) in confidence_rows:
|
||||
if conf is None:
|
||||
buckets["legacy (NULL)"] += 1
|
||||
elif conf >= 100:
|
||||
buckets["100"] += 1
|
||||
elif conf >= 80:
|
||||
buckets["80-99"] += 1
|
||||
elif conf >= 50:
|
||||
buckets["50-79"] += 1
|
||||
elif conf >= 25:
|
||||
buckets["25-49"] += 1
|
||||
else:
|
||||
buckets["0-24"] += 1
|
||||
|
||||
return {
|
||||
"total": total,
|
||||
"expired": expired,
|
||||
"active": total - expired,
|
||||
"by_status": by_status,
|
||||
"by_source": by_source,
|
||||
"source_status": source_status_table,
|
||||
"confidence_buckets": buckets,
|
||||
}
|
||||
|
||||
+40
-8
@@ -354,14 +354,46 @@ def stats():
|
||||
print(f"Total entries : {s['total']}")
|
||||
print(f"Active : {s['active']}")
|
||||
print(f"Expired : {s['expired']}")
|
||||
if s["by_status"]:
|
||||
print("\nBy status:")
|
||||
for status, count in s["by_status"].items():
|
||||
print(f" {status}: {count}")
|
||||
if s["by_source"]:
|
||||
print("\nBy source:")
|
||||
for source, count in s["by_source"].items():
|
||||
print(f" {source}: {count}")
|
||||
|
||||
# Source × Status table
|
||||
table = s.get("source_status", {})
|
||||
if table:
|
||||
all_statuses = sorted({st for row in table.values() for st in row})
|
||||
# Short labels for column headers
|
||||
short = {
|
||||
"SUCCESS_SYNCED": "synced",
|
||||
"SUCCESS_UNSYNCED": "unsynced",
|
||||
"NOT_FOUND": "not_found",
|
||||
"NETWORK_ERROR": "net_err",
|
||||
}
|
||||
headers = [short.get(st, st) for st in all_statuses]
|
||||
sources = sorted(table.keys())
|
||||
# Column widths
|
||||
src_w = max(len(src) for src in sources)
|
||||
src_w = max(src_w, 6) # min width for "source" header
|
||||
col_w = [max(len(h) if h else 0, 4) for h in headers]
|
||||
|
||||
print(
|
||||
f"\n{'source':<{src_w}} "
|
||||
+ " ".join(f"{h:>{w}}" for h, w in zip(headers, col_w))
|
||||
)
|
||||
print("-" * src_w + " " + " ".join("-" * w for w in col_w))
|
||||
for src in sources:
|
||||
counts = [str(table[src].get(st, 0)) for st in all_statuses]
|
||||
print(
|
||||
f"{src:<{src_w}} "
|
||||
+ " ".join(f"{c:>{w}}" for c, w in zip(counts, col_w))
|
||||
)
|
||||
|
||||
# Confidence distribution (positive entries only)
|
||||
buckets = s.get("confidence_buckets", {})
|
||||
non_empty = {k: v for k, v in buckets.items() if v > 0}
|
||||
if non_empty:
|
||||
label_w = max(len(k) for k in non_empty)
|
||||
print("\nConfidence distribution (positive entries):")
|
||||
for label, count in buckets.items():
|
||||
if count > 0:
|
||||
print(f" {label:>{label_w}} : {count}")
|
||||
|
||||
|
||||
@cache_app.command
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "lrx-cli"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
description = "Fetch line-synced lyrics for your music player."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
|
||||
Reference in New Issue
Block a user