Paper fork: harden latest.log tailing across rotation/restart

- Detect inode changes and truncation in tail_log
- Reopen latest.log automatically when Paper recreates log file
- Prevent lost trigger parsing after server restarts
This commit is contained in:
2026-03-15 23:40:41 -04:00
parent d2c302b48e
commit 08e8f067ad
+29 -9
View File
@@ -6,7 +6,7 @@ validates targets, and executes commands via RCON.
Config: /etc/mc_aigod.json Config: /etc/mc_aigod.json
""" """
import json, random, re, socket, struct, threading, time, logging import json, os, random, re, socket, struct, threading, time, logging
from collections import deque from collections import deque
from datetime import datetime from datetime import datetime
import requests import requests
@@ -1534,14 +1534,34 @@ def divine_intervention_loop(config):
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def tail_log(log_path): def tail_log(log_path):
with open(log_path, 'r') as f: """
f.seek(0, 2) Follow latest.log robustly across truncation/rotation.
while True: Paper can recreate latest.log on restart; we detect inode changes and reopen.
line = f.readline() """
if line: f = open(log_path, 'r')
yield line f.seek(0, 2)
else: current_inode = os.fstat(f.fileno()).st_ino
time.sleep(0.2)
while True:
line = f.readline()
if line:
yield line
continue
# No new line yet; check for rotation/truncation
try:
st = os.stat(log_path)
if st.st_ino != current_inode or st.st_size < f.tell():
f.close()
f = open(log_path, 'r')
current_inode = os.fstat(f.fileno()).st_ino
f.seek(0, 2)
log.info("Reattached log tail after latest.log rotation/truncation")
except FileNotFoundError:
# During restart, file may not exist briefly
pass
time.sleep(0.2)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Main # Main