Dev_help: trying to add logs to deve_help panel and extend to different error codes
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Dict
|
||||
|
||||
from PySide6.QtCore import Qt, Slot
|
||||
from PySide6.QtGui import QGuiApplication
|
||||
from PySide6.QtCore import Qt, Slot, QUrl
|
||||
from PySide6.QtGui import QGuiApplication, QDesktopServices
|
||||
from PySide6.QtWidgets import (
|
||||
QDialog,
|
||||
QVBoxLayout,
|
||||
@@ -24,6 +25,7 @@ from PySide6.QtWidgets import (
|
||||
)
|
||||
|
||||
from aare.common.error_codes import error_code_help
|
||||
from aare.common.logger_config import QtLogEmitter, QtLogHandler, find_existing_formatter, attach_to_logger
|
||||
from aare.gui.threads.daq_worker import DAQWorker
|
||||
|
||||
|
||||
@@ -110,6 +112,17 @@ class DeveloperHelpDialog(QDialog):
|
||||
self._copy_payload_btn.clicked.connect(self._copy_payload)
|
||||
top.addWidget(self._copy_payload_btn)
|
||||
|
||||
# Staff utilities: open log files
|
||||
self._open_gui_log_btn = QPushButton("Open GUI log", self)
|
||||
self._open_gui_log_btn.setVisible(self._is_staff)
|
||||
self._open_gui_log_btn.clicked.connect(lambda: self._open_log_file_for_logger("aareGUI"))
|
||||
top.addWidget(self._open_gui_log_btn)
|
||||
|
||||
self._open_daq_log_btn = QPushButton("Open DAQ log", self)
|
||||
self._open_daq_log_btn.setVisible(self._is_staff)
|
||||
self._open_daq_log_btn.clicked.connect(lambda: self._open_log_file_for_logger("aareDAQ"))
|
||||
top.addWidget(self._open_daq_log_btn)
|
||||
|
||||
# Tabs
|
||||
self._tabs = QTabWidget(self)
|
||||
root.addWidget(self._tabs, 1)
|
||||
@@ -125,7 +138,6 @@ class DeveloperHelpDialog(QDialog):
|
||||
self._codes_table.itemSelectionChanged.connect(self._update_code_details)
|
||||
self._codes_table.horizontalHeader().setStretchLastSection(True)
|
||||
|
||||
# Details panel (pretty form layout)
|
||||
self._details_frame = QFrame(self)
|
||||
self._details_frame.setFrameShape(QFrame.Shape.StyledPanel)
|
||||
self._details_frame.setStyleSheet(
|
||||
@@ -183,7 +195,12 @@ class DeveloperHelpDialog(QDialog):
|
||||
|
||||
self._tabs.addTab(codes_container, "Error codes")
|
||||
|
||||
# Tab: last error payload (staff only)
|
||||
# Tab: last error payload (staff only) + summary header
|
||||
self._payload_summary = QLabel(self)
|
||||
self._payload_summary.setVisible(self._is_staff)
|
||||
self._payload_summary.setWordWrap(True)
|
||||
self._payload_summary.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
|
||||
self._payload_text = QTextEdit(self)
|
||||
self._payload_text.setReadOnly(True)
|
||||
self._payload_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
|
||||
@@ -192,11 +209,48 @@ class DeveloperHelpDialog(QDialog):
|
||||
payload_container = QWidget(self)
|
||||
payload_layout = QVBoxLayout(payload_container)
|
||||
payload_layout.setContentsMargins(0, 0, 0, 0)
|
||||
payload_layout.addWidget(self._payload_summary, 0)
|
||||
payload_layout.addWidget(self._payload_text, 1)
|
||||
self._tabs.addTab(payload_container, "Last error payload")
|
||||
else:
|
||||
self._payload_text.setPlainText("Hidden (staff only).")
|
||||
|
||||
# Tab: recent payloads (staff only)
|
||||
self._payloads_text = QTextEdit(self)
|
||||
self._payloads_text.setReadOnly(True)
|
||||
self._payloads_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
|
||||
if self._is_staff:
|
||||
payloads_container = QWidget(self)
|
||||
payloads_layout = QVBoxLayout(payloads_container)
|
||||
payloads_layout.setContentsMargins(0, 0, 0, 0)
|
||||
payloads_layout.addWidget(self._payloads_text, 1)
|
||||
self._tabs.addTab(payloads_container, "Recent payloads")
|
||||
|
||||
# Tab: tracebacks (staff only)
|
||||
self._tracebacks_text = QTextEdit(self)
|
||||
self._tracebacks_text.setReadOnly(True)
|
||||
self._tracebacks_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
|
||||
self._tracebacks_text.setPlainText("Tracebacks will appear here (last 10).")
|
||||
|
||||
if self._is_staff:
|
||||
tb_container = QWidget(self)
|
||||
tb_layout = QVBoxLayout(tb_container)
|
||||
tb_layout.setContentsMargins(0, 0, 0, 0)
|
||||
tb_layout.addWidget(self._tracebacks_text, 1)
|
||||
self._tabs.addTab(tb_container, "Tracebacks")
|
||||
|
||||
# Tab: error log (staff only) – live view from python logging
|
||||
self._error_log_text = QTextEdit(self)
|
||||
self._error_log_text.setReadOnly(True)
|
||||
self._error_log_text.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap)
|
||||
if self._is_staff:
|
||||
log_container = QWidget(self)
|
||||
log_layout = QVBoxLayout(log_container)
|
||||
log_layout.setContentsMargins(0, 0, 0, 0)
|
||||
log_layout.addWidget(self._error_log_text, 1)
|
||||
self._tabs.addTab(log_container, "Error log")
|
||||
|
||||
|
||||
# Bottom button box
|
||||
buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close, parent=self)
|
||||
buttons.rejected.connect(self.reject)
|
||||
@@ -206,10 +260,40 @@ class DeveloperHelpDialog(QDialog):
|
||||
# Wire signals
|
||||
self._daq.error_codes_loaded.connect(self.set_error_codes)
|
||||
self._daq.last_error_payload_changed.connect(self.set_last_error_payload)
|
||||
self._daq.last_error_payloads_changed.connect(self.set_last_error_payloads)
|
||||
|
||||
# Hook a Qt logging handler to show ERROR+ messages in the dialog
|
||||
if self._is_staff:
|
||||
self._qt_log_emitter = QtLogEmitter()
|
||||
self._qt_log_emitter.message.connect(self._append_error_log_line)
|
||||
|
||||
self._qt_log_handler = QtLogHandler(self._qt_log_emitter)
|
||||
self._qt_log_handler.setLevel(logging.ERROR)
|
||||
self._qt_log_handler.setFormatter(find_existing_formatter())
|
||||
|
||||
attach_to_logger("aareGUI", self._qt_log_handler)
|
||||
attach_to_logger("aareDAQ", self._qt_log_handler)
|
||||
|
||||
self._update_banner()
|
||||
self._update_code_details()
|
||||
|
||||
def _open_log_file_for_logger(self, logger_name: str) -> None:
|
||||
"""
|
||||
Opens the first FileHandler path attached to the given logger name.
|
||||
"""
|
||||
log = logging.getLogger(logger_name)
|
||||
paths: list[str] = []
|
||||
for h in getattr(log, "handlers", []) or []:
|
||||
p = getattr(h, "baseFilename", None)
|
||||
if p and isinstance(p, str):
|
||||
paths.append(p)
|
||||
|
||||
if not paths:
|
||||
self._banner.setText(f"No file handler found for logger '{logger_name}'.")
|
||||
return
|
||||
|
||||
QDesktopServices.openUrl(QUrl.fromLocalFile(paths[0]))
|
||||
|
||||
@Slot(bool)
|
||||
def _set_freeze_payload(self, enabled: bool) -> None:
|
||||
self._freeze_payload = bool(enabled)
|
||||
@@ -222,6 +306,8 @@ class DeveloperHelpDialog(QDialog):
|
||||
def refresh(self) -> None:
|
||||
self._daq.get_error_codes()
|
||||
self.set_last_error_payload(self._daq.get_last_error_payload())
|
||||
if self._is_staff:
|
||||
self.set_last_error_payloads(self._daq.get_last_error_payloads())
|
||||
|
||||
@Slot(dict)
|
||||
def set_error_codes(self, codes: dict) -> None:
|
||||
@@ -238,9 +324,36 @@ class DeveloperHelpDialog(QDialog):
|
||||
self._last_payload = payload or {}
|
||||
pretty = json.dumps(self._last_payload, indent=2, sort_keys=True, default=str)
|
||||
self._payload_text.setPlainText(pretty)
|
||||
|
||||
code, msg = self._extract_code_message()
|
||||
url = str((self._last_payload or {}).get("url") or "")
|
||||
status = (self._last_payload or {}).get("http_status")
|
||||
self._payload_summary.setText(
|
||||
f"URL: {url}\nHTTP: {status}\nCode: {code or '-'}\nMessage: {msg or '-'}"
|
||||
)
|
||||
|
||||
self._update_banner()
|
||||
self._select_code_from_last_error()
|
||||
|
||||
@Slot(list)
|
||||
def set_last_error_payloads(self, payloads: list) -> None:
|
||||
if not self._is_staff:
|
||||
return
|
||||
blocks: list[str] = []
|
||||
for i, p in enumerate(payloads[-10:], start=max(1, len(payloads) - 9)):
|
||||
try:
|
||||
pretty = json.dumps(p or {}, indent=2, sort_keys=True, default=str)
|
||||
except Exception:
|
||||
pretty = str(p)
|
||||
blocks.append(f"#{i}\n{pretty}")
|
||||
self._payloads_text.setPlainText("\n\n".join(blocks) if blocks else "(none captured yet)")
|
||||
|
||||
@Slot(str)
|
||||
def _append_error_log_line(self, line: str) -> None:
|
||||
if not self._is_staff:
|
||||
return
|
||||
self._error_log_text.append(line)
|
||||
|
||||
def _code_name_for_value(self, value: str) -> str | None:
|
||||
for k, v in self._codes.items():
|
||||
if v == value:
|
||||
|
||||
Reference in New Issue
Block a user