fix: detect system_event_logout for real WeChat status
Previously only looked for WeChat send OK/error in last 200 log lines. system_event_logout was missed, so dashboard showed 正常 when session was actually dead. Now: - Greps full webhook log for system_event_login/logout - Logout after login => logged_out status - WeChat send timeout (Hermes error) also counts as failure
This commit is contained in:
@@ -613,7 +613,7 @@ def _augment_wechat_status(entry):
|
|||||||
r = subprocess.run(["tail", "-200", webhook_log],
|
r = subprocess.run(["tail", "-200", webhook_log],
|
||||||
capture_output=True, text=True, timeout=5)
|
capture_output=True, text=True, timeout=5)
|
||||||
lines = r.stdout.strip().split("\n") if r.stdout else []
|
lines = r.stdout.strip().split("\n") if r.stdout else []
|
||||||
last_ok, last_err, last_login = None, None, None
|
last_ok, last_err, last_login, last_logout = None, None, None, None
|
||||||
for line in reversed(lines):
|
for line in reversed(lines):
|
||||||
ts_match = re.match(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", line)
|
ts_match = re.match(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", line)
|
||||||
ts = ts_match.group(1) if ts_match else None
|
ts = ts_match.group(1) if ts_match else None
|
||||||
@@ -621,17 +621,32 @@ def _augment_wechat_status(entry):
|
|||||||
last_ok = ts
|
last_ok = ts
|
||||||
elif "WeChat send error" in line and ts and not last_err:
|
elif "WeChat send error" in line and ts and not last_err:
|
||||||
last_err = ts
|
last_err = ts
|
||||||
if "system_event_login" in line and ts and not last_login:
|
if last_ok and last_err:
|
||||||
last_login = ts
|
|
||||||
if last_ok and last_err and last_login:
|
|
||||||
break
|
break
|
||||||
|
# Login/logout events: search full log (not just tail -200)
|
||||||
|
try:
|
||||||
|
for ev, key in (("system_event_logout", "last_logout"), ("system_event_login", "last_login")):
|
||||||
|
er = subprocess.run(["grep", ev, webhook_log],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
ev_lines = [l for l in er.stdout.strip().split("\n") if l.strip()]
|
||||||
|
if ev_lines:
|
||||||
|
m = re.match(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", ev_lines[-1])
|
||||||
|
if m:
|
||||||
|
if key == "last_login":
|
||||||
|
last_login = m.group(1)
|
||||||
|
else:
|
||||||
|
last_logout = m.group(1)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
ok_dt = err_dt = None
|
ok_dt = err_dt = logout_dt = None
|
||||||
if last_ok:
|
if last_ok:
|
||||||
ok_dt = datetime.strptime(last_ok, "%Y-%m-%d %H:%M:%S")
|
ok_dt = datetime.strptime(last_ok, "%Y-%m-%d %H:%M:%S")
|
||||||
entry["session_age_hours"] = round((now - ok_dt).total_seconds() / 3600, 1)
|
entry["session_age_hours"] = round((now - ok_dt).total_seconds() / 3600, 1)
|
||||||
if last_err:
|
if last_err:
|
||||||
err_dt = datetime.strptime(last_err, "%Y-%m-%d %H:%M:%S")
|
err_dt = datetime.strptime(last_err, "%Y-%m-%d %H:%M:%S")
|
||||||
|
if last_logout:
|
||||||
|
logout_dt = datetime.strptime(last_logout, "%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
# Check docker logs for recent login (catches fresh logins before webhook sees them)
|
# Check docker logs for recent login (catches fresh logins before webhook sees them)
|
||||||
# Check webhook log for login event
|
# Check webhook log for login event
|
||||||
@@ -642,7 +657,18 @@ def _augment_wechat_status(entry):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
dlogin_dt = _docker_login_check()
|
dlogin_dt = _docker_login_check()
|
||||||
if err_dt and login_dt and login_dt > err_dt:
|
# Logout is the most authoritative signal: if logout happened after the last login, session is dead
|
||||||
|
if logout_dt and login_dt and logout_dt > login_dt:
|
||||||
|
entry["login_ok"] = False
|
||||||
|
h = round((now - logout_dt).total_seconds() / 3600, 1)
|
||||||
|
entry["message"] = "已掉线" if h < 1 else f"已掉线 {h:.0f}h"
|
||||||
|
entry["status"] = "logged_out"
|
||||||
|
elif logout_dt and dlogin_dt and logout_dt > dlogin_dt:
|
||||||
|
entry["login_ok"] = False
|
||||||
|
h = round((now - logout_dt).total_seconds() / 3600, 1)
|
||||||
|
entry["message"] = "已掉线" if h < 1 else f"已掉线 {h:.0f}h"
|
||||||
|
entry["status"] = "logged_out"
|
||||||
|
elif err_dt and login_dt and login_dt > err_dt:
|
||||||
entry["login_ok"] = True
|
entry["login_ok"] = True
|
||||||
entry["session_age_hours"] = round((now - login_dt).total_seconds() / 3600, 1)
|
entry["session_age_hours"] = round((now - login_dt).total_seconds() / 3600, 1)
|
||||||
h = entry["session_age_hours"]
|
h = entry["session_age_hours"]
|
||||||
@@ -1757,10 +1783,20 @@ def api_wechat_status():
|
|||||||
result["last_ok_at"] = ts
|
result["last_ok_at"] = ts
|
||||||
elif "WeChat send error" in line and ts and not result["last_err_at"]:
|
elif "WeChat send error" in line and ts and not result["last_err_at"]:
|
||||||
result["last_err_at"] = ts
|
result["last_err_at"] = ts
|
||||||
if "system_event_login" in line and ts and not result.get("last_login_at"):
|
if result["last_ok_at"] and result["last_err_at"]:
|
||||||
result["last_login_at"] = ts
|
|
||||||
if result["last_ok_at"] and result["last_err_at"] and result.get("last_login_at"):
|
|
||||||
break
|
break
|
||||||
|
# Login/logout events: search full log (not just tail -200)
|
||||||
|
try:
|
||||||
|
for ev, key in (("system_event_logout", "last_logout_at"), ("system_event_login", "last_login_at")):
|
||||||
|
er = subprocess.run(["grep", ev, webhook_log],
|
||||||
|
capture_output=True, text=True, timeout=5)
|
||||||
|
ev_lines = [l for l in er.stdout.strip().split("\n") if l.strip()]
|
||||||
|
if ev_lines:
|
||||||
|
m = re.match(r"^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})", ev_lines[-1])
|
||||||
|
if m:
|
||||||
|
result[key] = m.group(1)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1772,12 +1808,14 @@ def api_wechat_status():
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ok_dt = err_dt = None
|
ok_dt = err_dt = logout_dt = None
|
||||||
try:
|
try:
|
||||||
if result["last_ok_at"]:
|
if result["last_ok_at"]:
|
||||||
ok_dt = datetime.strptime(result["last_ok_at"], "%Y-%m-%d %H:%M:%S")
|
ok_dt = datetime.strptime(result["last_ok_at"], "%Y-%m-%d %H:%M:%S")
|
||||||
if result["last_err_at"]:
|
if result["last_err_at"]:
|
||||||
err_dt = datetime.strptime(result["last_err_at"], "%Y-%m-%d %H:%M:%S")
|
err_dt = datetime.strptime(result["last_err_at"], "%Y-%m-%d %H:%M:%S")
|
||||||
|
if result.get("last_logout_at"):
|
||||||
|
logout_dt = datetime.strptime(result["last_logout_at"], "%Y-%m-%d %H:%M:%S")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1790,7 +1828,15 @@ def api_wechat_status():
|
|||||||
login_dt = datetime.strptime(result["last_login_at"], "%Y-%m-%d %H:%M:%S")
|
login_dt = datetime.strptime(result["last_login_at"], "%Y-%m-%d %H:%M:%S")
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
if err_dt and login_dt and login_dt > err_dt:
|
if logout_dt and login_dt and logout_dt > login_dt:
|
||||||
|
result["online"] = False
|
||||||
|
h = round((now - logout_dt).total_seconds() / 3600, 1)
|
||||||
|
result["message"] = "已掉线" if h < 1 else f"已掉线 {h:.0f}h 前"
|
||||||
|
elif logout_dt and dlogin_dt and logout_dt > dlogin_dt:
|
||||||
|
result["online"] = False
|
||||||
|
h = round((now - logout_dt).total_seconds() / 3600, 1)
|
||||||
|
result["message"] = "已掉线" if h < 1 else f"已掉线 {h:.0f}h 前"
|
||||||
|
elif err_dt and login_dt and login_dt > err_dt:
|
||||||
result["online"] = True
|
result["online"] = True
|
||||||
result["session_age_hours"] = round((now - login_dt).total_seconds() / 3600, 1)
|
result["session_age_hours"] = round((now - login_dt).total_seconds() / 3600, 1)
|
||||||
h = result["session_age_hours"]
|
h = result["session_age_hours"]
|
||||||
|
|||||||
Reference in New Issue
Block a user