我有一个简单的Python脚本,它使用内置的logging
。
我正在配置函数内的日志记录。基本结构将是这样的:
#!/usr/bin/env python
import logging
import ...
def configure_logging():
logger = logging.getLogger("my logger")
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
return logger
def count_parrots():
...
logger.debug??
if __name__ == '__main__':
logger = configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()
我可以从__main__
内部调用logger。但是,如何从count_parrots()函数内部调用logger?处理这样的记录器的最pythonic方法是什么?
答案 0 :(得分:39)
您可以使用root(默认)记录器,因此模块级别函数logging.debug
,...或使用它来获取函数中的记录器。
实际上,getLogger
函数是一个类似工厂的函数,带有一个注册表(类似单例),即它总是返回给定记录器名称的相同实例。
因此,您只需使用
logger = logging.getLogger("my logger")
一开始。但是,惯例是为记录器使用点分层名称。见http://docs.python.org/library/logging.html#logging.getLogger
编辑:
您可以使用装饰器将记录行为添加到各个功能中,例如:
def debug(loggername):
logger = logging.getLogger(loggername)
def log_(enter_message, exit_message=None):
def wrapper(f):
def wrapped(*args, **kargs):
logger.debug(enter_message)
r = f(*args, **kargs)
if exit_message:
logger.debug(exit_message)
return r
return wrapped
return wrapper
return log_
my_debug = debug('my.logger')
@my_debug('enter foo', 'exit foo')
def foo(a, b):
return a+b
您可以“硬编码”记录器名称并删除顶级闭包和my_debug。
答案 1 :(得分:15)
你可以这样做:
logger = logging.getLogger("my logger")
在您的count_parrots()
方法中。当您传递先前使用的名称(即“我的记录器”)时,日志记录模块将返回与该名称对应的相同实例。
更新:来自logging tutorial (emphais mine)
getLogger()返回对a的引用 具有指定的logger实例 提供名称,如果提供,则为root 不。名称以句点分隔 等级结构。 多个 使用相同的方法调用getLogger() name将返回对引用的引用 相同的记录器对象。
答案 2 :(得分:8)
处理日志记录的典型方法是将每个模块的记录器存储在全局变量中。然后,该模块中的任何函数和方法只引用相同的记录器实例。
在文档中的高级日志记录教程的简介中对此进行了简要讨论: http://docs.python.org/howto/logging.html#advanced-logging-tutorial
你可以传递记录器实例作为参数,但这样做通常很少见。
答案 3 :(得分:0)
我对全局变量如何在Python中工作感到困惑。在函数中,如果您正在执行global logger
之类的操作并希望修改全局logger = logging.getLogger("my logger")
,则只需声明logger
。
因此,要修改示例,可以在文件的开头创建一个全局记录器对象。如果您的模块可以被另一个模块导入,则应添加NullHandler
,这样如果库的导入程序不希望启用日志记录,则它们对您的lib没有任何问题(ref )。
#!/usr/bin/env python
import logging
import ...
logger = logging.getLogger("my logger").addHandler(logging.NullHandler())
def configure_logging():
logger.setLevel(logging.DEBUG)
# Format for our loglines
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
# Setup console logging
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
ch.setFormatter(formatter)
logger.addHandler(ch)
# Setup file logging as well
fh = logging.FileHandler(LOG_FILENAME)
fh.setLevel(logging.DEBUG)
fh.setFormatter(formatter)
logger.addHandler(fh)
def count_parrots():
...
logger.debug('counting parrots')
...
return parrots
if __name__ == '__main__':
configure_logging()
logger.debug("I'm a log file")
parrots = count_parrots()
答案 4 :(得分:0)
如果您不需要控制台上的日志消息,则可以以极简主义的方式使用。
或者,您可以使用tail -f myapp.log
查看控制台上的消息。
import logging
logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', \
filename='myapp.log', \
level=logging.INFO)
def do_something():
logging.info('Doing something')
def main():
logging.info('Started')
do_something()
logging.info('Finished')
if __name__ == '__main__':
main()
答案 5 :(得分:-4)
您可以将logger
作为参数提供给count_parrots()
或者,我会做什么,创建类鹦鹉并使用记录器作为其方法之一。