Quando falamos de sistemas distribuídos e arquiteturas de microsserviços, a observabilidade é fundamental para o sucesso operacional. Diferente do simples monitoramento tradicional, a observabilidade nos permite não apenas identificar que algo está errado, mas entender por que está acontecendo.
Neste artigo, o primeiro dessa série que pretendo escrever sobre observabilidade, veremos algumas dicas de como melhorar os logs de uma aplicação para entender de maneira mais eficiente e clara o comportamento do seu sistema em produção.
Evite gerar logs excessivos sem filtragem adequada
Deixar sua aplicação gerar um volume excessivo de logs dificulta a equipe a encontrar dados relevantes no meio de tanta informação, além de poder comprometer o custo, considerando que muitos serviços de observabilidade cobram pela quantidade de logs que são ingeridos e armazenados.
Algumas dicas para ajudar:
- Não crie logs irrelevantes. Seja crítico e reflita se aquele log trará algum benefício para uma análise futura da aplicação.
- Evite gerar logs dentro de estruturas de loops na aplicação.
- Filtre logs debug e trace em produção.
- Filtre logs de bibliotecas e SDKs com informações irrelevantes.
Obs: Bibliotecas de logs já possuem essa funcionalidade de filtro. Por exemplo, em .NET você pode utilizar a biblioteca Serilog para configurar esses filtros.
Centralize os logs
Se você trabalha com sistemas distribuídos e/ou arquiteturas de microsserviços, centralizar todos os logs desses serviços em um único lugar para consulta e análise é essencial. Sem isso, a sustentação desses serviços será muito difícil.
Centralizar os logs ajudará a realizar consultas mais rápidas por não precisar alternar entre diferentes interfaces para visualizar os logs, assim como analisar e correlacionar diferentes serviços de maneira fácil.
Vale lembrar que não estamos falando somente de logs dos serviços que criamos, mas também de logs de serviços que você utiliza de provedores cloud, por exemplo.
Padronize o formato dos logs
Logs bem estruturados são mais fáceis de ler, filtrar e agrupar. Por isso, a maioria das aplicações utiliza o formato JSON para formatar os logs. Evite misturar diferentes formatos como JSON, texto simples e XML, principalmente se você precisa visualizar logs de diferentes aplicações/serviços.
Depois de adotado um formato padrão para o log (preferencialmente JSON), uma segunda definição importante é estabelecer um template padrão. Diferentes serviços gerando logs em diferentes templates dificultarão a realização de buscas em uma ferramenta centralizada. Por exemplo, em um serviço a propriedade se chama "message" e em outro serviço se chama "mensagem".
Outro ponto que geralmente recebe pouca atenção, mas que frequentemente cria dificuldades ao analisar os logs, é a formatação de datetime ou timestamp e fuso horário. Padronize para que todas as aplicações utilizem a mesma formatação e fuso horário para garantir uma análise consistente (você irá me agradecer no futuro, acredite hehehe).
Forneça contexto
Sempre ao criar um log, forneça o máximo de informações relevantes para ser possível identificar padrões de comportamento na aplicação. Evite mensagens genéricas como "Erro no sistema" ou "cliente cadastrado com sucesso". Existem vários tipos de informações que podem contribuir para um log mais completo, as principais são:
- Informações sobre o ambiente: Dados de host, container, IP, configuração (dev/hom/prod), etc.
- Informações sobre a aplicação/serviço: nome do serviço, versão de deploy, URL requisitada, nome da classe, nome do método, etc.
- Identificadores de correlação: trace ID, request ID, correlation ID, etc.
- Informações de contexto: Informações adicionais que fazem sentido para aquele log específico, como parâmetros de entrada, parâmetros de saída, qual ID foi gerado, qual usuário realizou aquela ação, etc.
- Em caso de erro: Qual foi o erro, stack trace do erro (fornecerá os métodos e linhas por onde o erro percorreu), etc.
Como fornecer contexto da maneira correta
A maioria das informações exemplificadas acima será configurada para que a aplicação já forneça automaticamente para os logs, exceto as informações de contexto, que são dados que você fornecerá de forma específica para cada log. Tome o cuidado para não fornecer essas informações como string, pois isso dificultará filtros e agrupamentos nas ferramentas de observabilidade. O correto é fornecer esses dados como metadados do log, veja o exemplo abaixo em C#:
Forma incorreta:
log.LogInformation(
$"Transação #{transactionId} processada: status={transactionStatus}, tipo={transactionType}."
);
Output gerado:
{
...
"Message": "Transação #45892 processada: status=FINALIZADA, tipo=PAGAMENTO"
...
}
Forma correta:
log.LogInformation(
"Transação #{transactionId} processada: status={transactionStatus}, tipo={transactionType}.",
transactionId,
transactionStatus,
transactionType
);
Output gerado:
{
...
"Message": "Transação #45892 processada: status=FINALIZADA, tipo=PAGAMENTO",
"Metadata":
{
"transactionId": 45892,
"transactionStatus": "FINALIZADA",
"transactionType": "PAGAMENTO"
}
...
}
Remova dados sensíveis
Criar logs com dados sensíveis pode resultar em problemas jurídicos ou de segurança para sua aplicação. Não forneça dados que possam identificar uma pessoa como CPF, nome completo, email e afins. Dados como tokens e senhas também podem expor riscos de segurança.
Quando um dado sensível precisa realmente estar em um log para trazer contexto e sentido para ele, você pode optar pelo ofuscamento parcial da informação, como por exemplo, fornecer apenas os 5 primeiros números do CPF e ocultar o restante. Existem bibliotecas que podem ajudar com esse ofuscamento, e também as principais ferramentas de observabilidade permitem criar padrões de ofuscamento, geralmente mediante um custo adicional.
Utilize o nível de log correto
Logs não servem apenas para capturar erros; uma estratégia de logging robusta faz uso de todos ou quase todos os diferentes níveis de log. Embora os nomes de cada nível possam variar um pouco entre as linguagens de programação e ferramentas de observabilidade, geralmente são oferecidos seis níveis de log. Para este artigo, utilizarei os nomes dos níveis de log da Microsoft.
Nível | Descrição |
---|---|
Critical | Logs que descrevem um erro catastrófico irrecuperável na aplicação que impede que ela continue funcionando, exigindo atenção imediata. |
Error | Logs que destacam quando o fluxo de execução atual é interrompido devido a um erro inesperado. Deve indicar um erro na atividade atual, não um erro em toda a aplicação. |
Warning | Indica situações inesperadas ou potencialmente problemáticas mas que não impedem o funcionamento normal. Serve como alerta para possíveis problemas futuros. |
Information | Captura eventos operacionais normais e marcos importantes do fluxo da aplicação, útil para rastrear o funcionamento geral do sistema. |
Debug | Fornece informações detalhadas úteis para diagnóstico de problemas durante o desenvolvimento ou investigação de problemas; inclui valores de variáveis e fluxo de execução. Não possuem valor a longo prazo. |
Trace | Registra o nível mais granular de informações, incluindo entrada/saída de métodos e detalhes de processamento interno; usado principalmente durante debugging intensivo. São desabilitadas por padrão e nunca devem ser habilitadas em ambiente de produção. |
Configure um período de retenção de logs
Logs são caros para armazenar devido ao alto volume de dados. Configure um período de retenção adequado para o orçamento destinado à observabilidade.
Se sua aplicação precisa de um período maior de armazenamento de logs, considere transferir esses dados após um determinado período para um armazenamento mais econômico. Em algumas ferramentas de observabilidade, como o Datadog, isso é fácil de configurar.
Sobre retenção de logs, já participei de discussões onde foi defendido que o período de retenção deveria ser extenso (na casa de anos) pois os logs serviam como auditoria da aplicação. Acredito ser um equívoco utilizar os logs como auditoria, pois os dois possuem finalidades distintas (pode até virar tema de outro artigo hehe).
Performance
Por último, mas não menos importante, a aplicação não deve sofrer bloqueio da thread principal para operações de log. Utilize processamentos assíncronos e buffering de logs para melhorar a performance da aplicação.
Conclusão
Implementar boas práticas de logging é importante para construir uma estratégia de observabilidade eficiente. Com logs bem estruturados, padronizados e contextualizados, sua equipe estará melhor equipada para diagnosticar problemas rapidamente e entender o comportamento real do sistema em produção.
Se você possui alguma dica adicional, ou discorda de algum ponto, por favor, deixe um comentário. Será legal trocar experiências sobre o tema.
Top comments (1)
Excelente @marcosbelorio !