禁用每个方法/功能的记录?

时间:2011-09-07 22:05:35

标签: python logging

我是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

5 个答案:

答案 0 :(得分:10)

诀窍是创建多个记录器。

这有几个方面。

首先。不要在模块的开头使用logging.basicConfig()。在主导入开关

中使用 only
 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')