Отключить ведение журнала для метода / функции? - PullRequest
13 голосов
/ 08 сентября 2011

Я новичок в журналировании 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

Ответы [ 4 ]

12 голосов
/ 08 сентября 2011

Хитрость заключается в создании нескольких регистраторов.

Есть несколько аспектов этого.

Во-первых. Не используйте logging.basicConfig() в начале модуля. Используйте его только внутри переключателя основного импорта

 if __name__ == "__main__":
     logging.basicConfig(...)
     main()
     logging.shutdown()

Во-вторых. Никогда не получайте «корневой» логгер, кроме как для установки глобальных настроек.

В-третьих. Получить отдельные с именем регистраторы для вещей, которые могут быть включены или отключены.

log = logging.getLogger(__name__)

func1_log = logging.getLogger( "{0}.{1}".format( __name__, "my_func1" )

Теперь вы можете устанавливать уровни ведения журнала для каждого именованного регистратора.

log.setLevel( logging.INFO )
func1_log.setLevel( logging.ERROR )
6 голосов
/ 08 сентября 2011

Вы можете создать декоратор, который временно приостановит ведение журнала, ала:

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 голосов
/ 08 сентября 2011

Вы можете использовать декоратор:

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(...):
1 голос
/ 24 февраля 2016

Мне потребовалось некоторое время, чтобы научиться внедрять суб-логгеры, как было предложено С.Лоттом.

Учитывая, как трудно было понять, как настроить ведение журнала, когда я только начинал, я думаю, что давно пора поделиться тем, что я узнал с тех пор.

Имейте в виду, что это не единственный способ настройки логгеров / суб-логгеров, и при этом он не лучший.Это просто способ, которым я использую работу, чтобы соответствовать моим потребностям.Надеюсь, это кому-нибудь пригодится.Пожалуйста, не стесняйтесь комментировать / делиться / критиковать.


Предположим, у нас есть простая библиотека, которую мы хотели бы использовать.Из основной программы мы хотели бы иметь возможность контролировать сообщения регистрации, которые мы получаем из библиотеки.Конечно, мы внимательны к создателям библиотек, поэтому мы настраиваем нашу библиотеку, чтобы упростить это.

Сначала основная программа:

# 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(), чтобы выяснить, какие уровни ведения журнала нужно настроить, чтобы это произошло!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...