我是Python日志的新手,我可以很容易地看到它对我提出的家庭酿造解决方案的优越性。
我似乎无法找到答案的一个问题:如何根据每个方法/函数压制记录消息?
我的假设模块包含单个功能。在我开发时,日志调用是一个很好的帮助:
logging.basicConfig(level=logging.DEBUG,
format=('%(levelname)s: %(funcName)s(): %(message)s'))
log = logging.getLogger()
my_func1():
stuff...
log.debug("Here's an interesting value: %r" % some_value)
log.info("Going great here!")
more stuff...
当我在'my_func1'上完成工作并开始处理第二个函数'my_func2'时,来自'my_func1'的日志消息开始从“有用”变为“混乱”。
是否存在单行魔术语句,例如'logging.disabled_in_this_func()',我可以将其添加到'my_func1'的顶部以禁用'my_func1'中的所有日志记录调用,但仍保留所有其他日志调用功能/方法不变?
由于
linux,Python 2.7.1
答案 0 :(得分:10)
诀窍是创建多个记录器。
这有几个方面。
首先。不要在模块的开头使用logging.basicConfig()
。在主导入开关
if __name__ == "__main__":
logging.basicConfig(...)
main()
logging.shutdown()
二。除了设置全局首选项外,永远不要获得“root”记录器。
第三。为可能启用或禁用的内容获取单独的命名记录器。
log = logging.getLogger(__name__)
func1_log = logging.getLogger( "{0}.{1}".format( __name__, "my_func1" )
现在,您可以在每个指定的记录器上设置日志记录级别。
log.setLevel( logging.INFO )
func1_log.setLevel( logging.ERROR )
答案 1 :(得分:6)
您可以创建一个临时暂停日志记录的装饰器,ala:
from functools import wraps
def suspendlogging(func):
@wraps(func)
def inner(*args, **kwargs):
previousloglevel = log.getEffectiveLevel()
try:
return func(*args, **kwargs)
finally:
log.setLevel(previousloglevel)
return inner
@suspendlogging
def my_func1(): ...
警告:这也会暂停从my_func1调用的任何函数的日志记录,所以要小心你如何使用它。
答案 2 :(得分:2)
你可以使用装饰者:
import logging
import functools
def disable_logging(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
logging.disable(logging.DEBUG)
result = func(*args,**kwargs)
logging.disable(logging.NOTSET)
return result
return wrapper
@disable_logging
def my_func1(...):
答案 3 :(得分:1)
我花了一些时间来学习如何实现S.Lott建议的子记录器。
考虑到在我开始时弄清楚如何设置日志记录是多么艰难,我认为从那以后我很久就分享了我所学到的知识。
请记住,这不是设置记录器/子记录器的唯一方法,也不是最好的方法。这就是我用来完成工作以满足我的需求的方式。我希望这对某人有帮助。请随时评论/分享/批评。
假设我们有一个我们喜欢使用的简单库。从主程序中,我们希望能够控制从库中获取的日志消息。当然,我们是体贴的图书馆创作者,因此我们配置我们的图书馆以使其变得简单。
首先,主程序:
# some_prog.py
import os
import sys
# Be sure to give Vinay Sajip thanks for his creation of the logging module
# and tireless efforts to answer our dumb questions about it. Thanks Vinay!
import logging
# This module will make understanding how Python logging works so much easier.
# Also great for debugging why your logging setup isn't working.
# Be sure to give it's creator Brandon Rhodes some love. Thanks Brandon!
import logging_tree
# Example library
import some_lib
# Directory, name of current module
current_path, modulename = os.path.split(os.path.abspath(__file__))
modulename = modulename.split('.')[0] # Drop the '.py'
# Set up a module-local logger
# In this case, the logger will be named 'some_prog'
log = logging.getLogger(modulename)
# Add a Handler. The Handler tells the logger *where* to send the logging
# messages. We'll set up a simple handler that send the log messages
# to standard output (stdout)
stdout_handler = logging.StreamHandler(stream=sys.stdout)
log.addHandler(stdout_handler)
def some_local_func():
log.info("Info: some_local_func()")
log.debug("Debug: some_local_func()")
if __name__ == "__main__":
# Our main program, here's where we tie together/enable the logging infra
# we've added everywhere else.
# Use logging_tree.printout() to see what the default log levels
# are on our loggers. Make logging_tree.printout() calls at any place in
# the code to see how the loggers are configured at any time.
#
# logging_tree.printout()
print("# Logging level set to default (i.e. 'WARNING').")
some_local_func()
some_lib.some_lib_func()
some_lib.some_special_func()
# We know a reference to our local logger, so we can set/change its logging
# level directly. Let's set it to INFO:
log.setLevel(logging.INFO)
print("# Local logging set to 'INFO'.")
some_local_func()
some_lib.some_lib_func()
some_lib.some_special_func()
# Next, set the local logging level to DEBUG:
log.setLevel(logging.DEBUG)
print("# Local logging set to 'DEBUG'.")
some_local_func()
some_lib.some_lib_func()
some_lib.some_special_func()
# Set the library's logging level to DEBUG. We don't necessarily
# have a reference to the library's logger, but we can use
# logging_tree.printout() to see the name and then call logging.getLogger()
# to create a local reference. Alternately, we could dig through the
# library code.
lib_logger_ref = logging.getLogger("some_lib")
lib_logger_ref.setLevel(logging.DEBUG)
# The library logger's default handler, NullHandler() won't output anything.
# We'll need to add a handler so we can see the output -- in this case we'll
# also send it to stdout.
lib_log_handler = logging.StreamHandler(stream=sys.stdout)
lib_logger_ref.addHandler(lib_log_handler)
lib_logger_ref.setLevel(logging.DEBUG)
print("# Logging level set to DEBUG in both local program and library.")
some_local_func()
some_lib.some_lib_func()
some_lib.some_special_func()
print("# ACK! Setting the library's logging level to DEBUG output")
print("# all debug messages from the library. (Use logging_tree.printout()")
print("# To see why.)")
print("# Let's change the library's logging level to INFO and")
print("# only some_special_func()'s level to DEBUG so we only see")
print("# debug message from some_special_func()")
# Raise the logging level of the libary and lower the logging level
# of 'some_special_func()' so we see only some_special_func()'s
# debugging-level messages.
# Since it is a sub-logger of the library's main logger, we don't need
# to create another handler, it will use the handler that belongs
# to the library's main logger.
lib_logger_ref.setLevel(logging.INFO)
special_func_sub_logger_ref = logging.getLogger('some_lib.some_special_func')
special_func_sub_logger_ref.setLevel(logging.DEBUG)
print("# Logging level set to DEBUG in local program, INFO in library and")
print("# DEBUG in some_lib.some_special_func()")
some_local_func()
some_lib.some_lib_func()
some_lib.some_special_func()
接下来,我们的图书馆:
# some_lib.py
import os
import logging
# Directory, name of current module
current_path, modulename = os.path.split(os.path.abspath(__file__))
modulename = modulename.split('.')[0] # Drop the '.py'
# Set up a module-local logger. In this case the logger will be
# named 'some_lib'
log = logging.getLogger(modulename)
# In libraries, always default to NullHandler so you don't get
# "No handler for X" messages.
# Let your library callers set up handlers and set logging levels
# in their main program so the main program can decide what level
# of messages they want to see from your library.
log.addHandler(logging.NullHandler())
def some_lib_func():
log.info("Info: some_lib.some_lib_func()")
log.debug("Debug: some_lib.some_lib_func()")
def some_special_func():
"""
This func is special (not really). It just has a function/method-local
logger in addition to the library/module-level logger.
This allows us to create/control logging messages down to the
function/method level.
"""
# Our function/method-local logger
func_log = logging.getLogger('%s.some_special_func' % modulename)
# Using the module-level logger
log.info("Info: some_special_func()")
# Using the function/method-level logger, which can be controlled separately
# from both the library-level logger and the main program's logger.
func_log.debug("Debug: some_special_func(): This message can be controlled at the function/method level.")
现在让我们运行该程序,以及评论轨道:
# Logging level set to default (i.e. 'WARNING').
请注意,默认级别没有输出,因为我们没有生成任何WARNING级别的消息。
# Local logging set to 'INFO'.
Info: some_local_func()
库的处理程序默认为NullHandler()
,因此我们只看到主程序的输出。这很好。
# Local logging set to 'DEBUG'.
Info: some_local_func()
Debug: some_local_func()
主程序记录器设置为DEBUG。我们仍然看不到图书馆的输出。这很好。
# Logging level set to DEBUG in both local program and library.
Info: some_local_func()
Debug: some_local_func()
Info: some_lib.some_lib_func()
Debug: some_lib.some_lib_func()
Info: some_special_func()
Debug: some_special_func(): This message can be controlled at the function/method level.
糟糕。
# ACK! Setting the library's logging level to DEBUG output
# all debug messages from the library. (Use logging_tree.printout()
# To see why.)
# Let's change the library's logging level to INFO and
# only some_special_func()'s level to DEBUG so we only see
# debug message from some_special_func()
# Logging level set to DEBUG in local program, INFO in library and
# DEBUG in some_lib.some_special_func()
Info: some_local_func()
Debug: some_local_func()
Info: some_lib.some_lib_func()
Info: some_special_func()
Debug: some_special_func(): This message can be controlled at the function/method level.
还可以从some_special_func()
获取仅调试消息 。使用logging_tree.printout()
确定要调整哪些日志记录级别以实现此目的!
答案 4 :(得分:0)
如果您正在使用日志沉默日志,则非常简单。只需使用NullHandler
-https://logbook.readthedocs.io/en/stable/api/handlers.html
>>> logger.warn('TEST')
[12:28:17.298198] WARNING: TEST
>>> from logbook import NullHandler
>>> with NullHandler():
... logger.warn('TEST')