pyqt-logging-manager
Reusable logging utilities for PyQt6 applications.
This package wraps the complete logging setup - file handlers, GUI handler, and history dialogs - in one LoggingManager class that can be reused in PyQt6 projects without project-specific changes.
Current version: 1.1.1
Contents
- Features
- Requirements
- Installation
- Quick Start
- LoggingManager API
- LogColumn
- Additional Classes And Functions
- Examples
Features
LoggingManager: initialize once and let the manager wire everything up.- RotatingFileHandler for all file handlers, with configurable maximum file size and backup count.
- Optional handlers for main logs, error logs, and debug logs.
- GUI integration through
QTextEditwith level-based color coding. - Log history dialogs with filter buttons (All / Warnings + Errors / Errors Only).
- Bounded GUI history through the optional
max_recordssetting. - Structured formatter configuration through the
LogColumnenum instead of raw format strings. - Thread-safe GUI logging:
GuiLoggerforwards records from worker threads to the GUI thread through a Qt signal. - Safe log paths: generated file names cannot escape the configured log directory.
- No project-specific code and no external runtime dependency besides PyQt6.
Requirements
- Python >= 3.13
- PyQt6
Installation
Install From PyPI
pip install pyqt-logging-manager
Editable Install From A Local Checkout
Use this during development so package changes are immediately visible in consuming projects.
# Clone the package from GitLab
git clone git@gitlab.dlr.de:fm/fks/thermoelektrik/python-lib/pyqt-logging-manager.git
# Install it into the target project after activating its virtual environment
pip install -e /path/to/pyqt-logging-manager
Install Directly From GitLab
pip install git+ssh://git@gitlab.dlr.de/fm/fks/thermoelektrik/python-lib/pyqt-logging-manager.git
Install A Specific Version Or Tag
pip install git+ssh://git@gitlab.dlr.de/fm/fks/thermoelektrik/python-lib/pyqt-logging-manager.git@v1.1.1
Quick Start
Minimal GUI-Only Usage
from pyqt_logging_manager import LoggingManager
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
uic.loadUi("my_app.ui", self)
self.log_manager = LoggingManager(system_name="MyTool")
self.log_manager.connect_widget(self.plainLog) # QTextEdit from the UI
logger = self.log_manager.get_logger("MAIN")
logger.info("Application started")
Standard File Configuration
from pyqt_logging_manager import LoggingManager
self.log_manager = LoggingManager(
system_name="MyApplication",
system_version="1.2.0",
log_dir="logs/",
)
self.log_manager.connect_widget(self.plainLog)
Creates: logs/MyApplication.log
LoggingManager currently attaches its handlers to Python's root logger. This allows loggers created in other modules with logging.getLogger(...) to use the same handlers without receiving a manager instance.
Full Configuration
from pyqt_logging_manager import LoggingManager, LogColumn
import logging
self.log_manager = LoggingManager(
system_name="MyApplication",
system_version="1.2.0",
log_dir="logs/",
level=logging.INFO,
delete_old_logs=True,
error_log=True, # -> logs/MyApplication_Error.log
debug=True, # -> logs/MyApplication_Debug.log
max_bytes=20_000_000, # 20 MB per file
backup_count=5, # max. 5 backup files
columns=[
(LogColumn.TIMESTAMP, 32),
(LogColumn.LEVEL, 10),
(LogColumn.LOGGER, 16),
(LogColumn.MESSAGE, 0),
],
separator="\t",
)
self.log_manager.connect_widget(self.plainLog)
# Run custom logic for warnings, for example opening a dialog
self.log_manager.connect_extra_slot(self._on_warning)
logger = self.log_manager.get_logger("MAIN")
logger.info("Ready")
LoggingManager API
Constructor
LoggingManager(
system_name: str,
system_version: str = "",
log_dir: str | None = None,
level: int = logging.INFO,
delete_old_logs: bool = True,
error_log: bool = False,
debug: bool = False,
max_bytes: int = 20_000_000,
backup_count: int = 5,
formatter_string: str | None = None,
formatter_width: int | None = None,
columns: list[tuple[LogColumn, int]] | None = None,
separator: str = "\t",
max_records: int | None = None,
)
| Parameter | Type | Default | Description |
|---|---|---|---|
system_name |
str |
- | Application name used for log headers and as the sanitized file-name base. |
system_version |
str |
"" |
Optional version shown in the log header. |
log_dir |
str | None |
None |
Directory for log files. None means GUI-only logging. |
level |
int |
logging.INFO |
Minimum root logger level. |
delete_old_logs |
bool |
True |
Delete current log files and rotating backups at startup. When False, existing logs are preserved and a new start header is appended. |
error_log |
bool |
False |
Create a separate error FileHandler for WARNING and above. |
debug |
bool |
False |
Create a debug RotatingFileHandler for DEBUG and above. |
max_bytes |
int |
20_000_000 |
Maximum file size in bytes for all file handlers. |
backup_count |
int |
5 |
Maximum number of backup files per handler. |
formatter_string |
str | None |
None |
Raw Python logging format string. Overrides columns. |
formatter_width |
int | None |
128 |
Automatic line wrap width. |
columns |
list | None |
None |
Structured column definition; see LogColumn. |
separator |
str |
"\t" |
Separator between columns. |
max_records |
int | None |
None |
Maximum entries retained in GUI widgets and history dialogs. |
Formatter priority: formatter_string > columns > default format.
Log File Names And Existing Logs
Only letters, numbers, _, and - from system_name are used unchanged in generated file names. Spaces, path separators, dots, and other characters become _. Windows-reserved names such as CON, NUL, COM1, and LPT1 receive a leading underscore.
My Application -> My_Application.log
../outside -> ___outside.log
CON -> _CON.log
All resolved log paths must remain inside log_dir; paths through symlinks to files outside that directory are rejected with ValueError.
The default delete_old_logs=True starts with fresh log files. To keep logs across application starts, set:
self.log_manager = LoggingManager(
system_name="MyApplication",
log_dir="logs/",
delete_old_logs=False,
)
Methods
connect_widget(widget: QTextEdit) -> None
Connects a QTextEdit as GUI log output. In PyQt6 projects, call this after loadUi().
self.log_manager.connect_widget(self.plainLog)
get_logger(name: str) -> logging.Logger
Returns a named logger. All loggers automatically propagate to all registered handlers.
logger = self.log_manager.get_logger("CALC_ENGINE")
logger.warning("Temperature outside the expected range")
connect_extra_slot(slot) -> None
Connects an additional slot to the GuiLogger signal. Call this after connect_widget().
The slot must have the signature (message: str, level: int, levelname: str).
def _on_warning(self, _msg: str, level: int, _name: str) -> None:
if level >= logging.WARNING:
self.log_manager.show_errors(parent=self)
self.log_manager.connect_extra_slot(self._on_warning)
show_history(parent: QWidget | None = None) -> None
Opens the log history dialog with all records and filter buttons. If it is already open, it is brought to the foreground.
self.log_manager.show_history(parent=self)
show_errors(parent: QWidget | None = None) -> None
Opens the error log dialog for warnings and errors only. If it is already open, it is brought to the foreground.
self.log_manager.show_errors(parent=self)
Attributes
| Attribute | Type | Description |
|---|---|---|
log_records |
list[tuple[str, int, str]] |
All log records as (message, level, levelname). |
LogColumn
Instead of a raw format string, the formatter can be configured with the LogColumn enum and column widths.
from pyqt_logging_manager import LogColumn
columns=[
(LogColumn.TIMESTAMP, 32), # Timestamp, 32 characters
(LogColumn.LEVEL, 10), # Log level, 10 characters
(LogColumn.LOGGER, 16), # Logger name, 16 characters
(LogColumn.MESSAGE, 0), # Message, no fixed width
]
Width 0 means no padding; the field is as wide as needed.
Available Column Types
LogColumn.X |
Content | Example Value |
|---|---|---|
TIMESTAMP |
Date and time | 2026-05-05 14:32:01 |
LEVEL |
Log level | INFO, WARNING, ERROR |
LOGGER |
Logger name | MAIN, CALC_ENGINE |
MESSAGE |
Message | Calculation finished |
FILE |
Source file without path | calc_engine.py |
LINE |
Line number | 217 |
FUNCTION |
Function name | run_segment |
Additional Classes And Functions
GuiLogger
Qt-based logging.Handler that forwards records as pyqtSignal(str, int, str). It is used internally by LoggingManager, but can also be used directly.
WrappingFormatter
logging.Formatter with automatic line wrapping. Continuation lines are indented below the first message line.
formatter = WrappingFormatter(
fmt="%(asctime)s\t%(levelname)s\t%(message)s",
width=100,
)
LogHistoryDialog
QDialog for displaying and filtering log records. It supports two modes:
mode="all": all records with filter buttons (All / Warnings + Errors / Errors Only).mode="errors": warnings and errors only, with a checkbox to hide warnings.
dialog = LogHistoryDialog(self.log_manager.log_records, mode="all", parent=self)
dialog.show()
setup_exception_hook
Installs a global handler for uncaught exceptions.
from pyqt_logging_manager import setup_exception_hook
setup_exception_hook(
logger=self.log_manager.get_logger("MAIN"),
show_dialog=True,
parent=self,
)
add_measurement_log_handler / remove_measurement_log_handler
Adds a temporary FileHandler for a measurement and removes it afterwards.
from pyqt_logging_manager import add_measurement_log_handler, remove_measurement_log_handler
# Start measurement
handler = add_measurement_log_handler(
log_dir="measurements/2026-05-05/",
measurement_name="Run_01",
)
# ... measurement is running ...
# End measurement
remove_measurement_log_handler(handler)
Measurement names use the same safe file-name conversion as system_name.
Legacy Helpers
setup_multi_handler_logger() and rotate_default_log_files() remain available for existing applications. New integrations should prefer LoggingManager, which provides rotating handlers and the complete GUI integration through one API.
Examples
Small GUI Tool Without Files
from pyqt_logging_manager import LoggingManager
self.log_manager = LoggingManager("MyTool")
self.log_manager.connect_widget(self.logWidget)
self.log_manager.get_logger("MAIN").info("Started")
Application With All Handlers
import logging
from pyqt_logging_manager import LoggingManager, LogColumn, setup_exception_hook
self.log_manager = LoggingManager(
system_name="MySystem",
system_version="2.0.0",
log_dir="logs/",
error_log=True,
debug=True,
columns=[
(LogColumn.TIMESTAMP, 24),
(LogColumn.LEVEL, 8),
(LogColumn.LOGGER, 20),
(LogColumn.MESSAGE, 0),
],
)
self.log_manager.connect_widget(self.plainLog)
self.log_manager.connect_extra_slot(self._auto_open_errors)
setup_exception_hook(
logger=self.log_manager.get_logger("MAIN"),
show_dialog=True,
parent=self,
)
Loggers In Other Modules
# In calc_engine.py; no LoggingManager import required
import logging
class CalcEngine:
def __init__(self):
self.logger = logging.getLogger("CALC_ENGINE")
def run(self):
self.logger.info("Calculation starts")
# ...
self.logger.debug("Segment 5 finished")
All records automatically propagate to the root logger and therefore to all handlers managed by LoggingManager.
License
Internal - DLR FM-KP
Metadata
Release files for pyqt-logging-manager 1.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pyqt_logging_manager-1.1.1.tar.gz | 18.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pyqt_logging_manager-1.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.5 kB
Release files / pyqt_logging_manager-1.1.1.tar.gz
| Download URL | pyqt_logging_manager-1.1.1.tar.gz |
|---|---|
| Size | 18.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88487fbdb24fb7b67aaef6455783117f3248824def19ebe0de5d3bf03c297418
|
|
BLAKE2b-256 checksum How to use checksums |
3e647ccc00c32de67952000484437c55e3928b7d7be74cad639f04919b99e06e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / pyqt_logging_manager-1.1.1-py3-none-any.whl
| Download URL | pyqt_logging_manager-1.1.1-py3-none-any.whl |
|---|---|
| Size | 15.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0400d7f5b3472dcc8b3b5145d7e4ad14d1c1b4247a25799a28cf03a416aeb0cf
|
|
BLAKE2b-256 checksum How to use checksums |
8592bcc553cfb48b22e1408398b2b8f086484980adc1af152cde378a80025785
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|