Observabilidade em Node.js: OpenTelemetry + Grafana passo a passo
Introdução
Nos últimos anos, a observabilidade deixou de ser um diferencial e se tornou requisito básico para aplicações em produção. Sem visibilidade clara sobre latência, erros e recursos consumidos, equipes de desenvolvimento gastam horas (ou dias) tentando reproduzir problemas que já aconteceram. Ferramentas como OpenTelemetry, Prometheus e Grafana permitem coletar métricas, traces e logs de forma padronizada, facilitando a detecção precoce de incidentes e a tomada de decisão baseada em dados.
Este post mostra, de forma prática, como instrumentar uma aplicação Node.js usando o SDK do OpenTelemetry, exportar os dados para o Prometheus e visualizá‑los no Grafana. Ao final, você terá um pipeline completo de observabilidade pronto para ser integrado ao seu CI/CD.
1. Preparando o ambiente
1.1 Requisitos
- Node.js >= 14
- Docker & Docker‑Compose
- Conta no Grafana Cloud (ou instalação local)
- Git instalado
1.2 Estrutura do projeto
bash my-observability-app/ ├─ src/ │ └─ index.js ├─ otel-config/ │ └─ otel-setup.js ├─ docker-compose.yml ├─ package.json └─ .env
1.3 Inicializando o projeto
bash mkdir my-observability-app && cd $_ npm init -y npm install express @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-prometheus
2. Configurando o OpenTelemetry
2.1 Arquivo de bootstrap (otel-config/otel-setup.js)
javascript // otel-config/otel-setup.js const { NodeSDK } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus'); const { diag, DiagConsoleLogger, DiagLogLevel } = require('@opentelemetry/api');
// Habilita logs de diagnóstico (útil em dev) diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
// Exporter que expõe métricas no endpoint /metrics const prometheusExporter = new PrometheusExporter({ startServer: true, port: 9464, endpoint: '/metrics', });
const sdk = new NodeSDK({ instrumentations: [getNodeAutoInstrumentations()], metricReader: prometheusExporter, });
sdk.start();
process.on('SIGTERM', () => { sdk.shutdown() .then(() => console.log('OpenTelemetry shut down')) .catch((error) => console.error('Error shutting down OpenTelemetry', error)) .finally(() => process.exit(0)); });
2.2 Integrando ao código da aplicação (src/index.js)
javascript // src/index.js require('dotenv').config(); require('../otel-config/otel-setup'); // <-- inicializa OpenTelemetry antes de tudo
const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000;
app.get('/health', (req, res) => { res.json({ status: 'ok' }); });
app.get('/slow', async (req, res) => { // Simula latência aleatória entre 200ms e 2s const delay = Math.floor(Math.random() * 1800) + 200; await new Promise((r) => setTimeout(r, delay)); res.json({ delayMs: delay }); });
app.listen(PORT, () => {
console.log(🚀 App rodando na porta ${PORT});
});
Importante: O
require('../otel-config/otel-setup')deve ser a primeira linha que executa código da aplicação, garantindo que todos os módulos sejam instrumentados.
3. Orquestrando com Docker‑Compose
3.1 docker-compose.yml
yaml version: '3.8' services: app: build: . ports: - "3000:3000" - "9464:9464" # porta do exporter Prometheus environment: - NODE_ENV=production depends_on: - prometheus
prometheus: image: prom/prometheus:latest volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml ports: - "9090:9090"
grafana: image: grafana/grafana:latest ports: - "3001:3000" depends_on: - prometheus environment: - GF_SECURITY_ADMIN_PASSWORD=admin volumes: - grafana-data:/var/lib/grafana
volumes: grafana-data:
3.2 Configuração do Prometheus (prometheus.yml)
yaml global: scrape_interval: 15s
scrape_configs:
- job_name: 'node_app'
static_configs:
- targets: ['app:9464']
3.3 Dockerfile
dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 9464 CMD ["node", "src/index.js"]
Com tudo configurado, basta executar:
bash docker-compose up --build
A aplicação ficará disponível em http://localhost:3000, o endpoint de métricas em http://localhost:9464/metrics e o Prometheus em http://localhost:9090.
4. Visualizando métricas no Grafana
- Acesse
http://localhost:3001(login: admin / admin). - Adicione um Data Source → Prometheus → URL:
http://prometheus:9090→ Save & Test. - Crie um Dashboard → Add Panel → escolha a métrica
process_cpu_seconds_totalouhttp_server_requests_duration_seconds. - Salve o painel e explore: você verá o número de requisições, latência média, uso de CPU e memória da aplicação Node.js.
4.1 Painel de latência das rotas
promql
Latência média da rota /slow em segundos
histogram_quantile(0.95, sum(rate(http_server_requests_duration_seconds_bucket{handler="/slow"}[5m])) by (le))
Esse query exibe o 95º percentil da latência nos últimos 5 minutos, permitindo identificar picos de resposta lenta.
5. Boas práticas e próximos passos
- Instrumentação manual: embora o auto‑instrumentation cubra a maioria dos casos, você pode criar spans customizados com
api.trace.getTracer('my-app')para rastrear fluxos de negócio críticos. - Logs estruturados: combine traces com logs usando o OpenTelemetry Logging SDK ou ferramentas como Elastic Stack.
- Alertas: configure alertas no Grafana (ou Alertmanager) para disparar notificações quando a latência ultrapassar limites definidos.
- CI/CD: inclua testes de performance que validem métricas básicas (ex.: tempo médio < 300 ms) antes de promover para produção.
- Escalabilidade: ao escalar horizontalmente, garanta que cada instância exponha seu próprio endpoint
/metrics; o Prometheus agregará automaticamente.
Conclusão
Implementar observabilidade com OpenTelemetry, Prometheus e Grafana em uma aplicação Node.js não precisa ser complexo. Com poucos arquivos de configuração, você ganha visibilidade completa sobre métricas, traces e, futuramente, logs. Essa camada de insight reduz o MTTR (Mean Time to Recovery), melhora a experiência do usuário e fornece dados valiosos para otimizações de performance.
Próximos passos recomendados:
- Adicionar tracing: exporte spans para o Jaeger ou Tempo e correlacione com os dashboards Grafana.
- Integrar ao GitHub Actions: execute
docker-compose upem pipelines de teste para validar a coleta de métricas. - Explorar OpenTelemetry Collector: centralize dados de múltiplas aplicações e envie para destinos como Loki, Datadog ou Splunk.
A observabilidade está se tornando o novo “monitoramento”. Comece hoje, experimente os exemplos acima e evolua seu stack conforme a necessidade do negócio.


