<h2>O que é OpenTelemetry e por que usar com AWS Distro</h2>
<p>OpenTelemetry é um padrão aberto e agnóstico de fornecedor para coleta de telemetria (traces, métricas e logs). O AWS Distro for OpenTelemetry (ADOT) é a distribuição mantida pela Amazon com componentes otimizados nativamente para a plataforma AWS. A grande vantagem é a portabilidade: você escreve uma única instrumentação que funciona em qualquer lugar — desenvolvimento local, Kubernetes, Lambda, EC2 — sem lock-in de vendor. Com ADOT, você ativa observabilidade sem reescrever código quando migra entre ambientes.</p>
<p>A arquitetura segue um padrão simples: sua aplicação envia telemetria para um coletor local (ou remoto), que processa, enriquece e exporta para backends AWS como X-Ray, CloudWatch e Prometheus. Isso reduz complexidade e custos comparado a múltiplas SDKs proprietárias.</p>
<h2>Instrumentação Prática com Node.js</h2>
<h3>Instalação e configuração básica</h3>
<p>Comece instalando as dependências essenciais para Node.js. O pacote principal fornece a API, enquanto os instrumentos detectam automaticamente bibliotecas populares como Express, HTTP e banco de dados.</p>
<pre><code class="language-bash">npm install @opentelemetry/api \
@opentelemetry/sdk-node \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/exporter-trace-otlp-http \
@opentelemetry/sdk-trace-node \
@opentelemetry/resources \
@opentelemetry/semantic-conventions</code></pre>
<p>Crie um arquivo <code>instrumentation.js</code> que deve ser carregado <strong>antes</strong> de qualquer outro código:</p>
<pre><code class="language-javascript">const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const resource = Resource.default().merge(
new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'minha-app',
[SemanticResourceAttributes.SERVICE_VERSION]: '1.0.0',
environment: 'production'
})
);
const traceExporter = new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || 'http://localhost:4317'
});
const sdk = new NodeSDK({
resource,
traceExporter,
instrumentations: [getNodeAutoInstrumentations()]
});
sdk.start();
console.log('OpenTelemetry iniciado');
process.on('SIGTERM', () => {
sdk.shutdown()
.then(() => process.exit(0))
.catch(err => process.exit(1));
});</code></pre>
<p>Execute sua aplicação com este arquivo carregado primeiro:</p>
<pre><code class="language-bash">node -r ./instrumentation.js app.js</code></pre>
<h3>Spans customizados</h3>
<p>Para adicionar contexto específico do negócio, crie spans manualmente:</p>
<pre><code class="language-javascript">const { trace } = require('@opentelemetry/api');
const tracer = trace.getTracer('meu-modulo', '1.0.0');
app.get('/api/usuarios/:id', async (req, res) => {
const span = tracer.startSpan('buscar-usuario');
try {
span.setAttributes({
'usuario.id': req.params.id,
'http.method': 'GET'
});
const usuario = await db.usuarios.findById(req.params.id);
span.addEvent('usuario-encontrado', { 'db.rows': 1 });
res.json(usuario);
} catch (error) {
span.recordException(error);
span.setStatus({ code: 2 }); // ERROR
res.status(500).json({ erro: 'Falha ao buscar usuário' });
} finally {
span.end();
}
});</code></pre>
<h2>Deployment no AWS com ADOT Collector</h2>
<h3>Configuração do Coletor</h3>
<p>O ADOT Collector recebe traces da sua aplicação e os envia aos serviços AWS. Crie um arquivo <code>otel-collector-config.yaml</code>:</p>
<pre><code class="language-yaml">receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
batch:
timeout: 10s
send_batch_size: 1024
memory_limiter:
check_interval: 5s
limit_mib: 512
exporters:
awsxray:
region: us-east-1
awsemf:
namespace: MinhaApp
log_group_name: /aws/otel/minhaapp
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [awsxray]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [awsemf]</code></pre>
<h3>ECS/Fargate com ADOT</h3>
<p>Adicione um container sidecar de coletor à sua task definition (JSON):</p>
<pre><code class="language-json">{
"name": "aws-otel-collector",
"image": "public.ecr.aws/aws-observability/aws-for-opentelemetry-collector:latest",
"portMappings": [
{
"containerPort": 4317,
"protocol": "tcp"
}
],
"environment": [
{
"name": "AWS_REGION",
"value": "us-east-1"
}
],
"mountPoints": [
{
"sourceVolume": "otel-config",
"containerPath": "/etc/ot-collector-config.yaml"
}
]
}</code></pre>
<p>Na sua aplicação Node.js, configure o endpoint para apontar ao coletor:</p>
<pre><code class="language-bash">export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317</code></pre>
<h2>Observabilidade End-to-End: Da Aplicação ao X-Ray</h2>
<h3>Visualização de Traces no X-Ray</h3>
<p>Após configurar a exportação, os traces aparecerão no console X-Ray da AWS. O CloudWatch também receberá métricas automaticamente graças ao EMF Exporter. A correlação entre logs, traces e métricas acontece via trace ID:</p>
<pre><code class="language-javascript">const { context, trace } = require('@opentelemetry/api');
app.use((req, res, next) => {
const span = trace.getActiveSpan();
if (span) {
const traceId = span.spanContext().traceId;
// Injete em logs estruturados
res.locals.traceId = traceId;
}
next();
});
// Nos seus logs estruturados:
console.log(JSON.stringify({
message: 'Processamento iniciado',
traceId: res.locals.traceId,
timestamp: new Date().toISOString()
}));</code></pre>
<h3>Análise e Troubleshooting</h3>
<p>No console X-Ray, procure por erros usando filtros como:</p>
<ul>
<li><code>service("minha-app") AND error</code> — traces com exceções</li>
<li><code>annotations.usuario.id = "123"</code> — busque por atributos customizados</li>
<li><code>duration > 1</code> — identifique operações lentas</li>
</ul>
<p>A latência é quebrada automaticamente em cada span, mostrando exatamente qual chamada consumiu tempo.</p>
<h2>Conclusão</h2>
<p>OpenTelemetry com ADOT oferece três benefícios imediatos: <strong>portabilidade</strong> (mesma instrumentação em todo lugar), <strong>padronização</strong> (não depende de APIs AWS específicas) e <strong>custo-benefício</strong> (sem duplicação de SDKs). Comece simples com auto-instrumentação, adicione spans customizados conforme necessário e escale o coletor conforme o volume de traces cresce. A maioria dos problemas de produção se resolve mais rápido quando você consegue visualizar a jornada completa de uma requisição através de seus sistemas.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://aws-otel.github.io/" target="_blank" rel="noopener noreferrer">AWS Distro for OpenTelemetry - Documentação Oficial</a></li>
<li><a href="https://opentelemetry.io/docs/" target="_blank" rel="noopener noreferrer">OpenTelemetry - Especificação e SDKs</a></li>
<li><a href="https://aws-otel.github.io/docs/getting-started/collector/" target="_blank" rel="noopener noreferrer">ADOT Collector Configuration Guide</a></li>
<li><a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-instrumenting-your-application.html" target="_blank" rel="noopener noreferrer">AWS X-Ray Integration with ADOT</a></li>
<li><a href="https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/auto-instrumentations-node" target="_blank" rel="noopener noreferrer">Node.js Auto-Instrumentation</a></li>
</ul>