Add owner-only logging and Brickset API call tracking
LIM configured no logging at all, so the instruction fetcher had no trail to follow. Adds a rotating file handler on the root logger plus two owner-only admin pages. - Admin > Logs: filter by level, source and text; tracebacks kept with their error; auto-refresh, raw download, rotated-file browsing and rotate-now - Admin > Logs > Brickset API calls: every outbound call recorded with method, params, caller, duration, result count and error, plus daily quota accounting (only getSets counts) and a comparison against getKeyUsageStats - New owner concept (services/ownership.py): a single account, distinct from is_admin, since these pages expose other admins activity. Defaults to the first admin; flask owner show/set to change - Services now log through module loggers; retention setting and pruning for call records - New CLI: flask owner show/set, flask logs path/prune - New table brickset_api_calls, created automatically at boot; LOG_* env vars, /data/logs in Docker
This commit is contained in:
1 parent
89f65e2d74
commit
f7c20de5ac
27 files changed
+1914
-35
No files matched your search
@@ -18,10 +18,13 @@ with `flask instructions run` instead.
|
||||
Created by: Jess Rogerson (yelling commands at Claude.AI)
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_thread = None
|
||||
_stop = threading.Event()
|
||||
_lock = threading.Lock()
|
||||
@@ -38,7 +41,7 @@ def _is_cli_command():
|
||||
def start(app):
|
||||
"""Start the ticker unless it's disabled or already running."""
|
||||
if not app.config.get('INSTRUCTION_FETCH_WORKER', True):
|
||||
app.logger.info('Instruction fetch worker disabled by config')
|
||||
logger.info('Instruction fetch worker disabled by config')
|
||||
return False
|
||||
|
||||
# `flask instructions run`, `flask backup restore` and friends shouldn't
|
||||
@@ -61,7 +64,8 @@ def start(app):
|
||||
daemon=True)
|
||||
_thread.start()
|
||||
|
||||
app.logger.info('Instruction fetch worker started')
|
||||
logger.info('Instruction fetch worker started (tick %ss)',
|
||||
app.config.get('INSTRUCTION_FETCH_TICK_SECONDS', 20))
|
||||
return True
|
||||
|
||||
|
||||
@@ -86,7 +90,7 @@ def _loop(app):
|
||||
with app.app_context():
|
||||
fetcher.run_one()
|
||||
except Exception:
|
||||
app.logger.exception('Instruction fetch worker tick failed')
|
||||
logger.exception('Instruction fetch worker tick failed')
|
||||
|
||||
|
||||
def run_once_async(app, force=False):
|
||||
@@ -102,7 +106,7 @@ def run_once_async(app, force=False):
|
||||
from app.services import instruction_fetcher as fetcher
|
||||
fetcher.run_one(force=force)
|
||||
except Exception:
|
||||
app.logger.exception('Manual instruction fetch failed')
|
||||
logger.exception('Manual instruction fetch failed')
|
||||
|
||||
thread = threading.Thread(target=_work, name='lim-fetch-once', daemon=True)
|
||||
thread.start()
|
||||
|
||||
Reference in new issue
Block a user