Gunicorn: O formato de data de registro de erros padrão do Gunicorn não é o padrão ISO8601

Criado em 3 mai. 2018  ·  34Comentários  ·  Fonte: benoitc/gunicorn

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

A motivação para esse problema é a seguinte declaração grok no 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" }

Se o formato de data não incluísse espaço entre a hora e o fuso horário, a seguinte declaração teria cortado:

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

Eu diria que um formato de data padrão seria mais adequado para uma configuração padrão. Acho que adicionar um espaço extra não agrega valor, mas cria problemas. Ou ter que substituir todo o logconfig padrão, o que é excessivo, ou ter que escrever expressões personalizadas nos analisadores de log para atendê-lo.

Improvement Discussion FeaturLogging

Comentários muito úteis

Ok, isso significa que o grok no logstash é pré-carregado com um padrão estrito em vez do leniente. Eu trabalhei com pessoas de padrões antes na BBC/EBU e me lembro desse tipo de frase terrível. Para legibilidade "(digamos) um caractere de espaço" Isso não é implementável.... o que é esse caractere? É claro que você pode permitir qualquer caractere neste momento e isso não está certo. Então, os caras do Logstash implementaram isso da seguinte maneira para ser T ou espaço

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

Além disso, NÃO É ASSIM QUE O PROBLEMA SE TRATA. O problema era que o sufixo de fuso horário tinha um espaço que o padrão NÃO PERMITE.

Então não, infelizmente esse formato não é comum. Este formato não é ortodoxo específico para gunicorn. Eu sei o quão estúpido isso soa que estamos discutindo sobre um espaço, mas quando se trata de linguagens e autômatos, a sintaxe é tudo.

Todos 34 comentários

O formato de data segue o formato de log comum: https://en.wikipedia.org/wiki/Common_Log_Format

Ah, minhas desculpas. Minha resposta é sobre o formato do log de acesso. Este relatório é sobre o formato do log de erros.

Parece que você poderia usar %{DATESTAMP} %{ISO8601_TIMEZONE}

para 19.x é tarde demais para fazer qualquer alteração. Isso quebraria muito o uso de log ao redor. Isso é algo que queremos mudar na próxima versão principal?

@tilgovi então isso é algo desejado?

Muitos sistemas implantados dependem do formato atual. Estou preocupado que seja uma mudança muito grande que não traga muito valor, pois uma regra sempre pode ser escrita sobre isso em sistemas semelhantes a log stash. Pensamentos?

Um possível compromisso pode ser uma troca e uma depreciação. Você pode começar a eliminar gradualmente o formato de data ímpar (ainda que ligeiramente) que não esteja seguindo os padrões e fornecer ao usuário uma mudança para um formato de linha de log fixo. Eu sei que posso substituir o logger via python, mas como o gunicorn vem com suas configurações concorrentes, não seria minha escolha favorita: não sou uma pessoa com TOC, mas preparar uma consulta grok é um tipo moderno de tortura, especialmente quando a diferença você está contabilizando é um espaço :D E então cabe ao desenvolvedor manter essa correspondência mais longa do que o necessário, caso algo mude. Não é o fim do mundo se for preciso, mas continuamos corrigindo bugs, mesmo que as pessoas confiem no software com bugs... Isso é o que eu acho... não tenho certeza se a pergunta foi apontada para mim...

Poderíamos olhar para alterar o padrão para R20.

Este formato é bastante comum na verdade. O RFC 3339 tem uma nota sobre isso:

NOTA: A ISO 8601 define data e hora separadas por "T". Os aplicativos que usam essa sintaxe podem escolher, por uma questão de legibilidade, especificar uma data completa e um horário completo separados por (digamos) um caractere de espaço.

O log de erros também é impresso na linha de comando e deve ser lido por um humano e eu gostaria de mantê-lo assim. Existe algum problema com o formato do fuso horário?

Ok, isso significa que o grok no logstash é pré-carregado com um padrão estrito em vez do leniente. Eu trabalhei com pessoas de padrões antes na BBC/EBU e me lembro desse tipo de frase terrível. Para legibilidade "(digamos) um caractere de espaço" Isso não é implementável.... o que é esse caractere? É claro que você pode permitir qualquer caractere neste momento e isso não está certo. Então, os caras do Logstash implementaram isso da seguinte maneira para ser T ou espaço

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

Além disso, NÃO É ASSIM QUE O PROBLEMA SE TRATA. O problema era que o sufixo de fuso horário tinha um espaço que o padrão NÃO PERMITE.

Então não, infelizmente esse formato não é comum. Este formato não é ortodoxo específico para gunicorn. Eu sei o quão estúpido isso soa que estamos discutindo sobre um espaço, mas quando se trata de linguagens e autômatos, a sintaxe é tudo.

Isso é útil, @kozmaz87. Obrigado por se aprofundar na especificação.

Mas já que estamos aqui eu adoraria apontar também para o formato de log de acesso, que é ainda pior. Eu nem consegui encontrar no código nenhum lugar de onde ele vem... Ele é construído a partir de algum mecanismo de configuração bastante obscuro. atribuído de outro lugar. Eu não fiz check-out do código para investigar, mas ele produz esta saída:

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

Olhando para os documentos do gunicorn, aprendemos que a 2ª parte deste log é um '-' por qualquer motivo ... formato de data em que a hora é casada com o ano por um ':' e, claro, o sufixo de fuso horário separado por espaço favorito novamente. Mas depois de pesquisar, descobri que é assim que o nginx o registra, então suponho que é de onde essa coisa de fuso horário separado por espaço está se originando, tentando imitar os logs de acesso do nginx. O HAProxy também usa isso, exceto que não coloca um sufixo de fuso horário ...

A extração de madeira é uma loucura... Alguém me traga um balde de água gelada :)

O formato do log de acesso é definitivamente "comum": https://en.wikipedia.org/wiki/Common_Log_Format

No entanto, adicionamos referenciador e agente de usuário ao final. Consulte o sinalizador --access-logformat : http://docs.gunicorn.org/en/latest/settings.html#access -log-format

Eu percebo isso. Só acho engraçado que o 2º item seja um '-' :D Parece que quem o implementou teve isso com isso e apenas colocou um '-'

eu manteria o formato de log atual. O formato comum do imo é bom e não estou ciente de nenhuma alteração nos servidores upstream. pensamentos? cc @tilgovi

bump @tilgovi também @berkerpeksag

fechando o problema como não vai corrigir. Como disse @tilgovi , estamos usando o [formato de log comum](
https://en.wikipedia.org/wiki/Common_Log_Format.

Acho que poderíamos manter isso em aberto. Não estamos usando o formato de log comum para o log de erros. O formato de log comum é um formato de log de acesso e nós o usamos lá.

Na verdade, não importa. Eu verifiquei agora e usamos a mesma string de formato de hora para ambos. Isso me parece melhor do que qualquer alternativa. Eu não gostaria que o log de acesso e o log de erros tivessem formatos de data diferentes.

Entendo melhor a questão agora e acho que devemos reabrir.

Aqui está a saída de exemplo do Gunicorn com configurações padrão:

[2019-01-25 11:44:34 -0800] [22794] [INFO] Iniciando o gunicorn 19.9.0
[2019-01-25 11:44:34 -0800] [22794] [INFO] Ouvindo em: http://127.0.0.1 :8000 (22794)
[2019-01-25 11:44:34 -0800] [22794] [INFO] Usando o trabalhador: sincronização
[2019-01-25 11:44:34 -0800] [22797] [INFO] Inicializando o trabalhador com pid: 22797
[2019-01-25 11:44:36 -0800] [22797] [INFO] 127.0.0.1 - - [25/Jan/2019:11:44:36 -0800] "GET / HTTP/1.1" 200 14 " -" "enrolar/7.54.0"

O problema não é analisar o formato de log comum do log de acesso, é analisar a _linha de log inteira_.

Gunicorn gera um timestamp, pid e level no início da linha de log. As linhas de log de acesso _também_ possuem uma mensagem em formato de log comum com seu próprio timestamp.

Observe como os timestamps não estão no mesmo formato. A solicitação original para esse problema era que o carimbo de data/hora no início da linha de log não tivesse espaço _assim como o formato de log comum_.

Isso ficaria assim:

[25/Jan/2019:11:44:34 -0800] [22794] [INFO] Iniciando o gunicorn 19.9.0
[25/Jan/2019:11:44:34 -0800] [22794] [INFO] Ouvindo em: http://127.0.0.1 :8000 (22794)
[25/Jan/2019:11:44:34 -0800] [22794] [INFO] Usando o trabalhador: sincronização
[25/Jan/2019:11:44:34 -0800] [22797] [INFO] Inicializando o trabalhador com pid: 22797
[25/Jan/2019:11:44:36 -0800] [22797] [INFO] 127.0.0.1 - - [25/Jan/2019:11:44:36 -0800] "GET / HTTP/1.1" 200 14 "-" "enrolar/7.54.0"

Acho que a resposta provavelmente não é, porque o formato de log comum não é tão internacional (tem um nome de mês curto).

No entanto, podemos alterar o carimbo de data/hora no início de cada linha de log para ser um carimbo de data/hora ISO8601.

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

O espaço entre a data e a hora é realmente permitido no lugar de um caractere T, mas um espaço entre a hora e o deslocamento da zona não é.

Aqui estão os formatos ISO8601 válidos que poderíamos ter:

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

Compare com o que temos agora:

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

Eu me preocuparia muito em quebrar sistemas implantados, no entanto.

bem, os logs de análise/reformatação podem ser facilmente manipulados por ferramentas como o logstash, então não tenho certeza se é um problema. Eu manteria assim por enquanto.

Se as pessoas quiserem um formato diferente para logs de acesso, talvez possamos adicionar um identificador específico para ele? Assim não quebraríamos o formato. No entanto, os logs de erros são um problema, pois não fornecemos uma maneira de formatá-los. Nesse caso, talvez uma variável de ambiente faria isso?

Eu não acho que o formato do log de acesso deva mudar. É o formato de log comum agora e temos a configuração --access-log-format .

O formato do log de acesso apenas formata a _message_ do log de acesso que é passado para o manipulador. O manipulador tem então seu próprio formatador.

Nosso formatador padrão para os manipuladores de fluxo em stdout e stderr coloca um timestamp no início. Isso significa que com a configuração padrão o log de acesso tem _dois_ timestamps: um no início e outro na mensagem.

Alterar o formatador do manipulador requer o uso de uma das opções --logconfig (file ou dict).

Devemos considerar ter um timestamp ISO8601 no formatador padrão.

os logs de análise/reformatação podem ser facilmente manipulados por ferramentas como o logstash

Sim, mas é muito conveniente quando essas ferramentas podem analisar o timestamp com padrões internos para que o usuário não precise escrever um regexp. O problema original foi aberto porque o grok possui um padrão interno para carimbos de data e hora ISO8601.

@tilgovi Não quero quebrar a compatibilidade. Além disso, o NGINX oferece a possibilidade de definir a hora usando o formato ISO8601 ou o formato de log comum:

$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

Eu faria o mesmo desde que não quebra o legado. Aliás, não deveríamos apenas exibir a linha de log de acesso para a saída? Parece que não devemos ter o primeiro cabeçalho com o PID. Pensamentos?

sobre torná-lo parte do formatador padrão, estou preocupado que ele quebre alguma ferramenta. Que tal ter uma variável de ambiente personalizada TIME_ISO8601=true para forçá-la?

Não quero quebrar a compatibilidade.

Eu também não. Eu só queria reabrir o ticket porque acho que o fechamos pelo motivo errado. Ambos respondemos como se o problema fosse mudar do formato de log comum. O problema é o carimbo de data/hora no formatador padrão, não o formato da mensagem de log de acesso. Fico feliz que possamos discutir mais sobre isso, mas a resposta talvez seja ainda não fazer nada.

Aliás, não deveríamos apenas exibir a linha de log de acesso para a saída? Parece que não devemos ter o primeiro cabeçalho com o PID. Pensamentos?

Possível. Não tenho certeza.

Que tal ter uma variável de ambiente personalizada

Talvez tudo bem. O usuário sempre pode controlar o log completamente usando a configuração de log avançada. Tentamos simplificar algumas configurações para a CLI, como --log-level , para que os usuários não precisem usar arquivos de configuração. Talvez possamos adicionar --log-date-format ? Ele pode até reconhecer strings simbólicas como iso8601 . Essa configuração seria para usuários que não desejam usar --log-config ou log_config_dict .

@tilgovi , enquanto isso, a versão 20.0 é um bom momento para uma mudança no formato, pois estamos quebrando a compatibilidade com o python 2.

Acho que o que mais me preocupa em qualquer legado é que o ISO8601 é difícil de analisar aos olhos humanos e muitas pessoas, inclusive eu, estão usando o console como uma oportunidade de observar o que está acontecendo.

Eu gostaria de sugerir o seguinte:

  • [ ] adicione uma opção -iso8601 que força os logs stdout e stderr a usar este formato (como você está sugerindo)
  • [ ] no log de acesso adicione uma opção no formato para exibir a hora neste formato

Enquanto estamos aqui, talvez também possamos ter uma opção -utc para usar o UTC por enquanto? Pensamentos?

Só para ter certeza, este seria o diff proposto se apenas alterássemos o padrão:

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"

Acho interessante uma opção de usar um datetime ISO8601 nos tokens de log de acesso, mas é separado do que motivou esse problema.

A propósito, não me sinto muito bem com isso. 😄 Eu só quero representar a questão com precisão.

provavelmente precisamos pensar um pouco mais sobre isso. Estou adiando para 20.1 para nos deixar algumas vezes.

Caros devels,
Estou enfrentando um problema de perda de solicitação (não tem nada a ver com Gunicorn). Eu precisaria ter o timestamp preciso incluindo os microssegundos, como neste exemplo de um de nossos servidores Apache: 2019-10-30 14:27:16.960421 . Seria um aprimoramento legal, obrigado por considerá-lo.

Alguma esperança se a bandeira, log-date-format iso8601 , estará disponível nas próximas versões do gunicorn?

Esta página foi útil?
0 / 5 - 0 avaliações