任务
我有一个脚本集合,我希望它们能够生成统一的日志消息,并且对记录实际消息的模块进行最少的更改。
我写了一个小模块'custom_logger',我打算从主应用程序调用一次,让它返回一个记录器,然后我继续使用。
我要导入应用程序的子模块应该只是(或者我希望它们)
* custom_logger.py *
import logging
import logging.handlers
import os
import sys
def getLogger(name='root', loglevel='INFO'):
logger = logging.getLogger(name)
# if logger 'name' already exists, return it to avoid logging duplicate
# messages by attaching multiple handlers of the same type
if logger.handlers:
return logger
# if logger 'name' does not already exist, create it and attach handlers
else:
# set logLevel to loglevel or to INFO if requested level is incorrect
loglevel = getattr(logging, loglevel.upper(), logging.INFO)
logger.setLevel(loglevel)
fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
fmt_date = '%Y-%m-%dT%T%Z'
formatter = logging.Formatter(fmt, fmt_date)
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logger.addHandler(handler)
if logger.name == 'root':
logger.warning('Running: %s %s',
os.path.basename(sys.argv[0]),
' '.join(sys.argv[1:]))
return logger
然后是子模块,其中包含一些测试消息,其中包含哪些有效,哪些无效。
submodule.py
import sys
import custom_logger
import logging
class SubClass(object):
def __init__(self):
# NOK (no idea why since by default (no name parameter), it should return the root logger)
#log = logging.getLogger()
#log.info('message from SubClass / __init__')
# OK (works as expected)
#log = logging.getLogger('root')
#log.info('message from SubClass / __init__')
# OK (works as expected)
log = custom_logger.getLogger('root')
log.info('message from SubClass / __init__')
def SomeMethod(self):
# OK but I'd have to define `log` for every method, which is unacceptable
# Please see question below all code snippets
log = custom_logger.getLogger('root')
log.info('message from SubClass / SomeMethod')
主应用程序: app.py 这里没什么特别的:
#!/usr/bin/python
import custom_logger
import submodule
log = custom_logger.getLogger('root', loglevel='DEBUG')
log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')
a = submodule.SubClass() # this should produce a log message
a.SomeMethod() # so should this
我正在追求并且我正在以极其丑陋的方式获得的输出:
% ./app.py
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py
2013-04-08T03:07:46BST app.py DEBUG : debug message
2013-04-08T03:07:46BST app.py INFO : info message
2013-04-08T03:07:46BST app.py WARNING : warning message
2013-04-08T03:07:46BST app.py ERROR : error message
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass / __init__
2013-04-08T03:07:46BST submodule.py INFO : message from SubClass / SomeMethod
我希望能够在app.py中定义一个记录器,然后在子模块中只使用标准的Python记录库来使用app.py中已配置的记录器。
另外,一个丑陋的解决方法:如果我在submodule.py中导入后放置以下代码:
log = custom_logger.getLogger('root')
它将在app.py中配置我的记录器之前执行,有效地制作子模块,而不是我的应用程序配置记录。
我考虑过的另一种解决方法:在SubClass类的构造函数中,我可以定义
self.log = custom_logger.getLogger('root')
然后使用self.log.error('some error')。必须有一个更好的方法 - 如果你能提出一些有用的东西或指出我误解了文档的地方,我将非常感激!
PS。我花了很多时间阅读Python日志指南(基础和高级)和食谱,所以如果我错过了那些有用的东西,请指出。
谢谢!
答案 0 :(得分:6)
如果你想更改root logger,你可以在任何地方使用getLogger()
,没有参数。
关于仅在主模块中的实例设置,您可以实例化您的记录器,添加您自己的处理程序,并在所有其他子模块中使用它(如我所做的那样)。
我创建了一个继承custom_logger.py
中的StreamHandler的类:
class MyHandler(logging.StreamHandler):
def __init__(self):
logging.StreamHandler.__init__(self)
fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s'
fmt_date = '%Y-%m-%dT%T%Z'
formatter = logging.Formatter(fmt, fmt_date)
self.setFormatter(formatter)
然后,在submodule.py
中,我将getLogger放在导入之后,并在方法中对其进行了评论:
import sys
import logging
log = logging.getLogger('root')
class SubClass(object):
def __init__(self):
log.info('message from SubClass / __init__')
def SomeMethod(self):
log.info('message from SubClass / SomeMethod')
然后,在app.py中我创建了一个Logger实例(在所有模块中都是相同的)并添加了我的处理程序,它将输出格式化:
#!/usr/bin/python
import logging
import custom_logger
import submodule
log = logging.getLogger('root')
log.setLevel('DEBUG')
log.addHandler(custom_logger.MyHandler())
log.debug('debug message')
log.info('info message')
log.warning('warning message')
log.error('error message')
a = submodule.SubClass() # this should produce a log message
a.SomeMethod() # so should this
输出:
./app.py
2013-04-08T15:20:05EEST app.py DEBUG : debug message
2013-04-08T15:20:05EEST app.py INFO : info message
2013-04-08T15:20:05EEST app.py WARNING : warning message
2013-04-08T15:20:05EEST app.py ERROR : error message
2013-04-08T15:20:05EEST submodule.py INFO : message from SubClass / __init__
2013-04-08T15:20:05EEST submodule.py INFO : message from SubClass / SomeMethod