Skip to content

QgisLogger

Import
from pyqgis_wrapper.utils import QgisLogger, LoggerMixin, create_child_logger

LevelFilter(level=logging.INFO)

Bases: logging.Filter

Provide a filter to log message higher than the filter level

Init the filter with a filter level

Parameters:

Name Type Description Default
level int

Filter level, defaults to logging.INFO

logging.INFO
Source code in pyqgis_wrapper/utils/log_handler.py
49
50
51
52
53
54
55
56
57
def __init__(self, level: int = logging.INFO):
    """
    Init the filter with a filter level

    :param level: Filter level, defaults to logging.INFO
    :type level: logging.INFO, optional
    """
    super().__init__()
    self.level = level

LoggerMixin

Mixin to use to st up a root logger in your plugin.

You can call set_up_logger with the root name of your plugin. All your logger in this plugin with have the settings (log level) from this logger

You can update the level of the filter level using set_level to propagate in childs logger for exmaple given the state of a checkbox.

set_up_logger(root_name='pyqgis_wrapper', feedback=None, level=logging.INFO)

Setup root logger

Parameters:

Name Type Description Default
root_name str

Name of the root logger. Should be the root of your plugin, defaults to "pyqgis_wrapper"

'pyqgis_wrapper'
feedback typing.Optional[qgis.core.QgsProcessingFeedback]

Optionnal feedback object to provide to handler within QGIS, defaults to None

None
level int

Filter level to use, defaults to logging.INFO

logging.INFO
Source code in pyqgis_wrapper/utils/log_handler.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
def set_up_logger(
    self,
    root_name: str = "pyqgis_wrapper",
    feedback: Optional[QgsProcessingFeedback] = None,
    level: int = logging.INFO,
):
    """
    Setup root logger

    :param root_name: Name of the root logger. Should
    be the root of your plugin, defaults to "pyqgis_wrapper"
    :type root_name: str, optional
    :param feedback: Optionnal feedback object to provide to handler within QGIS, defaults to None
    :type feedback: Optional[QgsProcessingFeedback], optional
    :param level: Filter level to use, defaults to logging.INFO
    :type level: int, optional
    """

    self.loggerClass = logging.getLoggerClass()
    logging.setLoggerClass(QgisLogger)
    self._root_logger = logging.getLogger(root_name)
    self._root_logger.__init__(root_name, feedback, level)

unset_logger()

Should be called on plugin unload to reset to original logger

Source code in pyqgis_wrapper/utils/log_handler.py
100
101
102
103
104
def unset_logger(self):
    """
    Should be called on plugin unload to reset to original logger
    """
    logging.setLoggerClass(self.loggerClass)

set_level(level=logging.INFO)

Set the filter levle of the root logger and propagate to child.

Parameters:

Name Type Description Default
level int

Filter level, defaults to logging.INFO

logging.INFO
Source code in pyqgis_wrapper/utils/log_handler.py
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def set_level(self, level: int = logging.INFO):
    """
    Set the filter levle of the root logger and propagate to child.

    :param level: Filter level, defaults to logging.INFO
    :type level: int, optional
    """
    # Update root
    self.root_logger.setLevel(level)
    if level == logging.DEBUG:
        self.root_logger.debug_mode = True
    else:
        self.root_logger.debug_mode = False

    for handler in self.root_logger.handlers:
        for f in handler.filters:
            if isinstance(f, LevelFilter):
                f.set_level(level)

        handler.setLevel(level)

    # Update child
    for name, logger in logging.Logger.manager.loggerDict.items():
        if isinstance(logger, logging.Logger) and name.startswith(self.root_name):
            logger.setLevel(level)
            if level <= logging.DEBUG:
                logger.debug_mode = True
            else:
                logger.debug_mode = False

QgisLogger(name='pyqgis_wrapper', feedback=None, level=logging.INFO)

Bases: logging.Logger

QgisLogger Logger that accept either a stream handler or a QgsFeedback handler

Parameters:

Name Type Description Default
name (str, optional)

Name of the logger (global), defaults to "qgis"

'pyqgis_wrapper'
feedback typing.Optional[qgis.core.QgsProcessingFeedback]

Feedback object if executed within QGIS. Will be use to construct the handler, defaults to None

None
debug_mode (typing.Optional[bool], optional)

If True will output the entire stack trace, defaults to None The state is propagated from the root logger if None.

required
Source code in pyqgis_wrapper/utils/log_handler.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def __init__(
    self,
    name="pyqgis_wrapper",
    feedback: Optional[QgsProcessingFeedback] = None,
    level: int = logging.INFO,
):
    """
    :param name: Name of the logger (global), defaults to "qgis"
    :type name: str, optional
    :param feedback: Feedback object if executed within QGIS.
    Will be use to construct the handler, defaults to None
    :type feedback: Optional[QgsProcessingFeedback], optional
    :param debug_mode: If True will output the entire stack trace, defaults to None
    The state is propagated from the root logger if None.
    :type debug_mode: Optional[bool], optional
    """
    super().__init__(name)
    # Avoid initializint handler in child (duplicated msg)
    self.setLevel(level)
    self.level_filter = LevelFilter(level)
    if level == logging.DEBUG:
        self.debug_mode = True
    else:
        self.debug_mode = False

    if "." not in name:
        self._init_handler(feedback, level)

log_exception(exc, context='')

Catch an error and call the method corresponding to severity

Parameters:

Name Type Description Default
exc Exception

Catched exception

required
context str

Additionnal information to push

''
Source code in pyqgis_wrapper/utils/log_handler.py
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
def log_exception(self, exc: Exception, context: str = ""):
    """
    Catch an error and call the method corresponding to severity

    :param exc: Catched exception
    :type exc: Exception
    :param context: Additionnal information to push
    :type context: str
    """
    severity = getattr(exc, "severity", "ERROR")
    level = getattr(logging, severity, logging.ERROR)
    fatal = getattr(exc, "fatal", False)

    exc_type = type(exc).__name__

    if bool(context):
        context += " "
    message = f"{exc_type}: {context}{str(exc)}"
    # self.log(level, message, exc_info=self.debug_mode)
    # if fatal:
    #     raise exc
    if fatal or self.debug_mode:
        raise exc
    else:
        self.log(level, message, exc_info=self.debug_mode)

FeedbackLogHandler(feedback)

Bases: logging.Handler

QgsProcessingFeedback handler for execution within QGIS

Parameters:

Name Type Description Default
feedback qgis.core.QgsProcessingFeedback

Feedback object

required
Source code in pyqgis_wrapper/utils/log_handler.py
235
236
237
238
239
240
241
def __init__(self, feedback: QgsProcessingFeedback):
    """
    :param feedback: Feedback object
    :type feedback: QgsProcessingFeedback
    """
    super().__init__()
    self.feedback = feedback

create_child_logger(name)

Set up a child logger with levle and debug mode of the direct parent

Parameters:

Name Type Description Default
name str

Name of the child

required

Returns:

Type Description
QgisLogger

Child logger

Source code in pyqgis_wrapper/utils/log_handler.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def create_child_logger(name: str) -> QgisLogger:
    """
    Set up a child logger with levle and debug mode of the direct parent

    :param name: Name of the child
    :type name: str

    :return: Child logger
    :rtype: QgisLogger
    """
    child = logging.getLogger(name)
    parent = child.parent
    if parent is not None and isinstance(parent, QgisLogger):
        child.debug_mode = parent.debug_mode
    else:
        child.debug_mode = False
    child.setLevel(parent.level)
    return child