Django logging - настраиваемый фильтр работает для обработчика, но не работает для регистратора - PullRequest
0 голосов
/ 26 мая 2020

У меня есть собственный фильтр:

proj / proj / log_utils / filters.py:

import logging

class OnlyThisSeverity(logging.Filter):
     def filter(self, record):
         print('levelname: {}'.format(record.levelname))
         return record.levelno == logging.INFO

И Django настройки выглядят так:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',

        },        
    },
    'filters': {
        'only_this_severity': {
            '()': 'android_blend.log_utils.filters.OnlyThisSeverity',
        }
    },

    'loggers': {
        'my_app': {
            'handlers': ('console',),  # 'console'
            'level': 'INFO',
            'propagate': False,
            'filters': ['only_this_severity']
        },

    }
}

Внутри my_app/test.py у меня есть такая функция:

import logging
logger = logging.getLogger(__name__)

def handle(self, *args, **kwargs):
   logger.info('Reporting info......')
   logger.error('Reporting error......')

Если мой фильтр работает правильно, я должен видеть только Reporting info в консоли, тогда как я вижу обе строки. Проблема в том, что фильтр only_this_severity игнорируется. Однако, если я переместу filters внутрь определения обработчика console, я достигну своей цели. Что я делаю не так? Я хочу, чтобы фильтр работал для логгера my_app, а не только на уровне обработчика. Моя конечная цель - изменить настраиваемое поведение библиотеки журналов. То есть для обработчиков уровня «X» я хочу, чтобы они уважали только записи уровня «X», а не «X и выше».

1 Ответ

0 голосов
/ 27 мая 2020

Кажется, ваш фильтр работает правильно даже с фильтром, добавленным на уровне регистратора.

Это мой текущий результат:

levelname: INFO
Reporting info......
levelname: ERROR

Это показывает, как код достигает фильтра в обеих операциях журнала, но фильтрует запись об ошибке.

Я думаю что проблема может быть в иерархии регистраторов. Когда вы используете свой test.py в качестве импортированного модуля, вы получаете не регистратор 'my_app', а 'my_app.test', которого не существует.

Когда это происходит, ядро ​​извлекает регистратор root и «передает» конфигурацию по умолчанию новому регистратору с именем 'my_app.test', включая его в иерархию журналов. В этом регистраторе не задействован ваш фильтр.

Попробуйте принудительно получить регистратор 'my_app', передав его имя:

import logging
logger = logging.getLogger('my_app')

def handle(self, *args, **kwargs):
   logger.info('Reporting info......')
   logger.error('Reporting error......')

Или вы можете использовать регистратор root для определения вашего фильтров, а затем позвольте приложению создать для вас иерархию:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',

        },        
    },
    'filters': {
        'only_this_severity': {
            '()': 'android_blend.log_utils.filters.OnlyThisSeverity',
        }
    },

    'loggers': {
        'root': {
            'handlers': ('console',),  # 'console'
            'level': 'INFO',
            'filters': ['only_this_severity']
        },

    }
}

Мне лично нравится этот метод, потому что он позволяет безопасно вызывать

logger = logging.getLogger(__name__)

в ваших модулях, чтобы показать (с правильный форматтер) модуль, из которого вы ведете журнал.

Из https://docs.python-guide.org/writing/logging/

Лучшая практика при создании экземпляров логгеров в библиотеке - создавать их только с помощью глобальной переменной __name__: модуль регистрации создает иерархия регистраторов с использованием точечной нотации, поэтому использование __name__ гарантирует отсутствие конфликтов имен.

...