Подтвердить что ты не робот

Отключить ведение журнала на метод/функцию?

Я новичок в регистрации на Python, и я могу легко понять, как это предпочтительнее для домашнего решения brew, которое я придумал.

Один вопрос, на который я не могу найти ответ: как я могу подавить сообщения журнала на основе каждого метода/функции?

Мой гипотетический модуль содержит одну функцию. По мере того, как я разрабатываю, звонки в журнале очень помогают:

logging.basicConfig(level=logging.DEBUG,
                format=('%(levelname)s: %(funcName)s(): %(message)s'))
log = logging.getLogger()

my_func1():
    stuff...
    log.debug("Here 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

4b9b3361

Ответ 1

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

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

Во-первых. Не используйте 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 )

Ответ 2

Вы можете создать декоратор, который временно приостановит ведение журнала, 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, поэтому будьте осторожны, как вы ее используете.

Ответ 3

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

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(...):

Ответ 4

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

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

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


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

Во-первых, основная программа:

# 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 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 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 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 logging level to DEBUG.  We don't necessarily
    # have a reference to the library 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 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 logging level to DEBUG output")
    print("# all debug messages from the library.  (Use logging_tree.printout()")
    print("# To see why.)")
    print("# Let change the library logging level to INFO and")
    print("# only some_special_func() 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 main logger, we don't need
    # to create another handler, it will use the handler that belongs
    # to the library 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 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 logging level to DEBUG output
# all debug messages from the library.  (Use logging_tree.printout()
# To see why.)
# Let change the library logging level to INFO and
# only some_special_func() 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(), чтобы выяснить, какие уровни ведения журнала настраиваются, чтобы это произошло!