stratified_packager.toolbelt.logging_records

Record-level machinery for the QGIS logging suite: targets, filters, configs, level mapping.

The dependency-free lower layer of logging: the Target routing flag, the QgisContextFilter / TargetFilter filters, the MessageBarConfig / MessageBoxConfig per-target configs, the EmitPayload cross-thread snapshot, the SUCCESS level and the level_to_qgis() mapping. QgisHandler and QgisLoggerWrapper build on these; nothing here depends on the handler or wrapper, so the import edge runs one way only.

Module Attributes

SUCCESS

Custom logging level between logging.INFO and logging.WARNING.

Functions

level_to_qgis(level)

Convert a stdlib logging level to the nearest qgis.core.Qgis.MessageLevel.

Classes

EmitPayload(targets, plugin_name, tag, ...)

Immutable snapshot of everything needed to render a log record on the main thread.

MessageBarConfig([duration, buttons, ...])

Configuration for the qgis.gui.QgsMessageBar target.

MessageBoxConfig([title, standard_buttons, ...])

Configuration for the QMessageBox target.

QgisContextFilter([static_fields, name, iface])

A logging.Filter that stamps QGIS context and static fields onto records.

Target(*values)

Bit-flag enum selecting which QGIS outputs receive log records.

TargetFilter(allowed_targets[, min_level, name])

logging.Filter that gates records based on Target and minimum logging level.

class stratified_packager.toolbelt.logging_records.EmitPayload(targets, plugin_name, tag, message, level, bar_config, box_config)[source]

Immutable snapshot of everything needed to render a log record on the main thread.

Constructed inside emit() (possibly on a worker thread) and consumed by _render(). Per-call overrides — if present on the record — take precedence over the handler’s own defaults before this object is built, so the render path never needs to inspect the record again.

Parameters:
__init__(targets, plugin_name, tag, message, level, bar_config, box_config)
Parameters:
bar_config: MessageBarConfig

Resolved MessageBarConfig for this record.

box_config: MessageBoxConfig

Resolved MessageBoxConfig for this record.

level: int

Original logging level integer.

message: str

Formatted log message.

plugin_name: str

Human-readable plugin identifier.

tag: str

Tag / topic for qgis.core.QgsMessageLog.

targets: Target

Resolved Target flags for this record.

class stratified_packager.toolbelt.logging_records.MessageBarConfig(duration=5, buttons=<factory>, show_progress=False, progress_value=0, progress_format='%p%')[source]

Configuration for the qgis.gui.QgsMessageBar target.

Parameters:
__init__(duration=5, buttons=<factory>, show_progress=False, progress_value=0, progress_format='%p%')
Parameters:
buttons: list[qgis.PyQt.QtWidgets.QPushButton]

Extra QPushButton instances to embed in the bar.

They are created by the caller and passed here so that signal connections can be set up before the bar shows them.

duration: int = 5

Seconds the message stays visible (0 = permanent).

progress_format: str = '%p%'

Format string for the progress bar.

Passed to setFormat() (e.g. "%p%").

progress_value: int = 0

Initial value of the progress bar (0-100).

show_progress: bool = False

Whether the message bar shows a progress indicator.

When True, a QProgressBar is added to the bar widget.

class stratified_packager.toolbelt.logging_records.MessageBoxConfig(title=None, standard_buttons=qgis.PyQt.QtWidgets.QMessageBox.StandardButton.Ok, default_button=qgis.PyQt.QtWidgets.QMessageBox.StandardButton.Ok, detailed_text=None)[source]

Configuration for the QMessageBox target.

Parameters:
__init__(title=None, standard_buttons=qgis.PyQt.QtWidgets.QMessageBox.StandardButton.Ok, default_button=qgis.PyQt.QtWidgets.QMessageBox.StandardButton.Ok, detailed_text=None)
Parameters:
default_button: qgis.PyQt.QtWidgets.QMessageBox.StandardButton

The button that receives focus by default.

detailed_text: str | None = None

Optional detailed-text string shown via the Show Details expander.

standard_buttons: qgis.PyQt.QtWidgets.QMessageBox.StandardButton

Combination of StandardButton flags to display.

title: str | None = None

Window title of the dialog.

When None, the plugin name supplied to QgisHandler is used.

class stratified_packager.toolbelt.logging_records.QgisContextFilter(static_fields=None, name='', iface=None)[source]

A logging.Filter that stamps QGIS context and static fields onto records.

Attach this filter to a logging.Logger (or to any of its handlers) to have the fields below stamped onto every logging.LogRecord automatically, without any changes to call sites.

Dynamic fields (evaluated lazily at emit time):

qgis_version

The running QGIS version string (e.g. "4.2.0-Belém do Pará").

qgis_project_path

Absolute path of the currently open project file, or an empty string if no project is loaded.

qgis_active_layer_id

ID of the layer currently selected in the layer panel, or an empty string when no layer is active or iface is None.

qgis_locale

The QGIS UI locale string (e.g. "pt_BR").

Static fields (set once at construction, stamped on every record):

Any key/value pairs passed via static_fields are merged onto every record verbatim. This is the intended replacement for call-site extra= dicts: plugin-level constants such as a plugin version, task name, or environment tag belong here rather than being repeated on every log.info(...) call. Static fields are stamped before dynamic fields, so dynamic fields take precedence on name collision.

Example:

log = QgisLoggerWrapper.get_logger("MyPlugin")
context_filter = QgisContextFilter(static_fields={"plugin_version": "1.4.2"}, iface=iface)
log.logger.addFilter(context_filter)

# Every record now carries qgis_version, qgis_project_path,
# qgis_active_layer_id, qgis_locale, and plugin_version.
log.info("Processing started.")

# Per-record context that varies per call still goes in extra=.
log.warning("Bad geometry.", extra={"feature_id": feat.id()})
Parameters:
  • static_fields (dict[str, object] | None)

  • name (str)

  • iface (QgisInterface | None)

__init__(static_fields=None, name='', iface=None)[source]

Initialize the filter.

Parameters:
  • static_fields (dict[str, object] | None) – Plugin-level constant attributes to stamp on every record (e.g. {"plugin_version": "1.4.2", "task": "import"}). Keys must not clash with standard logging.LogRecord attributes.

  • name (str) – Passed to logging.Filter; restricts the filter to records from loggers whose name starts with this prefix. An empty string (the default) matches all loggers.

  • iface (QgisInterface | None) – The QGIS interface instance, used to obtain the active layer id.

filter(record)[source]

Stamp static and dynamic QGIS context fields onto record.

This filter never blocks records — it always returns True. Static fields supplied at construction time are applied first; dynamic QGIS fields are applied second and take precedence on name collision.

Parameters:

record (LogRecord) – The logging.LogRecord to enrich.

Return type:

bool

Returns:

Always True.

_iface: QgisInterface | None
_static_fields: dict[str, object]
class stratified_packager.toolbelt.logging_records.Target(*values)[source]

Bit-flag enum selecting which QGIS outputs receive log records.

Members can be combined with |:

Target.LOG | Target.BAR
static _generate_next_value_(name, start, count, last_values)

Generate the next value when not given.

name: the name of the member start: the initial start value or None count: the number of existing members last_values: the last value assigned or None

BAR = 2

Route to qgis.gui.QgsMessageBar.

DIALOG = 4

Route to a QMessageBox modal dialog.

LOG = 1

Route to qgis.core.QgsMessageLog.

_all_bits_ = 7
_boundary_ = 'strict'
_flag_mask_ = 7
_inverted_ = None
_singles_mask_ = 7
class stratified_packager.toolbelt.logging_records.TargetFilter(allowed_targets, min_level=0, name='')[source]

logging.Filter that gates records based on Target and minimum logging level.

Intended to be attached to a QgisHandler.

This filter expresses permanent, handler-level routing rules — complementing the per-call overrides available through QgisLoggerWrapper methods. A typical use is to restrict a QgisHandler configured with Target.DIALOG to only show modal dialogs for ERROR and above, while the same handler (or a sibling one) routes INFO and WARNING records to the message bar or log panel.

When the record carries a per-call Target override (injected by QgisLoggerWrapper), that override is compared against allowed_targets: the record is allowed through only if the two share at least one flag in common. Records emitted by a plain logging.Logger (no override) are always allowed through, since target routing is the handler’s responsibility in that case.

Example — restrict a DIALOG handler to errors only:

handler = QgisHandler(
    plugin_name="MyPlugin",
    targets=Target.DIALOG,
    box_config=MessageBoxConfig(title="Error"),
)
handler.addFilter(
    TargetFilter(
        allowed_targets=Target.DIALOG,
        min_level=logging.ERROR,
    )
)

Example — a BAR handler that ignores records explicitly routed elsewhere:

bar_handler = QgisHandler(
    plugin_name="MyPlugin",
    targets=Target.BAR,
    bar=iface.messageBar(),
)
bar_handler.addFilter(TargetFilter(allowed_targets=Target.BAR))
Parameters:
__init__(allowed_targets, min_level=0, name='')[source]

Initialize the filter.

Parameters:
  • allowed_targets (Target) – The Target flags this handler is permitted to process. Records whose per-call target override shares no flag with this value are dropped.

  • min_level (int) – Minimum logging level to allow through. Records below this level are dropped regardless of target. Defaults to logging.NOTSET (no additional level gate beyond the logger’s own).

  • name (str) – Passed to logging.Filter; restricts the filter to records from loggers whose name starts with this prefix.

filter(record)[source]

Allow the record through only if it passes both gates.

The two gates, applied in order:

  1. Level gate — the record’s level must be >= min_level.

  2. Target gate — if the record carries a per-call Target override, it must share at least one flag with allowed_targets. Records without an override always pass this gate.

Parameters:

record (LogRecord) – The logging.LogRecord to evaluate.

Return type:

bool

Returns:

True if the record should be processed, False if it should be silently dropped.

_allowed_targets: Target
_min_level: int
property allowed_targets: Target

The Target flags permitted by this filter.

Returns:

The current allowed Target combination.

property min_level: int

Minimum logging level permitted by this filter.

Returns:

An integer logging level constant.

stratified_packager.toolbelt.logging_records._qmsgbox_icon(level)[source]

Return the Icon for a stdlib logging level.

Delegates to level_to_qgis() and then looks up the result in _QGIS_TO_QMSGBOX_ICON, so the two mappings stay in sync.

Parameters:

level (int) – Numeric stdlib level (e.g. logging.WARNING).

Return type:

Icon

Returns:

The corresponding Icon.

stratified_packager.toolbelt.logging_records.level_to_qgis(level)[source]

Convert a stdlib logging level to the nearest qgis.core.Qgis.MessageLevel.

Parameters:

level (int) – Numeric stdlib level (e.g. logging.WARNING) or SUCCESS.

Return type:

MessageLevel

Returns:

The closest matching qgis.core.Qgis.MessageLevel.

stratified_packager.toolbelt.logging_records.SUCCESS: Final = 25

Custom logging level between logging.INFO and logging.WARNING.

Intended for successful operations that deserve user attention.

stratified_packager.toolbelt.logging_records._K_BAR_CFG: Final = '_qgis_bar_config'

Key under which a per-call MessageBarConfig override is stored.

stratified_packager.toolbelt.logging_records._K_BOX_CFG: Final = '_qgis_box_config'

Key under which a per-call MessageBoxConfig override is stored.

stratified_packager.toolbelt.logging_records._K_TARGETS: Final = '_qgis_targets'

Key under which a Target override is stored in the record’s __dict__.

stratified_packager.toolbelt.logging_records._QGIS_TO_QMSGBOX_ICON: Final[dict[Qgis.MessageLevel, QMessageBox.Icon]] = {qgis.core.Qgis.MessageLevel.Critical: qgis.PyQt.QtWidgets.QMessageBox.Icon.Critical, qgis.core.Qgis.MessageLevel.Info: qgis.PyQt.QtWidgets.QMessageBox.Icon.Information, qgis.core.Qgis.MessageLevel.NoLevel: qgis.PyQt.QtWidgets.QMessageBox.Icon.NoIcon, qgis.core.Qgis.MessageLevel.Success: qgis.PyQt.QtWidgets.QMessageBox.Icon.Information, qgis.core.Qgis.MessageLevel.Warning: qgis.PyQt.QtWidgets.QMessageBox.Icon.Warning}

Per-level icon used for modal dialogs.

Maps each qgis.core.Qgis.MessageLevel to a Icon.