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
"""
import json, random, re, socket, struct, threading, time, logging
import json, os, random, re, socket, struct, threading, time, logging
from collections import deque
from datetime import datetime
import requests
@@ -1534,14 +1534,34 @@ def divine_intervention_loop(config):
# ---------------------------------------------------------------------------
def tail_log(log_path):
with open(log_path, 'r') as f:
f.seek(0, 2)
while True:
line = f.readline()
if line:
yield line
else:
time.sleep(0.2)
"""
Follow latest.log robustly across truncation/rotation.
Paper can recreate latest.log on restart; we detect inode changes and reopen.
"""
f = open(log_path, 'r')
f.seek(0, 2)
current_inode = os.fstat(f.fileno()).st_ino
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