Я закончил тем, что создал пользовательский процессор
Я посмотрел на что structlog
делает для вывода модуля и номера строки, когда ему говорят "притворись" для форматирования в совместимом режиме с библиотекой logging
(имеется в виду, когда он использует обычный stdlib.LoggerFactory
), и я нашел в этом вдохновение.Ключ, в котором слова ...
Используя structlog structlog.stdlib.LoggerFactory, также обеспечивается правильное расширение переменных, таких как имена функций и номера строк, в формате журнала.
... С этой страницы документации
Кажется, что он продолжает искать кадры выполнения, пока не найдет тот, который находится в модуле, не связанном с журналированием.
У меня есть все настройки для structlog
внутри модуля с именем my_libs.util.logger
, поэтому я хочу получить первый кадр, который НЕ находится внутри этого модуля, поэтому я сказал ему добавить к этим исключениям мой связанный с журналированием my_libs.util.logger
.Вот что делает additional_ignores
в приведенном ниже коде.
В примере я жестко закодировал имя модуля ('my_libs.util.logger'
) в списке исключений для ясности, но если у вас есть аналогичная настройка, вы, вероятно, будетелучше вместо этого использовать __name__
.
Как только он найдет правильный кадр, извлечь любую информацию (имя модуля, имя функции, номер строки ...) очень легко, особенноиспользуя осмотреть модуль .Я решил вывести имя модуля и номер строки, но можно было бы добавить больше полей.
# file my_libs/util/logger.py
from structlog._frames import _find_first_app_frame_and_name
def show_module_info_processor(logger, _, event_dict):
# If by any chance the record already contains a `modline` key,
# (very rare) move that into a 'modline_original' key
if 'modline' in event_dict:
event_dict['modline_original'] = event_dict['modline']
f, name = _find_first_app_frame_and_name(additional_ignores=[
"logging",
'my_libs.util.logger', # could just be __name__
])
if not f:
return event_dict
frameinfo = inspect.getframeinfo(f)
if not frameinfo:
return event_dict
module = inspect.getmodule(f)
if not module:
return event_dict
if frameinfo and module:
event_dict['modline'] = '{}:{}'.format(
module.__name__,
frameinfo.lineno,
)
return event_dict
def setup_structlog(env=None):
# . . .
ch.setFormatter(logging.Formatter('%(message)s'))
logging.getLogger().handlers = [ch]
processors = [
structlog.stdlib.add_logger_name,
structlog.stdlib.add_log_level,
# . . . more . . .
show_module_info_processor, # THIS!!!
structlog.processors.TimeStamper(fmt="%Y-%m-%d %H:%M:%S"),
structlog.processors.format_exc_info,
structlog.processors.StackInfoRenderer(),
# . . . more . . .
]
# . . . more . . .
structlog.configure_once(
logger_factory=structlog.stdlib.LoggerFactory(),
wrapper_class=structlog.stdlib.BoundLogger,
context_class=structlog.threadlocal.wrap_dict(dict),
processors=processors,
)
Это приводит к выводу типа:
server_1
| INFO [my_libs.hdfs] 2019-07-01 01:01:01 [info ] Initialized HDFS
[my_libs.hdfs] modline=my_libs.hdfs:31