Observabilidade em TypeScript: da caixa-preta ao sistema transparente
\n\nImagine que sua aplicação TypeScript é um mecanismo complexo com milhares de engrenagens. Tudo funciona perfeitamente, até que algo quebra. E então você recebe uma mensagem: "O site está lento". Onde procurar o problema? Banco de dados? API? Ou apenas um dos microsserviços caiu?
\n\nSem observabilidade, você estará adivinhando como um xamã com um tambor. Com observabilidade, você vê o quadro completo: onde a performance caiu, qual requisição causou o erro e por que houve vazamento de memória.
\n\nNeste artigo, vamos explorar os três pilares da observabilidade — rastreamento, métricas e logs — e aprender a implementá-los em aplicações TypeScript com exemplos reais. Você descobrirá como transformar sua aplicação de uma caixa-preta em um sistema transparente que pode ser diagnosticado em minutos.
\n\nPor que a observabilidade é crítica para aplicações TypeScript?
\n\nTypeScript não é apenas uma extensão do JavaScript. É uma linguagem usada para desenvolver backends de sistemas de alta carga, microsserviços e até ferramentas CLI. E quanto mais complexo o sistema, mais importante é entender o que está acontecendo nele.
\n\nO registro tradicional de logs é bom, mas insuficiente. Quando você tem 50 microsserviços, os logs se tornam ruído branco. Você precisa de:
\n\n- \n
- Rastreamento — para acompanhar o caminho de uma requisição através de todos os serviços. \n
- Métricas — para ver que a RAM está crescendo como fermento. \n
- Logs estruturados — para não procurar uma agulha no palheiro. \n
Vamos implementar isso em uma aplicação real.
\n\nRastreamento em TypeScript: OpenTelemetry na prática
\n\nRastreamento (tracing) é a história de vida de uma requisição. Você vê quanto tempo cada etapa levou: desde a requisição HTTP até a consulta ao banco de dados. Em TypeScript, o padrão de facto é o OpenTelemetry.
\n\nInstalação e configuração do OpenTelemetry
\n\nnpm install @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-jaeger\n\nCrie um arquivo tracing.ts para inicializar o rastreamento:
import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';\nimport { JaegerExporter } from '@opentelemetry/exporter-jaeger';\nimport { Resource } from '@opentelemetry/resources';\nimport { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';\n\nconst jaegerExporter = new JaegerExporter({\n endpoint: 'http://localhost:14268/api/traces',\n serviceName: 'my-typescript-app',\n});\n\nconst sdk = new NodeSDK({\n resource: new Resource({\n [SemanticResourceAttributes.SERVICE_NAME]: 'my-typescript-app',\n [SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',\n }),\n traceExporter: jaegerExporter,\n instrumentations: [getNodeAutoInstrumentations()],\n});\n\nsdk.start();\n\n\nAgora, cada requisição HTTP e cada chamada ao banco de dados serão automaticamente rastreadas. Você verá no Jaeger UI (ou Grafana Tempo) o mapa completo das chamadas.
\n\nCriação manual de spans
\n\nA autoinstrumentação é ótima, mas às vezes você precisa adicionar suas próprias marcações. Por exemplo, medir o tempo de execução de uma lógica de negócios complexa:
\n\nimport { trace } from '@opentelemetry/api';\n\nconst tracer = trace.getTracer('business-logic');\n\nasync function processOrder(orderId: string): Promise<void> {\n const span = tracer.startSpan('process-order', {\n attributes: { 'order.id': orderId },\n });\n\n try {\n // Sua lógica de processamento do pedido\n await validateOrder(orderId);\n await chargePayment(orderId);\n await sendConfirmation(orderId);\n\n span.setStatus({ code: 1 }); // OK\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus