spacr.qt.logging_util

Qt-side extension of the package-scope logger.

Delegates all file-handler configuration to spacr.logging_util and adds a QtLogHandler that emits every formatted record over a Qt signal so widgets on the main thread can display them without cross-thread violations.

Two sinks end up wired at spacr-qt startup:

  1. The rotating file handler at ~/.spacr/logs/spacr.log (installed by spacr.logging_util).

  2. The QtLogHandler here — ConsolePanel connects to its record_ready(str, int) signal.

Public API:

setup_logging(…) — call once early in launch(). get_signal_handler() — the shared QtLogHandler instance. log_path() — absolute path of the rotating log file.

Classes

QtLogHandler

A logging.Handler that emits every formatted record over a Qt

Functions

get_logger(→ logging.Logger)

Convenience wrapper — returns a child logger under spacr.qt.

get_signal_handler(→ QtLogHandler)

Return the shared QtLogHandler. Instantiated on first access.

log_dir(→ pathlib.Path)

Return the folder where spacr log files live.

log_path(→ pathlib.Path)

Return the absolute path of the rotating log file.

setup_logging(→ None)

Install the file handler + the Qt signal handler on the root

Module Contents

class spacr.qt.logging_util.QtLogHandler(level: int = logging.INFO)[source]

Bases: PySide6.QtCore.QObject, logging.Handler

A logging.Handler that emits every formatted record over a Qt signal so QWidget slots (running on the main thread) can display them without cross-thread violations.

Variables:

record_ready – signal (formatted_line, levelno) emitted once per record.

Parameters:

level – the minimum level to relay, as logging.Handler takes it.

Create a logging handler that re-emits records as a Qt signal.

The signal lives on a small relay object rather than on the handler itself, and is re-exported here so the existing handler.record_ready.connect(...) contract is unchanged – only the QObject that owns it moved.

Parameters:

level – the minimum level to relay.

emit(record: logging.LogRecord) → None[source]

Format and re-emit record over record_ready.

Records produced while a console panel is mid-write are dropped. Every ConsolePanel in the process subscribes to record_ready, so without this a record logged from inside append_stdout — which the function-trace profile hook emits on entry to every spaCR function — comes straight back into the same widget. _StdoutBlock.append answers it with a nested setPlainText, and the inner call destroys the QTextDocument’s frames while the outer one is still inside QTextDocumentPrivate::clear(): a segfault, gdb’d to QTextFrame::~QTextFrame.

The latch lives in spacr.qt.verbose_logger because that module owns the console-target contract; this is the second sink that has to honour it. Measured: a 30-file shard still dumped core in the same place when only the first sink was guarded.

Parameters:

record – the log record; it is formatted with this handler’s formatter and emitted with its levelno.

spacr.qt.logging_util.get_logger(name: str = 'spacr.qt') → logging.Logger[source]

Convenience wrapper — returns a child logger under spacr.qt.

Parameters:

name – logger name, defaults to "spacr.qt".

spacr.qt.logging_util.get_signal_handler() → QtLogHandler[source]

Return the shared QtLogHandler. Instantiated on first access.

spacr.qt.logging_util.log_dir() → pathlib.Path[source]

Return the folder where spacr log files live.

Alias for spacr.logging_util.log_dir().

spacr.qt.logging_util.log_path() → pathlib.Path[source]

Return the absolute path of the rotating log file.

Alias for spacr.logging_util.log_path().

spacr.qt.logging_util.setup_logging(level: int = logging.INFO, console_level: int = logging.INFO) → None[source]

Install the file handler + the Qt signal handler on the root logger. Idempotent — safe to call more than once.

Parameters:
  • level – minimum record level for the rotating file handler.

  • console_level – minimum record level for the Qt signal handler (i.e. what ConsolePanel receives).