A primeira vez que você realmente precisa de observabilidade não é quando olha calmamente para um painel. É quando um usuário escreve “checkout lento”, o gráfico de erros parece normal e nos logs você encontra apenas uma linha de mensagens desconectadas.
OpenTelemetry foi criado para evitar esse momento: não para ter mais gráficos, mas para conectar as peças. Uma solicitação entra no API, chama um banco de dados, passa por um provedor externo, publica um trabalho na fila e talvez falhe três serviços depois. Sem rastreamento distribuído, você reconstrói essa história manualmente. Com OpenTelemetry pelo menos você tem um mapa.
A questão não é o trace, é a história
Um trace é uma sequência de span. Dito assim, parece frio. Na prática, cada span é um pedaço da história: POST /checkout, SELECT inventory, call payment provider, publish order.created.
O valor surge quando você começa a responder perguntas reais:
- qual serviço externo está desacelerando?
- os erros vêm de uma versão específica?
- o problema afecta todos ou apenas um inquilino?
- uma nova tentativa está ocultando um tempo limite?
- o trabalho assíncrono começa, mas depois morre em outro lugar?
Essas questões não podem ser resolvidas com um console.log lançado às pressas. Na verdade, muitas vezes o registro adicionado em caso de emergência ajuda você hoje e se torna um barulho amanhã.
Como eu colocaria isso em um aplicativo Node.js
A configuração mais saudável é simples: o aplicativo produz telemetria, o Collector decide para onde enviá-la.
Node.js app -> OpenTelemetry Collector -> backend di observability
Por que não exportar diretamente para o fornecedor? Porque a princípio parece mais rápido, depois você percebe que cada serviço tem configurações diferentes, tentativas diferentes, filtros diferentes e nenhum ponto central para remover dados sensíveis ou alterar o destino.
O Collector é chato da maneira certa. Ele recebe OTLP, faz lotes, pode filtrar, pode fazer amostragem, pode adicionar atributos comuns e pode exportar para vários sistemas.
Autoinstrumentação: boa, mas não suficiente
Em Node.js eu começaria com a instrumentação automática. Dá visibilidade imediata sobre HTTP, estruturas suportadas, bancos de dados e bibliotecas comuns.
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http
Então você inicializa o SDK antes do resto do aplicativo:
import { NodeSDK } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
No entanto, isso vê a estrutura, não o seu produto. Ele sabe que você fez uma consulta, mas não sabe que a consulta estava em "criar pedido" ou "renovar assinatura". Para isso você precisa de span manuais nos pontos onde o domínio conta.
const span = tracer.startSpan('checkout.create_order'); try { span.setAttribute('cart.items_count', input.items.length); const order = await createOrder(input); span.setAttribute('order.id', order.id); return order; } catch (error) { span.recordException(error as Error); throw error; } finally { span.end(); }
Eu não colocaria manuais span em lugar nenhum. Eu os colocaria onde, às três da manhã, gostaria de entender o que aconteceu sem ler metade do código base.
Três regras que evitam muito caos
Primeira regra: cada serviço deve ter service.name, ambiente e versão. Parece trivial, mas sem esses atributos um trace é muito menos útil. Quando uma implantação quebra alguma coisa, você deseja filtrar por versão em dois segundos.
Segunda regra: não coloque dados confidenciais nos atributos. E-mails, tokens, cargas inteiras e endereços não devem acabar em um back-end de observabilidade por acidente. Se você precisar identificar um usuário, considere IDs internos, hash ou campos menos confidenciais.
Terceira regra: preste atenção à cardinalidade. user.id como um atributo de trace pode fazer sentido. Como rótulo de métrica, pode destruir seus custos e desempenho.
Métricas: poucas, mas boas
Eu começaria com métricas muito práticas:
- taxas, erros e duração das solicitações;
- latência de dependências externas;
- número de timeouts e novas tentativas;
- profundidade das caudas;
- duração do trabalho;
- porcentagem de erros por versão.
O resto é adicionado quando necessário. Painéis cheios de gráficos que ninguém olha são móveis, não observabilidade.
Logs: ainda úteis, mas vinculados
Os registros não desaparecem. Eles simplesmente se tornam muito mais úteis quando carregam trace_id e span_id. Portanto, você pode começar a partir de um log de erros e abrir o trace, ou começar a partir de um trace lento e ler apenas os logs produzidos nesse caminho.
Sem correlação, você está procurando agulhas. Com a correlação, pelo menos você sabe em qual gaveta procurar.
A lista de verificação que eu usaria antes de dizer "estamos cobertos"
- O trace na verdade cruza vários serviços.
- Os registros incluem
trace_idespan_id. - O Collector está configurado com lotes e limites de memória.
- Os erros são registrados em span.
- Existe uma política de amostragem.
- As métricas têm cardinalidade controlada.
- Dados confidenciais são filtrados.
- Os alertas começam a partir dos sintomas do usuário, não de gráficos aleatórios.
Conclusão
OpenTelemetry não resolve problemas de produção por si só. Mas a maneira como você lida com eles muda. Em vez de adicionar logs às cegas, você começa a seguir o caminho real de uma solicitação.
Para mim o sinal de que está funcionando é simples: quando algo acontece, a equipe para de perguntar “para onde estamos olhando?” e começa a perguntar "por que essa peça está lenta?". É aí que a observabilidade se torna uma ferramenta, não uma coleção de painéis.