任务
我有一组脚本,希望它们能产生统一的日志消息,同时最小限度地更改执行实际日志消息记录的模块。
我编写了一个名为“custom_logger”的小模块,计划从主应用程序中调用它一次,让它返回一个记录器,然后我将继续使用它。
我将导入到应用程序中的子模块应该只(或者说我希望它们只):
- 只需“import logging as log” - 这样就不需要特定于我的站点的内容才能使它们运行,如果其他人发现它们有用的话。 - 只需使用log.info/error('message')记录消息,而不添加任何特定于站点的内容。 - 应使用已经配置好的“root”记录器及其所有格式和处理程序,并且不影响根记录器的配置。
*custom_logger.py*
我希望能在app.py中定义一个日志记录器,并且在子模块中只使用标准的Python logging库,以利用在app.py中已经配置好的日志记录器。
此外,还有一个丑陋的解决方法:如果我将以下代码放在submodule.py的导入之后:
我有一组脚本,希望它们能产生统一的日志消息,同时最小限度地更改执行实际日志消息记录的模块。
我编写了一个名为“custom_logger”的小模块,计划从主应用程序中调用它一次,让它返回一个记录器,然后我将继续使用它。
我将导入到应用程序中的子模块应该只(或者说我希望它们只):
- 只需“import logging as log” - 这样就不需要特定于我的站点的内容才能使它们运行,如果其他人发现它们有用的话。 - 只需使用log.info/error('message')记录消息,而不添加任何特定于站点的内容。 - 应使用已经配置好的“root”记录器及其所有格式和处理程序,并且不影响根记录器的配置。
*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 logging库,以利用在app.py中已经配置好的日志记录器。
此外,还有一个丑陋的解决方法:如果我将以下代码放在submodule.py的导入之后:
log = custom_logger.getLogger('root')
这将在app.py中配置我的日志记录器之前执行,有效地使子模块而不是我的应用程序配置日志记录。
我考虑的另一个解决方法:在SubClass类的构造函数中,我可以定义
self.log = custom_logger.getLogger('root')
然后使用self.log.error('some error')。应该有一个更好的方法-如果您能提供有用的建议或指出我误解文档的地方,我会非常感激!
附言:我花了很多时间阅读Python日志记录howto(基本和高级)和cookbook,所以如果我错过了一些有用的东西,请指出来。
谢谢!