У меня небольшая проблема с регистрацией в Python 3.6 (Flask==0.11.1
) и gunicorn==19.9.0
. Я использую structlog==18.1.0
(для ведения журнала JSON) и python-json-logger==0.1.9
внутри приложения Flask для выхода из системы различных материалов, которые работают сами по себе, т. Е. При запуске приложения Flask без gunicorn. Но при запуске приложения Flask внутри gunicorn появляются случайные проблемы с журналированием, т. Е. Пропадают как журналы доступа из gunicorn, так и из приложения Flask.
Примером события протоколирования будет
import structlog
def some_flask_endpoint():
logger = structlog.getLogger(__name__)
logger.info('This is an info event', additional_data='some additional data')
Что должно выводить сообщение JSON в журналы, подобные этому
{"message": "This is an info event", "additional_data": "some additional data"}
В настоящее время все это делается через регистрацию FileConfig (которую используют и gunicorn, и приложение для колб), как показано ниже:
[loggers]
keys = root,gunicorn.error,gunicorn.access
[handlers]
keys=console,logfile
[formatters]
keys=json
[logger_root]
level=INFO
handlers=console,logfile
[logger_gunicorn.error]
level = INFO
handlers = logfile
propagate = 1
qualname = gunicorn.error
[logger_gunicorn.access]
level = INFO
handlers = logfile
propagate = 0
qualname = gunicorn.access
[handler_console]
class=logging.StreamHandler
formatter=json
args=(sys.stdout, )
[handler_logfile]
class=logging.handlers.TimedRotatingFileHandler
formatter=json
args=('logs.log', 'midnight', )
[formatter_json]
format=%(message)s
class=pythonjsonlogger.jsonlogger.JsonFormatter
т.е. gunicorn использует этот файл с параметром --logconfig logconfig.ini
, а колба использует его с logging.config.fileConfig('logconfig.ini')
из пакета logging
.
Я понимаю, что отправка корневого регистратора в файл журнала может привести к тому, что некоторые события из других регистраторов будут дважды зарегистрированы, но моя главная проблема заключается в том, что, поскольку gunicorn раскручивает нескольких рабочих (в данном случае 4), в каждом из них может происходить столкновение где используется structlog
(т. е. несколько процессов пытаются получить доступ к одному файлу), что может быть причиной отсутствия некоторых журналов.
Итак, другой вариант, о котором я подумал, это просто изменить корневой регистратор, чтобы использовать только обработчик console
, или просто создать новый регистратор, который использует structlog
, т.е.
import structlog
logger = structlog.getLogger('my_app')
logger.info('some info')
[logger_my_app]
level=INFO
handlers=console
А затем заставьте мастера gunicorn взять все журналы из stdout и обработать запись этого в файл журнала и решить проблему с несколькими процессами в одном файле. Однако при предоставлении gunicorn с этим файлом конфигурации логов (чтобы он выводил свои логи в формате json, а также чтобы мне не приходилось предоставлять бесконечное количество параметров для настройки gunicorn), он, похоже, полностью игнорирует параметр --capture-output
и, следовательно, мой structlog
журналы появляются только в консоли, но не записываются ни в один файл конфигурации.
Итак, после этого довольно длинного, но, надеюсь, объяснительного поста, есть ли у кого-нибудь информация о правильном способе хранения журналов из logging
/ structlog
для хранения внутри gunicorn, потому что я не могу найти какую-либо конкретную информацию в Интернете и gunicorn документы на эту тему достаточно зарплатные?
Tl; dr: Как я могу отправить стандартный вывод в файл журнала в gunicorn, одновременно предоставив файл конфигурации журнала для gunicorn.