fix: 修复6个配置路由500错误 + 实时日志直读文件 + 开启自动同步

- 修复 config_cache/config_refresh/config_acls/config_rules/config_auth/config_peers
  6个路由缺少 save_struct() 调用导致 NameError: name 'ok' is not defined
- logs_live 改为直接读 access.log 文件,不经过 SQLite 缓存,确保实时性
- 仪表盘调整调用顺序:先同步日志再计算统计
- 设置 log_sync_interval=30 开启自动同步(原为0=关闭)
This commit is contained in:
Hermes Agent
2026-07-16 14:41:30 +08:00
parent 6ca58f3dea
commit 43d00d1eda
+15 -9
View File
@@ -818,8 +818,10 @@ def change_password():
@app.route("/")
@login_required
def dashboard():
stats = get_stats()
# Trigger auto-sync first (get_parsed_logs checks _should_auto_sync),
# then compute stats from the now-fresh SQLite data.
entries = get_parsed_logs()
stats = get_stats()
cfg = get_all_config()
# P1-2: surface any active alert rules at the top of the dashboard so
# operators see them without having to navigate to /alerts.
@@ -1060,10 +1062,14 @@ def logs_import():
@app.route("/logs/live")
@login_required
def logs_live():
"""Live tail view (auto-refresh)."""
"""Live tail view (auto-refresh). Reads directly from file for real-time."""
cfg = get_all_config()
n = int(cfg.get("live_tail_lines", 100))
entries = get_parsed_logs(force=False)[-n:]
# Read directly from file - bypass SQLite cache for true real-time
limit = max(n * 3, 500)
text = read_access_log_tail(max_lines=limit)
entries = log_parser.parse_lines(text)
entries = entries[-n:]
entries = list(reversed(entries))
return render_template("logs_live.html", entries=entries,
cfg=cfg, n=n,
@@ -1264,7 +1270,7 @@ def config_acls():
type=types[i] if i < len(types) else "src",
values=vals, comment=cmnt))
struct["acls"] = new_acls
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_acls"))
@@ -1314,7 +1320,7 @@ def config_rules():
idx = int(request.form.get("index", "-1"))
if 0 <= idx < len(struct["rules"]):
del struct["rules"][idx]
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_rules"))
@@ -1364,7 +1370,7 @@ def config_cache():
idx = int(request.form.get("index", "-1"))
if 0 <= idx < len(struct["cache_dirs"]):
del struct["cache_dirs"][idx]
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_cache"))
@@ -1415,7 +1421,7 @@ def config_refresh():
idx = int(request.form.get("index", "-1"))
if 0 <= idx < len(struct["refresh_patterns"]):
del struct["refresh_patterns"][idx]
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_refresh"))
@@ -1468,7 +1474,7 @@ def config_auth():
idx = int(request.form.get("index", "-1"))
if 0 <= idx < len(struct["auth_params"]):
del struct["auth_params"][idx]
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_auth"))
@@ -1521,7 +1527,7 @@ def config_peers():
idx = int(request.form.get("index", "-1"))
if 0 <= idx < len(struct["cache_peers"]):
del struct["cache_peers"][idx]
content_preview = msg if ok else ""
ok, msg, content_preview = save_struct(struct)
if not ok:
flash(msg, "error")
return redirect(url_for("config_peers"))