Python记录由不同脚本共享的模块

Fin*_*ode 4 python logging

我喜欢python日志记录基础设施,我想将它用于我运行的许多不同的夜间工作.很多这些工作使用模块X让我们说.我希望模块X的日志记录写入不依赖于模块X的日志文件,但是基于最终导致模块X中的调用功能的作业.

因此,如果在模块X中,Later_script_1.py调用foo(),我希望foo()的日志转到overnight_script_1.log.我还希望通过使用once_script_2.py调用foo()来登录later_script_2.log.

这个问题的一个潜在解决方案是基于查看sys.argv的第0个参数来设置日志文件,该参数可以映射到我的首选文件.以这种方式做事似乎很蠢.这样做有一个首选的设计模式吗?我不想根据调用函数的模块搜索不同的日志文件,以查找我的一个脚本的诊断信息.这是一些代码,因为我不确定我是否清楚自己.

这是script1.py

import X
import logging_utils as lu
import sys

logname=sys.argv[0][:-3] # logname==script1 with the .py cut off
logger=lu.setup_logger(log_name) # assume this does the formatting and sets the filehandlers
# furthermore assume the file handler is set so that the output goes to script1.log.

# do a bunch of thing
logger.info('I am doing a bunch of things in script1 and I will now call X.foo()')
X.foo() # see module X below
logger.info('I finished X.foo()')
Run Code Online (Sandbox Code Playgroud)

同样,这是script2.py

import X
import logging_utils as lu
import sys

logname=sys.argv[0][:-3] # logname==script2 with the .py cut off
logger=lu.setup_logger(log_name) # assume this does the formatting and sets the filehandlers
# furthermore assume the file handler is set so that the output goes to script2.log.

# do a bunch of thing
logger.info('I am doing a bunch of things in script2 and I will now call X.foo()')
X.foo() # see module X below
logger.info('I finished X.foo()')
Run Code Online (Sandbox Code Playgroud)

这是X.py

import logging
import sys
logname=sys.argv[0][:-3] # could be script1 or script2
logger=logging.getLogger(logname)

def foo():
    try:
        i=1/0
    except:
        logger.error('oops - division by zero')
Run Code Online (Sandbox Code Playgroud)

然后我想跑:

python script1.py

python script2.py

并获取两个日志文件script1.log和script2.log,其中每个都记录模块X中发生的除零错误.

Bak*_*riu 7

我相信你应该遵循库代码的标准设置:

假设您有一个软件包,mypkg并且您希望此软件包记录信息,同时让软件包的用户决定使用哪种级别的日志记录以及输出应该去哪里.

mypkg没有设置的级别,也不适用于任何日志处理.模块xmypkg应该是这样的:

import logging

logger = logging.getLogger(__name__)


def my_function():
    logger.info('something')
Run Code Online (Sandbox Code Playgroud)

没有任何配置的日志记录getLogger(__name__).

那么你script.py使用mypkg并希望INFO在控制台上登录级别会:

import logging
import mypkg

root_logger = logging.getLogger()
console_handler = logging.StreamHandler()

root_logger.setLevel(logging.INFO)
root_logger.addHandler(console_handler)

mypkg.my_function()  # produces output to stderr
Run Code Online (Sandbox Code Playgroud)

虽然script2.py会在级别登录DEBUG到文件:

import logging
import mypkg


root_logger = logging.getLogger()
file_handler = logging.FileHandler('some_file.log')

root_logger.setLevel(logging.DEBUG)
root_logger.addHandler(file_handler)

mypkg.my_function()
Run Code Online (Sandbox Code Playgroud)

请注意,通过在根记录器上设置级别和处理程序,我们将级别设置为"全局".如果用户有一些他想要与级别一起使用的记录器,DEBUG但他想使用级别INFO,mypkg他可以这样做:

root_logger = logging.getLogger()
root_logger.setLevel(logging.DEBUG)

mypkg_logger = logging.getLogger('mypkg')
mypkg_logger.setLevel(logging.INFO)

handler = #... whatever you want
root_logger.addHandler(handler)
Run Code Online (Sandbox Code Playgroud)

如果mypkg包含模块x.py, y.py,a.py,b.pyc.py你想记录里面的功能x,在DEBUG和里面那些yWARNING和那些a/b/c.pyINFO你可以通过设置相应的日志记录器级别这样做:

mypkg_logger = logging.getLogger('mypkg')
my_pkg_logger.setLevel(logging.INFO)

x_logger = logging.getLogger('mypkg.x')
x_logger.setLevel(logging.DEBUG)
y_logger = logging.getLogger('mypkg.y')
y_logger.setLevel(logging.WARNING)
Run Code Online (Sandbox Code Playgroud)

把处理程序只附加到root_logger,一切都应该工作正常.


注意:在某些版本的python上,logging模块可能会警告您定义了一个没有库模块处理程序的记录器.要解决这个问题,你可以使用NullHandler只删除日志消息:

# x.py

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())
Run Code Online (Sandbox Code Playgroud)

所以NullHandler除了防止logging模块抱怨之外,什么都不做.AFAIK的新版本根本不需要这个.

  • @FinanceGuyThatCantCode它有点复杂.记录器根据其名称形成层次结构,因此名为"mypkg.x"的记录器是记录器"mypkg"的"子".使用`getLogger(__ name __)`只是一种简单的方法来调用你的记录器`mypkg`,然后是`mypkg.x`,然后是`mypkg.y`然后是`mypkg.subpkg.x`等.根记录器是祖父母所有记录器.当您在记录器上调用`.info`或`.debug`时,记录器会检查它是否与其级别匹配,如果是,则尝试记录.如果找不到处理程序,它会将该项发送到父记录器等直到根记录器. (2认同)
  • @FinanceGuyThatCantCode您应该阅读:[Logging HOWTO](https://docs.python.org/3.5/howto/logging.html),[Logging Cookbook](https://docs.python.org/3.5/howto/ logging-cookbook.html),[高级日志教程](https://docs.python.org/3.5/howto/logging.html#logging-advanced-tutorial). (2认同)