Auto-fix day logs are deleted a calendar month after their date
Only files named exactly '<YYYY-MM-DD> <Weekday> Auto-Fix.log' in that folder; checked when a new day's file starts and when the watchdog starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -73,7 +73,7 @@ During that window, with ALARMS on, the panel fixes a problem by itself once it
|
||||
- At most 2 tries per problem, 90 s apart; then it is yours to hold.
|
||||
- It waits while the network is having a blip, and does nothing to Dante when several devices vanish at once (that is NA Ingest's view or the Dante network, not the Macs).
|
||||
- Never automatic: restarting a running ProPresenter, Bible app, ProdCom (or DVS on NA Ingest, which restarts ProdCom), captions or the bridge, power-cycling a switch port, or turning on a connection someone switched off. `load_config` refuses an auto fix that closes a program.
|
||||
- **Daily log:** everything auto-fix does is written as it happens to `~/Desktop/Auto-Fix Logs/<date> <weekday> Auto-Fix.log` on NA Ingest (e.g. `2026-10-11 Sunday Auto-Fix.log`): the problem, what it did, whether it worked, when the fault cleared, when it gave up or held back. Double-click it to open it in Console, which shows new lines live.
|
||||
- **Daily log:** everything auto-fix does is written as it happens to `~/Desktop/Auto-Fix Logs/<date> <weekday> Auto-Fix.log` on NA Ingest (e.g. `2026-10-11 Sunday Auto-Fix.log`): the problem, what it did, whether it worked, when the fault cleared, when it gave up or held back. Double-click it to open it in Console, which shows new lines live. One file per day; each is deleted a calendar month after its date (the 11 Oct file on 11 Nov).
|
||||
- Press ALARMS to mute the panel for maintenance: that also stops auto-fix. The window and the list are `"auto_fix"` in `config.json`.
|
||||
|
||||
## Restart page (page 20)
|
||||
|
||||
@@ -15,6 +15,7 @@ Stdlib only; runs on the macOS /usr/bin/python3 (3.9).
|
||||
status_panel.py --dry-run run, but never write to Companion
|
||||
"""
|
||||
import argparse
|
||||
import calendar
|
||||
import http.client
|
||||
import json
|
||||
import logging
|
||||
@@ -585,10 +586,41 @@ class AutoLog:
|
||||
e.g. "~/Desktop/Auto-Fix Logs/2026-10-11 Sunday Auto-Fix.log" (a .log opens in Console, which
|
||||
shows new lines live)."""
|
||||
|
||||
NAME = re.compile(r"^(\d{4})-(\d{2})-(\d{2}) [A-Za-z]+ Auto-Fix\.log$")
|
||||
|
||||
def __init__(self, directory):
|
||||
self.dir = os.path.expanduser(directory)
|
||||
self.lock = threading.Lock()
|
||||
|
||||
def cleanup(self, now):
|
||||
"""Delete day files once they are a calendar month old (the 11 Oct file goes on 11 Nov).
|
||||
Only files named exactly like these logs are ever touched."""
|
||||
today = datetime.fromtimestamp(now).date()
|
||||
removed = []
|
||||
try:
|
||||
names = os.listdir(self.dir)
|
||||
except OSError:
|
||||
return removed
|
||||
for name in names:
|
||||
m = self.NAME.match(name)
|
||||
if not m:
|
||||
continue
|
||||
y, mo, d = (int(x) for x in m.groups())
|
||||
y2, mo2 = (y + 1, 1) if mo == 12 else (y, mo + 1)
|
||||
try:
|
||||
due = datetime(y2, mo2, min(d, calendar.monthrange(y2, mo2)[1])).date()
|
||||
except ValueError:
|
||||
continue
|
||||
if today >= due:
|
||||
try:
|
||||
os.remove(os.path.join(self.dir, name))
|
||||
removed.append(name)
|
||||
except OSError as e:
|
||||
log.warning("auto-fix log cleanup %s: %s", name, e)
|
||||
if removed:
|
||||
log.info("auto-fix logs older than a month deleted: %s", ", ".join(sorted(removed)))
|
||||
return removed
|
||||
|
||||
def path(self, now):
|
||||
return os.path.join(self.dir, datetime.fromtimestamp(now).strftime("%Y-%m-%d %A") + " Auto-Fix.log")
|
||||
|
||||
@@ -600,6 +632,8 @@ class AutoLog:
|
||||
os.makedirs(self.dir, exist_ok=True)
|
||||
path = self.path(now)
|
||||
new = not os.path.exists(path)
|
||||
if new:
|
||||
self.cleanup(now) # a new day: drop files a month old
|
||||
with open(path, "a", encoding="utf-8") as f:
|
||||
if new:
|
||||
f.write("Status panel auto-fixes - %s\n"
|
||||
@@ -697,6 +731,8 @@ class Engine:
|
||||
self.auto_tries = {} # fix identity -> [tries, last try time] for the fault now going on
|
||||
self.auto_seen = {} # fix identity -> last time it was in an auto plan
|
||||
self.autolog = AutoLog(self.auto.get("log_dir", "~/Desktop/Auto-Fix Logs")) if self.auto else None
|
||||
if self.autolog:
|
||||
self.autolog.cleanup(time.time())
|
||||
self.auto_watch = {} # "BUTTON FAULT" auto-fix went after -> when (to log when it clears)
|
||||
self.auto_paused = False
|
||||
self.auto_on = False # inside the window (for the "auto-fix on" line)
|
||||
|
||||
@@ -722,6 +722,21 @@ class TestFixes(unittest.TestCase):
|
||||
self.assertIn("-> done, checking it comes back", body[1])
|
||||
self.assertIn("OK again: ABLETON NOT RUNNING (15 s after the auto-fix)", body[2])
|
||||
|
||||
def test_auto_fix_logs_go_after_a_month(self):
|
||||
d = tempfile.mkdtemp()
|
||||
names = ["2026-09-10 Thursday Auto-Fix.log", "2026-09-11 Friday Auto-Fix.log", # a month old
|
||||
"2026-09-12 Saturday Auto-Fix.log", "2026-10-04 Sunday Auto-Fix.log", # not yet
|
||||
"notes.txt", "2026-01-01 Thursday Auto-Fix.log.bak"] # not ours
|
||||
for n in names:
|
||||
open(os.path.join(d, n), "w").close()
|
||||
removed = sp.AutoLog(d).cleanup(SUNDAY) # Sunday 11 Oct 2026
|
||||
self.assertEqual(sorted(removed), names[:2])
|
||||
self.assertEqual(sorted(os.listdir(d)), sorted(names[2:]))
|
||||
open(os.path.join(d, "2026-01-31 Saturday Auto-Fix.log"), "w").close() # month ends: 28 Feb
|
||||
self.assertEqual(sp.AutoLog(d).cleanup(datetime(2026, 2, 27, 9).timestamp()), [])
|
||||
self.assertEqual(sp.AutoLog(d).cleanup(datetime(2026, 2, 28, 9).timestamp()),
|
||||
["2026-01-31 Saturday Auto-Fix.log"])
|
||||
|
||||
def test_auto_fix_tries_twice_then_leaves_it_to_you(self):
|
||||
ran, comp = self.auto_setup()
|
||||
self.snap.remote["tracks\0pgrep -xq Live"] = False
|
||||
|
||||
Reference in New Issue
Block a user