简体   繁体   English

使用python日志记录两次写入

[英]Two writes using python logging

I have two files of classes with essentially the same set up of logging: 我有两个类的文件,它们的日志设置基本相同:

"""code - of 1 class the parent with mods from Reut's answer"""
logger = None
def __init__(self, verboseLevel=4):
    '''
    Constructor
    '''    
    loggingLevels={1: logging.DEBUG,
               2: logging.INFO,
               3: logging.WARNING,
               4: logging.ERROR,
               5: logging.CRITICAL}

    #debug(), info(), warning(), error(), critical()
    if not tdoa.logger:
        tdoa.logger=logging.getLogger('TDOA')
        if (verboseLevel in range(1,6)):
            logging.basicConfig(format='%(message)s',level=loggingLevels[verboseLevel])
        else:
            logging.basicConfig(format='%(levelname)s:%(message)s',level=logging.DEBUG)
            tdoa.logger.critical("Incorrect logging level specified!")
    self.logger = tdoa.logger
    self.logger.debug("TDOA calculator using Newton's method.")
    self.verboseLevel = verboseLevel


    """code of second "subclass" (with Reut's changes) (who's function is printing twice):"""


def  __init__(self, verboseLevel=1, numberOfBytes=2, filename='myfile.log', ipaddr='127.0.0.1',getelset= True):
    #debug(), info(), warning(), error(), critical()
    # go through all this to know that only one logger is instantiated per class
    # Set debug level
    # set up various handlers (remove Std_err one for deployment unless you want them going to screen
    # create console handler with a higher log level
    if not capture.logger:
        capture.logger=logging.getLogger('SatGeo')
        console = logging.StreamHandler()

        if (verboseLevel in range(1,6)):
            console.setLevel(self.loggingLevels[verboseLevel])
            logging.basicConfig(format='%(message)s',level=self.loggingLevels[verboseLevel],
                                filename=filename,filemode='a') #format='%(levelname)s:%(message)s'
        else:
            logging.basicConfig(format='%(message)s',level=logging.DEBUG,
                                filename=filename,filemod='a')
            console.setLevel(logging.DEBUG)
            capture.logger.critical("Incorrect logging level specified!")

        # create formatter and add it to the handlers
        #formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        #console.setFormatter(formatter)
        # add the handlers to logger
        handlers=capture.logger.handlers
        if (console not in handlers):
            capture.logger.addHandler(console)
        else:
            capture.logger.critical("not adding handler")

    self.logger=capture.logger

I have a function in the "called class (satgeo)" that 'writes' to the logger: 我在“称为类(satgeo)”中有一个功能,可以“写入”记录器:

def printMyself(self, rowDict):
    ii=1
    for res in rowDict:
        self.logger.critical('{0}************************************'.format(ii))
        ii+=1
        for key, value in res.items():
            self.logger.critical(' Name: {0}\t\t Value:{1}'.format(key, value))

When I call it by itself I get one output per self.logger call; 当我自己调用它时,每个self.logger调用都会得到一个输出; but when I call it from the tdoa class it writes TWICE: for example: 但是当我从tdoa类调用它时,它写了TWICE:例如:

 Name: actualLat         Value:36.455444
 Name: actualLat         Value:36.455444

Any idea of how to fix this? 关于如何解决这个问题的任何想法?

You are adding a handler to the parent class each time you construct a class instance using this line: 每次使用此行构造类实例时,您都将向父类添加一个处理程序:

self.logger.addHandler(console)

So if you do something like: 因此,如果您执行以下操作:

for _ in range(x):
    SubClass1()
some_operation_with_logging()

You should be seeing x messages, since you just added x handlers to the logger by doing x calls to parent's __init__ . 您应该会看到x消息,因为您刚刚通过对父级的__init__进行x调用而将x处理程序添加到了记录器中。

You don't want to be doing that, make sure you add a handler only once ! 您不想这样做,请确保添加一次处理程序! You can access a logger's list of handlers using: logger.handlers . 您可以使用logger.handlers访问记录器的处理程序列表。


Also, if you're using the same logger in both classes (named "TDOA" ) by using this line in both: 另外, 如果您在两个类中都使用同一记录器(名为"TDOA" ), 在两个类中都使用此行:

self.logger=logging.getLogger('TDOA')

Make sure you either synchronize the logger instantiation, or use separate loggers. 确保同步记录器实例化,或使用单独的记录器。


What I use: 我用什么:

Instead of having a private logger for each instance, you probably want a logger for all of them, or to be more precise - for the class itself: 您可能希望为所有实例创建一个记录器,或者更确切地说-为类本身创建一个记录器,而不是为每个实例都提供一个私有记录器:

class ClassWithLogger(object):
    logger = None
    def __init__(self):
        if not ClassWithLogger.logger:
            ClassWithLogger.logger = logging.getLogger("ClassWithLogger")
            ClassWithLogger.logger.addHandler(logging.StreamHandler())
        # log using ClassWithLogger.logger ...
        # convenience:
        self.logger = ClassWithLogger.logger

And now you know logger is instantiated once per class (instead of once per instance), and all instances of a certain class use the same logger. 现在,您知道logger 每个类实例化一次 (而不是每个实例一次),并且某个类的所有实例都使用同一记录器。

I have since found a few links suggesting that submodules should take a logger as an input during the init : 此后,我发现了一些链接,这些链接建议子模块在初始化期间应将记录器作为输入:

def __init__ (self, pattern= None, action=None, logger = None):
    # Set up logging for the class
    self.log = logger or logging.getLogger(__name__)
    self.log.addHandler(logging.NullHandler())

Note: the nullhandler is added to avoid a warning if the user decides to not provide a logger. 注意:添加了nullhandler以避免在用户决定不提供记录器时发出警告。

Then, if you want to debug your submodule: 然后,如果要调试子模块:

if __name__ == "__main__":
    log_level = logging.INFO
    log = logging.getLogger('cmdparser')
    log.setLevel(log_level)
    fh = logging.FileHandler('cmdparser.log')
    fh.setLevel(log_level)
    # create console handler with a higher log level
    ch = logging.StreamHandler()
    ch.setLevel(log_level)
    # create formatter and add it to the handlers
    # formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    ch.setFormatter(formatter)
    # add the handlers to the logger
    log.addHandler(fh)
    log.addHandler(ch)
    <myfunction>(pattern,action, log)

Then provide the log to the module at instantiation. 然后在实例化时将日志提供给模块。

I hope this helps. 我希望这有帮助。

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

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