From 43d00d1eda454822b5ca36f44c30370b190f7e53 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Thu, 16 Jul 2026 14:41:30 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D6=E4=B8=AA=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=B7=AF=E7=94=B1500=E9=94=99=E8=AF=AF=20+=20?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=97=A5=E5=BF=97=E7=9B=B4=E8=AF=BB=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20+=20=E5=BC=80=E5=90=AF=E8=87=AA=E5=8A=A8=E5=90=8C?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 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=关闭) --- app.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app.py b/app.py index 367477a..721b1e0 100644 --- a/app.py +++ b/app.py @@ -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"))