开发者

Weird stuff happening while importing modules

开发者 https://www.devze.com 2023-04-07 16:35 出处:网络
I hate to give the question this heading but I actually don\'t know whats happening so here it goes. I was doing another project in which I wanted to use logging module. The code is distributed among

I hate to give the question this heading but I actually don't know whats happening so here it goes.

I was doing another project in which I wanted to use logging module. The code is distributed among few files & instead of creating separate logger objects for seperate files, I thought of creating a logs.py with contents

import sys, logging

class Logger:
    def __init__(self):
        formatter = logging.Formatter('%(filename)s:%(lineno)s %(levelname)s:%(message)s')
        stdout_handler = logging.StreamHandler(sys.stdout)
        stdout_handler.setFormatter(formatter)
        self.logger=logging.getLogger('')
        self.logger.addHandler(stdout_handler)
        self.logger.setLevel(logging.DEBUG)

    def debug(self, message):
        self.logger.debug(message)

and use this class like (in different files.)

import logs
b = logs.Logger()
b.debug("Hi from a.py")
  1. I stripped down the whole problem to ask the question here. Now, I have 3 files, a.py, b.py & main.开发者_开发百科py. All 3 files instantiate the logs.Logger class and prints a debug message.
  2. a.py & b.py imports "logs" and prints their debug message.
  3. main.py imports logs, a & b; and prints it own debug message.

The file contents are like this: http://i.imgur.com/XoKVf.png

Why is debug message from b.py printed 2 times & from main.py 3 times?


Specify a name for the logger, otherwise you always use root logger.

import sys, logging

class Logger:
    def __init__(self, name):
        formatter = logging.Formatter('%(filename)s:%(lineno)s %(levelname)s:%(message)s')
        stdout_handler = logging.StreamHandler(sys.stdout)
        stdout_handler.setFormatter(formatter)
        self.logger=logging.getLogger(name)
        self.logger.addHandler(stdout_handler)
        self.logger.setLevel(logging.DEBUG)

    def debug(self, message):
        self.logger.debug(message)

http://docs.python.org/howto/logging.html#advanced-logging-tutorial :

A good convention to use when naming loggers is to use a module-level logger, in each module which uses logging, named as follows:

logger = logging.getLogger(__name__)


logging.getLogger('') will return exactly the same object each time you call it. So each time you instantiate a Logger (why use old-style classes here?) you are attaching one more handler resulting in printing to one more target. As all your targets pointing to the same thing, the last call to .debug() will print to each of the three StreamHandler objects pointing to sys.stdout resulting in three lines being printed.


First. Don't create your own class of Logger.

Just configure the existing logger classes with exising logging configuration tools.

Second. Each time you create your own class of Logger you also create new handlers and then attach the new (duplicating) handler to the root logger. This leads to duplication of messages.

If you have several modules that must (1) run stand-alone and (2) also run as part of a larger, composite, application, you need to do this. This will assure that logging configuration is done only once.

import logging
logger= logging.getLogger( __file__ ) # Unique logger for a, b or main


if __name__ == "__main__":
    logging.basicConfig( stream=sys.stdout, level=logging.DEBUG, format='%(filename)s:%(lineno)s %(levelname)s:%(message)s' )
    # From this point forward, you can use the `logger` object.
    logger.info( "Hi" )
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号