Backup automatico script del 2026-07-12 07:00
This commit is contained in:
@@ -12,12 +12,15 @@ import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import Optional, List, Tuple
|
||||
from typing import Any, Dict, Optional, List, Tuple
|
||||
|
||||
DEBUG = os.environ.get("DEBUG", "0").strip() == "1"
|
||||
|
||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
LOG_FILE = os.path.join(SCRIPT_DIR, "daily_report.log")
|
||||
_default_log = os.path.join(SCRIPT_DIR, "daily_report.log")
|
||||
if not os.access(SCRIPT_DIR, os.W_OK):
|
||||
_default_log = "/data/daily_report.log"
|
||||
LOG_FILE = os.environ.get("DAILY_REPORT_LOG", _default_log)
|
||||
|
||||
TELEGRAM_CHAT_IDS = ["64463169", "24827341", "132455422", "5405962012"]
|
||||
|
||||
@@ -215,24 +218,24 @@ def docker_copy_db_to_temp() -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def generate_report(db_path: str) -> Optional[str]:
|
||||
def generate_report_data(db_path: str) -> Optional[Dict[str, Any]]:
|
||||
"""Aggrega gli speedtest completati nelle ultime 24 ore."""
|
||||
now_utc = datetime.datetime.now(datetime.timezone.utc)
|
||||
window_start_utc = now_utc - datetime.timedelta(hours=24)
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect(db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# NOTA: non filtriamo su created_at (string compare fragile).
|
||||
# Prendiamo le ultime MAX_ROWS righe completate e filtriamo in Python.
|
||||
query = """
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT download, upload, ping, created_at
|
||||
FROM results
|
||||
WHERE status = 'completed'
|
||||
ORDER BY created_at DESC
|
||||
LIMIT ?
|
||||
"""
|
||||
cursor.execute(query, (MAX_ROWS,))
|
||||
""",
|
||||
(MAX_ROWS,),
|
||||
)
|
||||
raw_rows = cursor.fetchall()
|
||||
except Exception as e:
|
||||
LOGGER.exception("Errore DB (%s): %s", db_path, e)
|
||||
@@ -247,13 +250,14 @@ def generate_report(db_path: str) -> Optional[str]:
|
||||
LOGGER.info("Nessun test trovato.")
|
||||
return None
|
||||
|
||||
# Filtra realmente per datetime (ultime 24h) e ordina crescente
|
||||
rows: List[Tuple[datetime.datetime, float, float, float]] = []
|
||||
rows: List[Dict[str, Any]] = []
|
||||
total_down = 0.0
|
||||
total_up = 0.0
|
||||
issues = 0
|
||||
|
||||
for d_raw, u_raw, ping_raw, created_at in raw_rows:
|
||||
dt_utc = _parse_created_at_utc(created_at)
|
||||
if not dt_utc:
|
||||
continue
|
||||
if dt_utc < window_start_utc or dt_utc > now_utc:
|
||||
if not dt_utc or dt_utc < window_start_utc or dt_utc > now_utc:
|
||||
continue
|
||||
|
||||
d_mbps = _to_mbps(d_raw)
|
||||
@@ -263,60 +267,75 @@ def generate_report(db_path: str) -> Optional[str]:
|
||||
except Exception:
|
||||
ping_ms = 0.0
|
||||
|
||||
rows.append((dt_utc, d_mbps, u_mbps, ping_ms))
|
||||
below = d_mbps < WARN_DOWN or u_mbps < WARN_UP
|
||||
if below:
|
||||
issues += 1
|
||||
|
||||
rows.sort(key=lambda x: x[0])
|
||||
total_down += d_mbps
|
||||
total_up += u_mbps
|
||||
rows.append({
|
||||
"time": dt_utc.astimezone().strftime("%H:%M"),
|
||||
"created_at": dt_utc.astimezone().isoformat(),
|
||||
"download_mbps": round(d_mbps, 1),
|
||||
"upload_mbps": round(u_mbps, 1),
|
||||
"ping_ms": round(ping_ms, 1),
|
||||
"below_threshold": below,
|
||||
})
|
||||
|
||||
LOGGER.debug("DB rows read=%s filtered_24h=%s (start=%s now=%s)",
|
||||
len(raw_rows), len(rows),
|
||||
window_start_utc.isoformat(timespec="seconds"),
|
||||
now_utc.isoformat(timespec="seconds"))
|
||||
rows.sort(key=lambda r: r["created_at"])
|
||||
|
||||
if not rows:
|
||||
LOGGER.info("Nessun test nelle ultime 24h dopo filtro datetime.")
|
||||
return None
|
||||
|
||||
header = "ORA | Dn | Up | Pg |!"
|
||||
sep = "-----+-----+-----+----+-"
|
||||
|
||||
total_down = 0.0
|
||||
total_up = 0.0
|
||||
count = 0
|
||||
issues = 0
|
||||
|
||||
count = len(rows)
|
||||
avg_d = total_down / count
|
||||
avg_u = total_up / count
|
||||
now_local = datetime.datetime.now()
|
||||
msg = f"📊 **REPORT VELOCITÀ 24H**\n📅 {now_local.strftime('%d/%m/%Y')}\n\n"
|
||||
|
||||
return {
|
||||
"date": now_local.strftime("%d/%m/%Y"),
|
||||
"window_hours": 24,
|
||||
"count": count,
|
||||
"issues": issues,
|
||||
"warn_download_mbps": WARN_DOWN,
|
||||
"warn_upload_mbps": WARN_UP,
|
||||
"avg_download_mbps": round(avg_d, 1),
|
||||
"avg_upload_mbps": round(avg_u, 1),
|
||||
"avg_download_ok": avg_d >= WARN_DOWN,
|
||||
"avg_upload_ok": avg_u >= WARN_UP,
|
||||
"rows": rows,
|
||||
}
|
||||
|
||||
|
||||
def generate_report(db_path: str) -> Optional[str]:
|
||||
data = generate_report_data(db_path)
|
||||
if not data:
|
||||
return None
|
||||
|
||||
header = "ORA | Dn | Up | Pg |!"
|
||||
sep = "-----+-----+-----+----+-"
|
||||
|
||||
msg = f"📊 **REPORT VELOCITÀ 24H**\n📅 {data['date']}\n\n"
|
||||
msg += "```text\n"
|
||||
msg += header + "\n"
|
||||
msg += sep + "\n"
|
||||
|
||||
for dt_utc, d_mbps, u_mbps, ping_ms in rows:
|
||||
total_down += d_mbps
|
||||
total_up += u_mbps
|
||||
count += 1
|
||||
|
||||
flag = " "
|
||||
if d_mbps < WARN_DOWN or u_mbps < WARN_UP:
|
||||
issues += 1
|
||||
flag = "!"
|
||||
|
||||
time_str = dt_utc.astimezone().strftime("%H:%M")
|
||||
|
||||
msg += f"{time_str:<5}|{int(round(d_mbps)):>5}|{int(round(u_mbps)):>5}|{int(round(ping_ms)):>4}|{flag}\n"
|
||||
for row in data["rows"]:
|
||||
flag = "!" if row["below_threshold"] else " "
|
||||
msg += (
|
||||
f"{row['time']:<5}|{int(round(row['download_mbps'])):>5}|"
|
||||
f"{int(round(row['upload_mbps'])):>5}|{int(round(row['ping_ms'])):>4}|{flag}\n"
|
||||
)
|
||||
|
||||
msg += "```\n"
|
||||
|
||||
avg_d = total_down / count
|
||||
avg_u = total_up / count
|
||||
icon_d = "✅" if data["avg_download_ok"] else "⚠️"
|
||||
icon_u = "✅" if data["avg_upload_ok"] else "⚠️"
|
||||
msg += f"Ø ⬇️{icon_d}`{data['avg_download_mbps']:.0f} Mbps` ⬆️{icon_u}`{data['avg_upload_mbps']:.0f} Mbps`"
|
||||
|
||||
icon_d = "✅" if avg_d >= WARN_DOWN else "⚠️"
|
||||
icon_u = "✅" if avg_u >= WARN_UP else "⚠️"
|
||||
|
||||
msg += f"Ø ⬇️{icon_d}`{avg_d:.0f} Mbps` ⬆️{icon_u}`{avg_u:.0f} Mbps`"
|
||||
|
||||
if issues > 0:
|
||||
msg += f"\n\n⚠️ **{issues}** test sotto soglia (!)"
|
||||
if data["issues"] > 0:
|
||||
msg += f"\n\n⚠️ **{data['issues']}** test sotto soglia (!)"
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
Reference in New Issue
Block a user