Benefícios do log estruturado versus log básico

110

Estamos criando um novo aplicativo e eu gostaria de incluir o log estruturado. Minha configuração ideal seria algo como Serilogpara o nosso código C # e Bunyanpara o nosso JS. Eles se alimentariam fluentde poderiam sair para várias coisas, pensei inicialmente elasticsearch + kibana. Já temos um banco de dados MySQL, então, a curto prazo, estou mais interessado em obter a configuração do Serilog + Bunyan e os desenvolvedores para usá-lo, e podemos fazer logon no MySQL enquanto levamos um pouco mais de tempo trazendo o fluente e o resto.

No entanto, um dos nossos codificadores mais experientes prefere fazer algo como: log.debug("Disk quota {0} exceeded by user {1}", quota, user);using log4nete, em seguida, apenas executar instruções select no MySQL como:SELECT text FROM logs WHERE text LIKE "Disk quota";

Dito isto, qual abordagem é melhor e / ou que coisas precisamos considerar ao escolher o tipo de sistema de registro?

DTI-Matt
fonte
Eu concordo com as edições que foram feitas. Não estou tentando provar algo a alguém, mas tentando entender os benefícios e as diferenças entre o log estruturado e o básico. Na minha opinião, a estrutura nos oferece muito mais flexibilidade, especialmente nas fontes de logs e em como podemos exibir seus dados. No ponto em que entendi, não consigo explicar por que o log e a pesquisa básicos do MySQL são melhores / piores que o log estruturado.
precisa
2
@ O log estruturado do DTI-Matt serilog é apenas um log básico, apenas formata os objetos que você imprime nele - algo que você pode fazer sozinho substituindo o ToString com muita facilidade. Um aspecto mais importante é a configuração e o gerenciamento dos arquivos de log, não uma maneira de formatar uma string em detrimento de outra, outra é o desempenho. Se o desenvolvedor quiser usar o log4net (que é uma boa biblioteca de registro), sua escolha do serilog (que parece legal) é uma dessas coisas de "soluções em busca de um problema".
precisa
@ DTI-Matt Ao olhar para o serilog, ele se parece muito com o log4net. O log4net trata da criação de logs estruturados na configuração. Você não precisa procurar as mensagens de log, pois pode ter informações adicionais configuradas e gravadas em uma tabela. Também configure o log4net para fluentd tipstuff.org/2014/05/…
RubberChickenLeader
Cuidado, existem alguns tolos que não entendem a idéia de perguntas conceituais aqui. perguntando sobre a direção dos aplicativos de banco de dados na tentativa de controlar seus recursos de ETL v. código, você receberá alguns votos negativos. Eu suponho que sua pergunta também estará no ponto de desbaste.
user3916597
2
@gbjbaanb O Serilog funciona da mesma maneira que o log4net ao renderizar eventos como texto, mas se você usar um formato estruturado para armazenar logs, ele associará as propriedades nomeadas aos argumentos passados ​​(por exemplo, para apoiar a pesquisa / filtragem sem regex etc.) ) HTH!
Nicholas Blumhardt

Respostas:

140

Existem dois avanços fundamentais na abordagem estruturada que não podem ser emulados usando logs de texto sem (às vezes níveis extremos de) esforço adicional.

Tipos de Eventos

Quando você escreve dois eventos com o log4net, como:

log.Debug("Disk quota {0} exceeded by user {1}", 100, "DTI-Matt");
log.Debug("Disk quota {0} exceeded by user {1}", 150, "nblumhardt");

Isso produzirá texto semelhante:

Disk quota 100 exceeded by user DTI-Matt
Disk quota 150 exceeded by user nblumhardt

Mas, no que diz respeito ao processamento da máquina, são apenas duas linhas de texto diferente.

Você pode encontrar todos os eventos de "cota de disco excedida", mas o caso simplista de procurar eventos like 'Disk quota%'cairá assim que outro evento ocorrer:

Disk quota 100 set for user DTI-Matt

O registro de texto descarta as informações que temos inicialmente sobre a origem do evento, e isso deve ser reconstruído ao ler os registros geralmente com expressões de correspondência cada vez mais elaboradas.

Por outro lado, quando você escreve os dois eventos Serilog a seguir :

log.Debug("Disk quota {Quota} exceeded by user {Username}", 100, "DTI-Matt");
log.Debug("Disk quota {Quota} exceeded by user {Username}", 150, "nblumhardt");

Eles produzem saída de texto semelhante à versão log4net, mas nos bastidores, o "Disk quota {Quota} exceeded by user {Username}" modelo de mensagem é carregado pelos dois eventos.

Com um coletor apropriado, você pode escrever consultas posteriormente where MessageTemplate = 'Disk quota {Quota} exceeded by user {Username}'e obter exatamente os eventos em que a cota de disco foi excedida.

Nem sempre é conveniente armazenar o modelo de mensagem inteiro com cada evento de log; portanto, alguns afundamentos colocam o modelo de mensagem em hash em um EventTypevalor numérico (por exemplo 0x1234abcd), ou você pode adicionar um enricher ao pipeline de log para fazer isso sozinho .

É mais sutil que a próxima diferença abaixo, mas extremamente poderosa ao lidar com grandes volumes de log.

Dados Estruturados

Novamente, considerando os dois eventos sobre o uso do espaço em disco, pode ser fácil usar logs de texto para consultar um usuário específico like 'Disk quota' and like 'DTI-Matt'.

Porém, os diagnósticos de produção nem sempre são tão diretos. Imagine que seja necessário encontrar eventos em que a cota de disco excedida esteja abaixo de 125 MB?

Com o Serilog, isso é possível na maioria dos sumidouros usando uma variante de:

Quota < 125

Construir esse tipo de consulta a partir de uma expressão regular é possível, mas torna-se cansativo rápido e normalmente acaba por ser uma medida de último recurso.

Agora adicione a isso um tipo de evento:

Quota < 125 and EventType = 0x1234abcd

Você começa a ver aqui como esses recursos se combinam de maneira direta para fazer com que a depuração da produção com logs pareça uma atividade de desenvolvimento de primeira classe.

Um benefício adicional, talvez não tão fácil de prevenir antecipadamente, mas depois que a depuração da produção foi removida da área de hackers regex, os desenvolvedores começam a valorizar os logs muito mais e a ter mais cuidado e consideração ao escrevê-los. Melhores registros -> aplicativos de melhor qualidade -> mais felicidade ao redor.

Nicholas Blumhardt
fonte
4
eu amo essa resposta muito bem escrito e, por algum motivo, não sei explicar, me mantém na ponta do meu assento.
Jokab
16

Quando você está coletando logs para processamento, seja para analisar em algum banco de dados e / ou pesquisar os logs processados ​​posteriormente, o uso do log estruturado torna alguns dos processos mais fáceis / eficientes. O analisador pode tirar proveito da estrutura conhecida ( por exemplo , JSON, XML, ASN.1, qualquer que seja) e usar máquinas de estado para analisar, em oposição a expressões regulares (que podem ser computacionalmente caras (relativamente) para compilar e executar). A análise de texto de forma livre, como a sugerida pelo seu colega de trabalho, tende a depender de expressões regulares e a não mudar o texto . Isso pode tornar a análise de texto de forma livre bastante frágil ( ou seja, a análise está fortemente acoplada ao texto exato no código).

Considere também o caso de pesquisa / pesquisa, por exemplo :

SELECT text FROM logs WHERE text LIKE "Disk quota";

LIKEcondições requerem comparações com cada textvalor de linha; novamente, isso é relativamente computacionalmente caro, principalmente quando os curingas são usados:

SELECT text FROM logs WHERE text LIKE "Disk %";

Com o log estruturado, sua mensagem de log relacionada ao erro de disco pode se parecer com isso no JSON:

{ "level": "DEBUG", "user": "username", "error_type": "disk", "text": "Disk quota ... exceeded by user ..." }

Os campos desse tipo de estrutura podem ser mapeados facilmente, por exemplo , nomes de colunas da tabela SQL, o que significa que a pesquisa pode ser mais específica / granular:

SELECT user, text FROM logs WHERE error_type = "disk";

Você pode colocar índices nas colunas cujos valores você espera pesquisar / procurar com freqüência, desde que não use LIKEcláusulas para esses valores de coluna . Quanto mais você puder dividir sua mensagem de log em categorias específicas, mais direcionado poderá fazer sua pesquisa. Por exemplo, além do error_typecampo / coluna no exemplo acima, você pode criar um par "error_category": "disk", "error_type": "quota"ou algo assim.

Quanto mais estrutura que você tem em suas mensagens de log, os sistemas mais a sua análise / busca (como fluentd, elasticsearch, kibana) pode tirar vantagem dessa estrutura, e executar suas tarefas com maior velocidade e menos CPU / memória.

Espero que isto ajude!

Castaglia
fonte
1
+1 Quer acrescentar que não se trata apenas de velocidade e eficiência. A relevância dos resultados da pesquisa será muito maior ao usar o log estruturado e, portanto, "consultas estruturadas". Sem isso, procurar por palavras que ocorram em diferentes contextos fornecerá toneladas de hits irrelevantes.
Marjan Venema
1
+1 de mim também, eu acho que isso acertou em cheio. Adicionada uma formulação ligeiramente diferente abaixo, para expandir também o caso dos tipos de eventos.
Nicholas Blumhardt
8

Você não encontrará muitos benefícios com o log estruturado quando o aplicativo criar algumas centenas de mensagens de log por dia. Definitivamente, você terá quando tiver centenas de mensagens de log por segundo provenientes de vários aplicativos implantados.

Relacionado, a configuração em que as mensagens de log terminam na pilha ELK também é apropriada para a escala em que o log no SQL se torna um gargalo.

Vi a configuração do "registro e pesquisa básicos" com SQL select .. likee regexps chegar ao limite onde desmorona - há falsos positivos, omissões, código de filtro horrível com bugs conhecidos difíceis de manter e ninguém quer tocar, novas mensagens de log que não seguem as premissas do filtro, relutância em tocar as instruções de log no código, para que não quebrem relatórios etc.

Portanto, vários pacotes de software estão surgindo para lidar com esse problema de uma maneira melhor. Existe o Serilog, ouvi dizer que a equipe do NLog está olhando para ele , e escrevemos StructuredLogging.Jsonpara o Nlog , também vejo que as novas abstrações de log de núcleo do ASP.Net "possibilitam que os provedores de log implementem ... o log estruturado".

Um exemplo com StructuredLogging. Você faz logon em um logger NLog como este:

logger.ExtendedError("Order send failed", new { OrderId = 1234, RestaurantId = 4567 } );

Esses dados estruturados vão para kibana. O valor 1234é armazenado no OrderIdcampo da entrada do log. Você pode pesquisar usando a sintaxe de consulta do kibana, por exemplo, todas as entradas de log em que @LogType:nlog AND Level:Error AND OrderId:1234.

Messagee OrderIdagora são apenas campos que podem ser pesquisados ​​por correspondências exatas ou inexatas, conforme necessário, ou agregados por contagens. Isso é poderoso e flexível.

Das práticas recomendadas do StructuredLogging :

A mensagem registrada deve ser a mesma sempre. Deve ser uma sequência constante, não uma sequência formatada para conter valores de dados, como IDs ou quantidades. Então é fácil procurar.

A mensagem registrada deve ser distinta, ou seja, não a mesma que a mensagem produzida por uma instrução de log não relacionada. Então, procurá-lo também não corresponde a coisas não relacionadas.

Anthony
fonte