简体   繁体   English

Python日志记录:仅记录到处理程序而不是root

[英]Python logging: log only to handlers not to root

I have the following class: 我有以下课程:

class Log(object):

# class new
#new is used instead of init because __new__ is able to return (where __init__ can't)
def __new__(self, name, consolelevel, filelevel):

    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(name)s: %(message)s')

    #Create consolehandler and set formatting (level is set in the ROOT)
    consolehandler = StreamHandler()
    consolehandler.setFormatter(formatter)

    #Create filehandler, set level and set formatting
    filehandler = FileHandler(name + '.log')
    filehandler.setLevel(filelevel)
    filehandler.setFormatter(formatter)

    #Create the root logger, add console and file logger. Set the rootlevel == consolelevel.
    self.root = logging.getLogger(name)

    #causing me problems....
    self.root.setLevel(consolelevel)

    self.root.addHandler(consolehandler)
    self.root.addHandler(filehandler)
    self.root.propagate = True

    return self.root

# Close the logger object
def close():
    # to be implemented
    pass

I use this class to log to the console and to a file (depending on the set level). 我使用此类来登录控制台和文件(取决于设置的级别)。 The problem is that the root level seems to be leading for the addhandlers. 问题在于,根级别似乎领先于addhandlers。 Is there a way to disable this? 有没有办法禁用此功能? Now I set the rootlevel to the same level as the consolelevel but this does not work... 现在,我将根级别设置为与控制台级别相同的级别,但这不起作用...

Any advice? 有什么建议吗?

Thanks in advance and with best regards, 在此先致以最诚挚的谢意,

JR JR

A problem that I can see in your code is that it will add more handlers whenever you instantiate the Log class. 我在您的代码中看到的一个问题是,每当实例化Log类时,它将添加更多处理程序。 You probably do not want this. 您可能不希望这样。

Keep in mind that getLogger returns always the same instance when called with the same argument, and basically it implements the singleton pattern. 请记住,当使用相同的参数调用getLogger时,它总是返回相同的实例,并且基本上实现了单例模式。 Hence when you later call addHandler it will add a new handler everytime. 因此,当您以后调用addHandler ,它将每次都添加一个新的处理程序。

The way to deal with logging is to create a logger at the module level and use it. 处理方式logging是建立在模块级记录器并使用它。

Also I'd avoid using __new__ . 另外我会避免使用__new__ In your case you can use a simple function. 您可以使用一个简单的函数。 And note that your Log.close method wont work, because your __new__ method does not return a Log instance, and thus the returned logger doesn't have that method. 并请注意,您的Log.close方法将无法工作,因为__new__方法不会返回Log实例,因此返回的记录器没有该方法。

Regarding the level of the logger, I don't understand why you do not set the level on the consolehandler but on the whole logger. 关于记录器的级别,我不明白为什么您没有在consolehandler而是在整个记录器上设置级别。

This is a simplified version of the module I am making. 这是我正在制作的模块的简化版本。 The module contains a few classes that all need a logging functionality. 该模块包含一些都需要日志记录功能的类。 Each class logs to a different file and and it should also be possible to change the file handler levels between classes (eg gamepad class: console.debug and filehandler.info and MQTT class: console info and filehandler.debug). 每个类都记录到不同的文件,并且还应该可以在类之间更改文件处理程序级别(例如,游戏手柄类:console.debug和filehandler.info和MQTT类:控制台信息和filehandler.debug)。

Therefor I thought that setting up a log class would be the easiest way. 因此,我认为设置日志类将是最简单的方法。 Please bear in mind that I usually do electronics but now combined with python. 请记住,我通常做电子产品,但现在与python结合使用。 So my skills are pretty basic.... 所以我的技能很基础。

#!/bin/env python2.7

from future import division from operator import * import logging from logging import FileHandler from logging import StreamHandler import pygame import threading from pygame.locals import * import mosquitto import time from time import sleep import sys 从操作员导入的未来导入部门*从日志记录的导入日志记录导入从日志记录的导入FileHandler导入StreamHandler导入pygame.locals导入pygame导入线程*导入mosquit到从导入睡眠导入系统开始的时间

class ConsoleFileLogger(object): ConsoleFileLogger(object)类:

# class constructor
def __init__(self, filename, loggername, rootlevel, consolelevel, filelevel):

    # logger levels: DEBUG, INFO, WARNING, ERROR, CRITICAL

    # define a root logger and set its ROOT logging level
    logger = logging.getLogger(loggername)
    logger.setLevel(rootlevel)

    # define a Handler which writes messages or higher to the sys.stderr (Console)
    self.console = logging.StreamHandler()
    # set the logging level
    self.console.setLevel(consolelevel)

    # define a Handler which writes messages to a logfile
    self.logfile = logging.FileHandler(filename + '.log')
    # set the logging level
    self.logfile.setLevel(filelevel)

    # create formatter and add it to the handlers
    formatter = logging.Formatter('%(asctime)s %(levelname)s: %(name)s: %(message)s')
    self.console.setFormatter(formatter)
    self.logfile.setFormatter(formatter)

    # add the handlers to the root logger
    logger.addHandler(self.console)
    logger.addHandler(self.logfile)

    self._logger = logger

# set a net instance of the logger
def set(self):
    return self._logger

# Stop and remove the ConsoleFileLogger object
def remove(self):
    self._logger.removeHandler(self.console)
    self._logger.removeHandler(self.logfile)
    self._logfile.FileHandler().close()

class Gamepad(): Gamepad()类:

# class constructor
def __init__(self, mqttgamepad):
    self.logger = ConsoleFileLogger('BaseLogFiles/Gamepad', 'Gamepad', logging.INFO, logging.INFO, logging.INFO).set()

    if joystickcount == 0:
        self.logger.error('No gamepad connected')
    elif joystickcount == 1:
        self.gamepad = pygame.joystick.Joystick(0)
        self.gamepad.init()
        self.logger.debug('Joystick name %s', self.gamepad.get_name())
        self.logger.debug('nb of axes = %s', self.gamepad.get_numaxes())
        self.logger.debug('nb of balls = %s', self.gamepad.get_numballs())
        self.logger.debug('nb of buttons = %s', self.gamepad.get_numbuttons())
        self.logger.debug('nb of mini joysticks = %s', self.gamepad.get_numhats())
    elif joystickcount > 1:
        self.logger.error('only one gamepad is allowed')

def run(self):
    self.logger.debug('gamepad running')

class MQTTClient(): MQTTClient()类:

def __init__(self, clientname):
    self.logger = ConsoleFileLogger('BaseLogFiles/MQTT/Pub', clientname, logging.DEBUG, logging.DEBUG, logging.DEBUG).set()
    self.logger.debug('test')

def run(self):
       self.logger.info('Connection MQTT Sub OK')

def main(): logger = ConsoleFileLogger('BaseLogFiles/logControlCenterMain', 'ControlCenterMain', logging.DEBUG, logging.DEBUG, logging.DEBUG).set() def main():logger = ConsoleFileLogger('BaseLogFiles / logControlCenterMain','ControlCenterMain',logging.DEBUG,logging.DEBUG,logging.DEBUG).set()

mqttclient = MQTTClient("MQTTClient")
mqttclient.connect()

gamepad = Gamepad(mqttclient)

if gamepad.initialized():
    gamepadthread = threading.Thread(target=gamepad.run)
    gamepadthread.start()

    mqtttpubhread = threading.Thread(target=mqttclient.run)
    mqtttpubhread.start()

logger.info('BaseMain started')

# Monitor the running program for a KeyboardInterrupt exception
# If this is the case all threads and other methods can be closed the correct way :)
while 1:
    try:
        sleep(1)
    except KeyboardInterrupt:
        logger.info('Ctrl-C pressed')
        gamepad.stop()
        mqttclient.stop()
        logger.info('BaseMain stopped')
        sys.exit(0)

if name == ' main ': main() 如果名称 ==' main ':main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM