Tag plugin logs structurally and surface the active plugin in System Logs (#418)

- get_logger() now returns a PluginLoggerAdapter when given a plugin_id,
  so every plugin log call is stamped with plugin_id automatically instead
  of only calls that explicitly passed extra={'plugin_id': ...}. This makes
  the "[Plugin: x]" prefix reliable in the journalctl-backed log stream.
- display_controller publishes the currently active mode/plugin to the
  shared cache whenever it changes, exposed via a new
  GET /api/v3/display/current-status endpoint.
- System Logs page: adds a "Now showing" banner backed by that endpoint, a
  plugin filter dropdown (populated from parsed log lines), a plugin badge
  per log entry, and fixes log parsing to handle the short-iso timestamp
  format journalctl actually returns (the old regex only matched syslog
  timestamps, so level/plugin extraction silently never ran).

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-07-18 10:59:36 -04:00
committed by GitHub
co-authored by Claude
parent c90129285c
commit 6a9d8014e5
5 changed files with 245 additions and 40 deletions
+23
View File
@@ -7022,6 +7022,29 @@ def list_plugin_assets():
logger.error('Unhandled exception', exc_info=True)
return jsonify({'status': 'error', 'message': 'An error occurred; see logs for details'}), 500
@api_v3.route('/display/current-status', methods=['GET'])
def get_current_display_status():
"""Return the display mode/plugin currently intended to be shown.
Published by the display process (display_controller._publish_current_mode_state)
to the shared cache whenever the active mode changes, so the web UI (e.g. the
System Logs page) can show what's on screen without querying the display
process directly.
"""
try:
cache = _ensure_cache_manager()
state = cache.get('display_current_state', max_age=120)
if state is None:
state = {
'mode': None,
'plugin_id': None,
'last_updated': None,
}
return jsonify({'status': 'success', 'data': state})
except Exception:
logger.error('Error in get_current_display_status', exc_info=True)
return jsonify({'status': 'error', 'message': 'An error occurred; see logs for details'}), 500
@api_v3.route('/logs', methods=['GET'])
def get_logs():
"""Get system logs from journalctl"""