Gunicorn: Формат даты регистрации ошибок Gunicorn по умолчанию не соответствует стандарту ISO8601

Созданный на 3 мая 2018  ·  34Комментарии  ·  Источник: benoitc/gunicorn

https://github.com/benoitc/gunicorn/blob/e73ca252f7e1d0286998a0ae4254164291020a0c/gunicorn/glogging.py#L88

Причиной этой проблемы является следующий оператор grok в logstash:

grok { match => { "message" => "\[(?<gunicorn.time>%{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})? %{ISO8601_TIMEZONE})\] \[%{NUMBER:[gunicorn][worker_id]}\] \[%{LOGLEVEL:[gunicorn][level]}\] %{GREEDYDATA:[gunicorn][message]}" } remove_field => "message" }

Если бы формат даты не содержал пробела между временем и часовым поясом , следующий оператор сократил бы его:

grok { match => { "message" => "\[%{TIMESTAMP_ISO8601:[gunicorn][time]}\] \[%{NUMBER:[gunicorn][worker_id]}\] \[%{LOGLEVEL:[gunicorn][level]}\] %{GREEDYDATA:[gunicorn][message]}" } remove_field => "message" }

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

Improvement Discussion FeaturLogging

Самый полезный комментарий

Итак, это означает, что grok в logstash предварительно загружается со строгим шаблоном, а не снисходительным. Я уже работал со стандартами на BBC/EBU и помню такие ужасные формулировки. Для удобочитаемости «(скажем) пробел». Это невозможно реализовать .... что это за символ? Конечно, в этот момент вы можете разрешить использовать любого персонажа, и это не нормально. Итак, ребята из Logstash реализовали это следующим образом: либо T, либо пробел.

TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?

Более того, ВОПРОС ДЕЛАЛСЯ НЕ В ЭТОМ. Проблема заключалась в том, что суффикс часового пояса имеет пробел, который стандарт НЕ ДОПУСКАЕТ.

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

Все 34 Комментарий

Формат даты соответствует Общему формату журнала: https://en.wikipedia.org/wiki/Common_Log_Format .

О, мои извинения. Мой ответ касается формата журнала доступа. Этот отчет касается формата журнала ошибок.

Похоже, вы могли бы использовать %{DATESTAMP} %{ISO8601_TIMEZONE}

для 19.x слишком поздно вносить какие-либо изменения. Это нарушило бы использование большого количества журналов. Мы хотим изменить это в следующей основной версии?

@tilgovi , так это что-то нужно?

Многие развернутые системы полагаются на текущий формат. Я беспокоюсь, что это слишком серьезное изменение, которое не приносит большой пользы, поскольку об этом всегда можно написать правило в журнале, например, в системе. Мысли?

Возможным компромиссом может быть переключение и устаревание. Вы можете начать поэтапный отказ от странного (хотя и незначительного) формата даты, который не соответствует стандартам, и предоставить пользователю возможность переключения на фиксированный формат строки журнала. Я знаю, что я могу переопределить регистратор с помощью python, но, поскольку gunicorn поставляется с запеченными конкурирующими настройками, это не будет моим любимым выбором: я не человек с обсессивно-компульсивным расстройством, но приготовление запроса grok - это современный вид пытки, особенно когда разница вы учитываете одно пространство: D И тогда разработчик должен поддерживать это совпадение дольше, чем необходимо, если что-то изменится. Это не конец света, если нужно, но мы продолжаем исправлять ошибки, даже если люди полагаются на ошибочное программное обеспечение... Вот что я думаю... не уверен, что вопрос был адресован мне...

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

Этот формат довольно распространен на самом деле. В RFC 3339 есть примечание об этом:

ПРИМЕЧАНИЕ. ISO 8601 определяет дату и время, разделенные буквой «T». Приложения, использующие этот синтаксис, могут для удобочитаемости указывать полную дату и полное время, разделенные (скажем) символом пробела.

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

Итак, это означает, что grok в logstash предварительно загружается со строгим шаблоном, а не снисходительным. Я уже работал со стандартами на BBC/EBU и помню такие ужасные формулировки. Для удобочитаемости «(скажем) пробел». Это невозможно реализовать .... что это за символ? Конечно, в этот момент вы можете разрешить использовать любого персонажа, и это не нормально. Итак, ребята из Logstash реализовали это следующим образом: либо T, либо пробел.

TIMESTAMP_ISO8601 %{YEAR}-%{MONTHNUM}-%{MONTHDAY}[T ]%{HOUR}:?%{MINUTE}(?::?%{SECOND})?%{ISO8601_TIMEZONE}?

Более того, ВОПРОС ДЕЛАЛСЯ НЕ В ЭТОМ. Проблема заключалась в том, что суффикс часового пояса имеет пробел, который стандарт НЕ ДОПУСКАЕТ.

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

Это полезно, @kozmaz87. Спасибо, что покопались в спецификации.

Но раз уж мы здесь, я хотел бы также указать на формат журнала доступа, который еще хуже. Мне даже не удалось найти в коде места, откуда он берется... Он построен из какого-то довольно непонятного конфигурационного механизма. присвоено откуда-то еще. Я не проверял код для исследования, но он выдает этот вывод:

127.0.0.1 - - [13/Aug/2018:15:03:26 +0000] "GET /debug/sms HTTP/1.1" 400 74 "-" "python-requests/2.18.4"

Глядя на документы gunicorn, мы узнаем, что вторая часть этого журнала является «-» по какой-то причине... третья часть должна быть пользователем, который также оценивается как «-», не знаю почему, а затем приходит это прекрасное формат даты, в котором час сочетается с годом с помощью ':' и, конечно же, любимый суффикс часового пояса, разделенный пробелом. Но после того, как я покопался, я обнаружил, что именно так nginx регистрирует это, поэтому я предполагаю, что именно отсюда происходит эта разделенная пробелом часовая зона, пытаясь имитировать журналы доступа nginx. HAProxy также использует это, за исключением того, что он не добавляет суффикс часового пояса...

Логирование - это безумие... Кто-нибудь, принесите мне ведро ледяной воды :)

Формат журнала доступа определенно «общий»: https://en.wikipedia.org/wiki/Common_Log_Format .

Однако мы добавляем реферер и пользовательский агент в конец. См. флаг --access-logformat : http://docs.gunicorn.org/en/latest/settings.html#access -log-format

Я понимаю это. Я просто нахожу забавным, что 2-й элемент - это "-": D Такое ощущение, что тот, кто его реализовал, имел это с этим и просто вставил "-"

я бы сохранил текущий формат журнала. imo общий формат хорош, и я не знаю о каких-либо изменениях в серверах вверх по течению. мысли? копия @tilgovi

бамп @tilgovi также @berkerpeksag

закрытие проблемы, поскольку это не исправит. Как сказал @tilgovi , мы используем [общий формат журнала] (
https://en.wikipedia.org/wiki/Common_Log_Format.

Я думаю, мы могли бы оставить это открытым. Мы не используем общий формат журнала для журнала ошибок. Общий формат журнала — это формат журнала доступа, и мы используем его там.

На самом деле, неважно. Я дважды проверил только что, и мы используем одну и ту же строку формата времени для обоих. Мне кажется, это лучше любой альтернативы. Я бы не хотел, чтобы журнал доступа и журнал ошибок имели разные форматы даты.

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

Вот пример вывода Gunicorn с настройками по умолчанию:

[2019-01-25 11:44:34 -0800] [22794] [ИНФОРМАЦИЯ] Стартовая версия gunicorn 19.9.0
[2019-01-25 11:44:34 -0800] [22794] [INFO] Прослушивание: http://127.0.0.1 :8000 (22794)
[2019-01-25 11:44:34 -0800] [22794] [INFO] Использование рабочего процесса: синхронизация
[2019-01-25 11:44:34 -0800] [22797] [INFO] Загрузка рабочего процесса с pid: 22797
[2019-01-25 11:44:36 -0800] [22797] [INFO] 127.0.0.1 - - [25 января/2019:11:44:36 -0800] "GET / HTTP/1.1" 200 14 " -" "завиток/7.54.0"

Проблема заключается не в анализе общего формата журнала доступа, а в анализе _всей строки журнала_.

Gunicorn выводит метку времени, pid и уровень в начале строки журнала. Строки журнала доступа _также_ имеют сообщение в общем формате журнала с собственной отметкой времени.

Обратите внимание, что временные метки имеют разный формат. Первоначальный запрос по этой проблеме заключался в том, чтобы отметка времени в начале строки журнала не содержала пробела _точно так же, как общий формат журнала_.

Это будет выглядеть так:

[25/Jan/2019:11:44:34 -0800] [22794] [ИНФОРМАЦИЯ] Стартовая версия gunicorn 19.9.0
[25/Jan/2019:11:44:34 -0800] [22794] [INFO] Прослушивание: http://127.0.0.1 :8000 (22794)
[25/Jan/2019:11:44:34 -0800] [22794] [INFO] Использование worker: sync
[25/Jan/2019:11:44:34 -0800] [22797] [INFO] Загрузка рабочего процесса с pid: 22797
[25 января/2019:11:44:36 -0800] [22797] [INFO] 127.0.0.1 - - [25 января/2019:11:44:36 -0800] "GET / HTTP/1.1" 200 14 "-" "завиток/7.54.0"

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

Однако мы могли бы изменить временную метку в начале каждой строки журнала на временную метку ISO8601.

https://en.wikipedia.org/wiki/ISO_8601#Combined_date_and_time_representations

Пробел между датой и временем фактически допускается вместо символа T, но пробел между временем и смещением зоны не допускается.

Вот допустимые форматы ISO8601, которые мы могли бы иметь:

  • [2019-01-25T11:44:34-0800]
  • [2019-01-25 11:44:34-0800]

Сравните с тем, что мы имеем сейчас:

[2019-01-25 11:44:34 -0800]
                    ^ there is a space here

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

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

Если людям нужен другой формат для журналов доступа, может быть, мы можем добавить для него специальный идентификатор? Так мы не нарушим формат. Однако журналы ошибок представляют собой проблему, поскольку мы не предоставляем способ их форматирования. В таком случае, может быть, это сделает переменная среды?

Я не думаю, что формат журнала доступа должен измениться. Сейчас это общепринятый формат журнала, и у нас есть настройка --access-log-format .

Формат журнала доступа форматирует только _сообщение_ журнала доступа, которое передается обработчику. Тогда у обработчика есть свой форматтер.

Наш модуль форматирования по умолчанию для обработчиков потоков на stdout и stderr ставит метку времени в начале. Это означает, что с конфигурацией по умолчанию журнал доступа имеет _две_ метки времени: одну в начале и одну в сообщении.

Изменение средства форматирования для обработчика требует использования одной из опций --logconfig (file или dict).

Мы должны рассмотреть возможность использования метки времени ISO8601 в средстве форматирования по умолчанию.

синтаксический анализ/переформатирование журналов легко обрабатываются такими инструментами, как logstash.

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

@tilgovi Я не хочу нарушать совместимость. Также NGINX предлагает возможность установить время в формате ISO8601 или Common Log Format:

$time_iso8601
local time in the ISO 8601 standard format
$time_local
local time in the Common Log Format

https://nginx.org/en/docs/http/ngx_http_log_module.html

Я бы сделал то же самое, поскольку это не нарушает наследие. Кстати, разве мы не должны просто отображать строку журнала доступа к выходу? Кажется, у нас не должно быть первого заголовка с PID. Мысли?

о том, чтобы сделать его частью средства форматирования по умолчанию, я беспокоюсь, что это сломает какой-то инструмент. А как насчет пользовательской переменной окружения TIME_ISO8601=true , чтобы заставить ее работать?

Я не хочу нарушать совместимость.

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

Кстати, разве мы не должны просто отображать строку журнала доступа к выходу? Кажется, у нас не должно быть первого заголовка с PID. Мысли?

Возможный. Я не уверен.

Как насчет пользовательской переменной среды

Может быть, хорошо. Пользователь всегда может полностью контролировать журнал, используя расширенную конфигурацию ведения журнала. Мы стараемся сделать некоторые настройки простыми для CLI, например --log-level , чтобы пользователям не приходилось использовать файлы конфигурации. Может быть, мы могли бы добавить --log-date-format ? Он мог даже распознавать символьные строки, такие как iso8601 . Этот параметр предназначен для пользователей, которые не хотят использовать --log-config или log_config_dict .

@tilgovi тем временем выпуск 20.0 — хорошее время для изменения формата, поскольку мы нарушаем совместимость с python 2.

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

Я хотел бы предложить следующее:

  • [] добавить параметр -iso8601 , который заставит журналы stdout и stderr использовать этот формат (как вы предлагаете)
  • [ ] в журнале доступа добавить опцию в формате для отображения времени в этом формате

Пока мы здесь, возможно, мы могли бы также иметь возможность -utc использовать UTC на время? Мысли?

Просто чтобы быть уверенным, это будет предлагаемый diff, если мы просто изменим значение по умолчанию:

diff --git a/gunicorn/glogging.py b/gunicorn/glogging.py
index 56cc5bd..0735e58 100644
--- a/gunicorn/glogging.py
+++ b/gunicorn/glogging.py
@@ -80,7 +80,7 @@ CONFIG_DEFAULTS = dict(
         formatters={
             "generic": {
                 "format": "%(asctime)s [%(process)d] [%(levelname)s] %(message)s",
-                "datefmt": "[%Y-%m-%d %H:%M:%S %z]",
+                "datefmt": "[%Y-%m-%d %H:%M:%S%z]",
                 "class": "logging.Formatter"
             }
         }
@@ -175,7 +175,7 @@ class Logger(object):
     loglevel = logging.INFO

     error_fmt = r"%(asctime)s [%(process)d] [%(levelname)s] %(message)s"
-    datefmt = r"[%Y-%m-%d %H:%M:%S %z]"
+    datefmt = r"[%Y-%m-%d %H:%M:%S%z]"

     access_fmt = "%(message)s"
     syslog_fmt = "[%(process)d] %(message)s"

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

Я, кстати, не очень к этому отношусь. 😄 Я просто хочу точно представить проблему.

нам, наверное, нужно еще немного подумать об этом. Я откладываю это до 20.1, чтобы позволить нам несколько раз.

Уважаемые девелоперы,
Я столкнулся с проблемой потери запроса (не имеет ничего общего с Gunicorn). Мне нужно иметь точную метку времени, включая микросекунды, как в этом примере с одного из наших серверов Apache: 2019-10-30 14:27:16.960421 . Это было бы классным улучшением, спасибо за его рассмотрение.

Есть ли надежда, что флаг log-date-format iso8601 будет доступен в следующих версиях gunicorn?

Была ли эта страница полезной?
0 / 5 - 0 рейтинги