# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2020 ifm electronic gmbh
#
# THE PROGRAM IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
#
"""
This module provides a service which maps log messages coming from c++ and qt to python log messages.
It is automatically used by NEXT_LOG_*() macros in c++.
"""
import logging
import os.path
import sys
from nexxT.Qt.QtCore import QObject, Slot, qInstallMessageHandler, QtMsgType
from nexxT.core.Utils import excepthook
logger = logging.getLogger(__name__)
# see https://stackoverflow.com/questions/32443808/best-way-to-override-lineno-in-python-logger
# pylint: disable=too-many-arguments
# pylint: disable=unused-argument
[docs]
def makeRecord(self, name, level, filename, lineno, msg, args, excInfo, func=None, extra=None, sinfo=None):
"""
A factory method which can be overridden in subclasses to create
specialized LogRecords.
"""
if extra is not None:
filename, lineno = extra
name = f"c++/{os.path.split(filename)[1]}"
return logging.LogRecord(name, level, filename, lineno, msg, args, excInfo, func, sinfo)
# pylint: enable=too-many-arguments
# pylint: enable=unused-argument
logger.__class__ = type("CplusplusLogger", (logger.__class__,), dict(makeRecord=makeRecord))
[docs]
class ConsoleLogger(QObject):
"""
Logging service to console (using python logging module). This class is used to log messages in C++.
"""
[docs]
@Slot(int, str, str, int)
def log(self, level, message, file, line):
"""
Called from c++ to log a message.
:param level: logging compatible log level
:param message: message as a string
:param file: file which originated the log message
:param line: line of log message statement
:return:
"""
logger.log(level, message, extra=(file, line))
[docs]
@staticmethod
def qtMessageHandler(qtMsgType, qMessageLogContext, msg):
"""
Qt message handler for handling qt messages in normal logging.
:param qtMsgType: qt log level
:param qMessageLogContext: qt log context
:param msg: message as a string
:return:
"""
typeMap = {QtMsgType.QtDebugMsg : logging.DEBUG,
QtMsgType.QtInfoMsg : logging.INFO,
QtMsgType.QtWarningMsg : logging.WARNING,
QtMsgType.QtCriticalMsg : logging.CRITICAL,
QtMsgType.QtFatalMsg : logging.FATAL}
logger.log(typeMap[qtMsgType], msg, extra=(qMessageLogContext.file if qMessageLogContext.file is not None
else "<qt>", qMessageLogContext.line))
[docs]
@staticmethod
def installCrashHandlers(force=False):
"""
Install crash handlers:
- QT message handler
- sys.excepthook
:param force: if set to true, overwrite the crash handlers even if we have installed them already.
"""
if not getattr(ConsoleLogger.installCrashHandlers, "executed", False) or force:
ConsoleLogger.installCrashHandlers.executed = True
qInstallMessageHandler(ConsoleLogger.qtMessageHandler)
sys.excepthook = excepthook