agent v1.4: MySQL/MariaDB live metrics (_mysql_stats)
Same fields as the postgres variant: sizes/tables/rows/top tables from information_schema.TABLES, connections/uptime from SHOW GLOBAL STATUS, InnoDB buffer-pool hit ratio as cache_hit_pct. Best-effort like the rest — any failure returns None and never disturbs the heartbeat.
This commit is contained in:
+43
-2
@@ -22,7 +22,7 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
VERSION = "1.3"
|
VERSION = "1.4"
|
||||||
RESULT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".dump-result.json")
|
RESULT_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".dump-result.json")
|
||||||
|
|
||||||
|
|
||||||
@@ -81,9 +81,11 @@ def db_version(t):
|
|||||||
def db_stats(t):
|
def db_stats(t):
|
||||||
"""Read-only live metrics for the dashboard's 'nerd stats' — size, tables, rows, index
|
"""Read-only live metrics for the dashboard's 'nerd stats' — size, tables, rows, index
|
||||||
footprint, connections, cache-hit ratio, the biggest tables, server version + uptime.
|
footprint, connections, cache-hit ratio, the biggest tables, server version + uptime.
|
||||||
Best-effort: any failure returns None and never disturbs the heartbeat. Postgres only."""
|
Best-effort: any failure returns None and never disturbs the heartbeat."""
|
||||||
if t["engine"] == "sqlite":
|
if t["engine"] == "sqlite":
|
||||||
return _sqlite_stats(t)
|
return _sqlite_stats(t)
|
||||||
|
if t["engine"] in ("mysql", "mariadb"):
|
||||||
|
return _mysql_stats(t)
|
||||||
if t["engine"] != "postgres":
|
if t["engine"] != "postgres":
|
||||||
return None
|
return None
|
||||||
env = dict(os.environ, PGPASSWORD=t["pw"])
|
env = dict(os.environ, PGPASSWORD=t["pw"])
|
||||||
@@ -120,6 +122,45 @@ def db_stats(t):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _mysql_stats(t):
|
||||||
|
"""Live metrics for MySQL/MariaDB, same fields as the postgres variant. Sizes and row
|
||||||
|
counts come from information_schema.TABLES (InnoDB estimates — same spirit as
|
||||||
|
n_live_tup); cache hit is the InnoDB buffer pool hit ratio."""
|
||||||
|
def q(sql):
|
||||||
|
r = subprocess.run(("mysql", "-h", t["host"], "-P", t["port"], "-u", t["user"],
|
||||||
|
f"-p{t['pw']}", "-N", "-B", t["db"], "-e", sql),
|
||||||
|
capture_output=True, text=True, timeout=30)
|
||||||
|
return r.stdout.strip()
|
||||||
|
|
||||||
|
def status(var):
|
||||||
|
out = q(f"SHOW GLOBAL STATUS LIKE '{var}'")
|
||||||
|
return int(out.split("\t")[1]) if "\t" in out else 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
size, idx, tables, rows = (int(float(v or 0)) for v in q(
|
||||||
|
"SELECT COALESCE(SUM(data_length+index_length),0),"
|
||||||
|
" COALESCE(SUM(index_length),0), COUNT(*), COALESCE(SUM(table_rows),0)"
|
||||||
|
" FROM information_schema.TABLES"
|
||||||
|
" WHERE table_schema=DATABASE() AND table_type='BASE TABLE'").split("\t"))
|
||||||
|
top = [{"name": f[0], "bytes": int(f[1]), "rows": int(f[2])}
|
||||||
|
for f in (line.split("\t") for line in q(
|
||||||
|
"SELECT table_name, data_length+index_length, COALESCE(table_rows,0)"
|
||||||
|
" FROM information_schema.TABLES"
|
||||||
|
" WHERE table_schema=DATABASE() AND table_type='BASE TABLE'"
|
||||||
|
" ORDER BY data_length+index_length DESC LIMIT 10").splitlines())
|
||||||
|
if len(f) == 3]
|
||||||
|
req = status("Innodb_buffer_pool_read_requests")
|
||||||
|
miss = status("Innodb_buffer_pool_reads")
|
||||||
|
return {"size_bytes": size, "tables": tables, "rows_est": rows,
|
||||||
|
"index_bytes": idx, "connections": status("Threads_connected"),
|
||||||
|
"cache_hit_pct": round(100.0 * (req - miss) / req, 2) if req else None,
|
||||||
|
"server_version": q("SELECT VERSION()"),
|
||||||
|
"uptime_s": status("Uptime") or None,
|
||||||
|
"top_tables": top}
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _sqlite_stats(t):
|
def _sqlite_stats(t):
|
||||||
"""Live metrics for a SQLite file: file size, table count, row totals, largest tables."""
|
"""Live metrics for a SQLite file: file size, table count, row totals, largest tables."""
|
||||||
def q(sql):
|
def q(sql):
|
||||||
|
|||||||
Reference in New Issue
Block a user