Observabilidade e Instrumentação

Instrumenta o código para que o comportamento em produção seja visível e diagnosticável. Use ao adicionar logging, métricas, tracing ou alertas. Use ao enviar qualquer funcionalidade que rode em produção e você precise de evidências de que funciona. Use quando problemas em produção são reportados, mas você não consegue descobrir o que aconteceu a partir dos dados disponíveis.

O que é Observabilidade e Instrumentação?

Este skill fornece um guia completo para adicionar observabilidade e instrumentação a sistemas em produção. Ele cobre desde a definição de perguntas-chave que um engenheiro de plantão faria, até a implementação de logs estruturados, métricas (RED/USE), tracing distribuído com OpenTelemetry e criação de alertas eficazes. A ênfase está em criar telemetria proposital e acionável, evitando ruído e armadilhas comuns como logs não estruturados, métricas com alta cardinalidade ou alertas baseados em causa, não em sintoma. O skill é agnóstico de plataforma, adequado para engenheiros de software, SREs e desenvolvedores que constroem e operam serviços, destacando a importância de instrumentar junto com o código, não depois.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/addyosmani/agent-skills/tree/main/skills/observability-and-instrumentation

Installed? Explore more Programação e Desenvolvimento skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que Observabilidade e Instrumentação faz?

Visão Geral

Código que você não pode observar é código que você não pode operar. Observabilidade é a capacidade de responder "o que o sistema está fazendo e por quê?" de fora, usando a telemetria que o código emite. Instrumentação não é um complemento pós-lançamento — é escrita junto com a funcionalidade, da mesma forma que os testes. Se uma funcionalidade for lançada sem telemetria, o primeiro bug relatado pelo usuário se torna uma arqueologia em vez de uma consulta.

Quando Usar

  • Construir qualquer funcionalidade que será executada em produção
  • Adicionar um novo serviço, endpoint, job em segundo plano ou integração externa
  • Um incidente de produção demorou muito para diagnosticar ("não conseguimos descobrir o que aconteceu")
  • Configurar ou revisar regras de alerta
  • Revisar um PR que adiciona E/S, retentativas, filas ou chamadas entre serviços

NÃO para:

  • Diagnosticar uma falha acontecendo agora — use o skill debugging-and-error-recovery (observabilidade é o que torna esse skill rápido na próxima vez)
  • Perfilamento e otimização de lentidão medida — use o skill performance-optimization
  • Checklists de monitoramento de lançamento e gatilhos de rollback — veja o skill shipping-and-launch; este skill cobre a instrumentação que os alimenta

Processo

1. Defina "funcionando" antes de instrumentar

Telemetria sem uma pergunta é ruído. Antes de adicionar qualquer instrumentação, escreva de 2 a 4 perguntas que um engenheiro de plantão fará sobre esta funcionalidade:

FUNCIONALIDADE: retentativa de pagamento no checkout
PERGUNTAS QUE O PLANTÃO FARÁ:
1. Qual fração de pagamentos é bem-sucedida na primeira tentativa versus após retentativas?
2. Quando um pagamento falha permanentemente, por quê? (erro do provedor? tempo limite? validação?)
3. O provedor de pagamento está mais lento que o normal?
→ Cada sinal abaixo deve ajudar a responder uma destas.

Se você não consegue nomear as perguntas, não está pronto para instrumentar — você registrará tudo e não aprenderá nada.

2. Escolha o sinal certo para cada pergunta

SinalRespostasPerfil de custoExemplo
Log estruturado"O que aconteceu neste caso específico?"Por evento; cresce com o tráfegopayment_failed com código de erro do provedor
Métrica"Com que frequência / rapidez, em agregado?"Fixo por série; barato para consultarp99 de latência de chamadas ao provedor
Trace"Onde o tempo foi gasto entre serviços?"Por requisição; geralmente amostradoUm checkout lento, detalhado por salto

Regra geral: métricas dizem que algo está errado, traces dizem onde, logs dizem por quê.

3. Logs estruturados

Registre eventos, não prosa. Cada linha de log é um objeto JSON com um nome de evento estável e campos legíveis por máquina:

// RUIM: interpolação de string — não consultável, inconsistente
logger.info(`Pagamento ${id} falhou para o usuário ${userId} após ${n} retentativas`);

// BOM: nome de evento estável + campos estruturados
logger.warn({
  event: 'payment_failed',
  paymentId: id,
  provider: 'stripe',
  errorCode: err.code,
  attempt: n,
}, 'pagamento falhou');

Níveis de log — use-os consistentemente:

NívelSignificadoAção do plantão
errorInvariante quebrada; alguém pode precisar agirInvestigar
warnDegradado, mas tratado (retentativa bem-sucedida, fallback usado)Observar tendências
infoEvento de negócio significativo (pedido realizado, job concluído)Nenhuma
debugDetalhe de diagnósticoDesativado em produção por padrão

IDs de correlação são obrigatórios. Gere (ou aceite) um ID de requisição no limite do sistema e anexe-o a cada linha de log, span e chamada de saída. Sem ele, você não pode reconstruir uma única requisição a partir de logs intercalados:

// Express: logger filho por requisição, ID propagado downstream
app.use((req, res, next) => {
  req.id = req.headers['x-request-id'] ?? crypto.randomUUID();
  req.log = logger.child({ requestId: req.id });
  res.setHeader('x-request-id', req.id);
  next();
});

Quando vários pontos de entrada escrevem em um único log, nomeie o ponto de entrada. Um ID de correlação identifica uma execução; ele não diz qual caminho de código a iniciou. O mesmo job alcançado por um agendador, por um endpoint de replay e por uma execução manual de CLI produz linhas intercambiáveis em um único coletor, então atribuir uma linha recai na eliminação — cruzar o histórico do agendador, a tabela de processos, um log de implantação — e esse argumento só é válido enquanto esses registros externos ainda existirem. Rotule o ponto de entrada onde a execução começa, ao lado do ID de correlação, e propague ambos da mesma forma:

// Um helper para cada ponto de entrada: o próprio logger da execução carrega ambos os campos.
// `entryPoint`, não `source` — ECS reserva `source.*` para campos de rede.
export const runLog = (entryPoint: 'scheduler' | 'replay_endpoint' | 'cli', runId: string) =>
  logger.child({ entryPoint, requestId: runId });

// tick do agendador        -> runLog('scheduler', crypto.randomUUID())
// POST /jobs/:id/replay -> runLog('replay_endpoint', req.id)
// invocação CLI          -> runLog('cli', process.env.RUN_ID ?? crypto.randomUUID())

Ambos os campos devem cruzar os mesmos limites que o ID de correlação — metadados de fila, cabeçalhos HTTP — ou um trabalhador redescobre o ponto de entrada e adivinha. Um campo que meramente se correlaciona com um ponto de entrada é uma dica, não uma atribuição: qualquer coisa que possa invocar o job pode reproduzi-lo.

Nunca registre segredos, tokens, senhas ou PII completa. Esta é uma regra rígida do skill security-and-hardening — pipelines de telemetria são um caminho clássico de vazamento de dados. Use uma lista de permissões de campos; não registre corpos de requisição inteiros.

4. Métricas

Para serviços orientados a requisições, instrumente RED em cada endpoint e cada dependência externa: Rate (requisições/s), Errors (taxa de falha), Duration (histograma de latência, não média). Para recursos (filas, pools, hosts), use USE: Utilization, Saturation, Errors.

Assim como com tracing, o caminho neutro de fornecedor é a API de métricas do OpenTelemetry (mesmo SDK e contexto da etapa 5). O exemplo abaixo usa prom-client do Prometheus — uma escolha comum de backend, não a única; as regras de RED/USE e cardinalidade são idênticas de qualquer forma.

import { Histogram } from 'prom-client';

const httpDuration = new Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duração da requisição HTTP',
  labelNames: ['method', 'route', 'status_class'],  // '2xx', não '200'
  buckets: [0.05, 0.1, 0.25, 0.5, 1, 2.5, 5],
});

Cardinalidade é o modo de falha. Cada combinação única de rótulos é uma série temporal separada. Rótulos devem vir de conjuntos pequenos e fixos (template de rota, classe de status, nome do provedor). Nunca use IDs de usuário, URLs brutas, mensagens de erro ou outros valores ilimitados como rótulos — isso pertence a logs e traces.

OK como rótulo:    route="/api/tasks/:id"   status_class="5xx"   provider="stripe"
NUNCA um rótulo:  user_id, email, request_id, URL completa, texto de mensagem de erro

Nunca acompanhe médias, sempre percentis: uma média esconde os 1% de usuários que estão tendo uma experiência terrível. Use histogramas e leia p50/p95/p99.

5. Tracing distribuído

Use OpenTelemetry — é o padrão neutro de fornecedor, e a auto-instrumentação cobre HTTP, gRPC e clientes de banco de dados comuns com código quase zero:

// tracing.ts — deve ser importado antes de qualquer outra coisa
import { NodeSDK } from '@opentelemetry/sdk-node';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  serviceName: 'checkout-service',
  instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

Adicione spans manuais apenas em torno de unidades de trabalho internas significativas (por exemplo, applyDiscounts, chargeProvider) e anexe os atributos pelos quais o plantão filtrará. Propague o contexto através de cada limite assíncrono — cabeçalhos HTTP, metadados de mensagens de fila — ou o trace morre na lacuna. Amostre com base na cabeça a uma taxa baixa por padrão; mantenha 100% dos erros se seu backend suportar amostragem de cauda.

6. Alertas

Alerta sobre sintomas que os usuários sentem, não sobre causas:

SINTOMA (pagina):                         CAUSA (dashboard, não uma página):
taxa de erro > 1% por 5 min               CPU a 85%
latência p99 > 2s                         um pod reiniciou
idade da fila > 10 min                    disco a 70%

Alertas baseados em causa disparam quando nada está errado e perdem falhas que você não previu. Alertas baseados em sintoma disparam exatamente quando os usuários são prejudicados, independentemente da causa.

Regras para cada alerta que você criar:

  1. Deve ser acionável. Se a resposta for "ignorar, ele se cura sozinho", exclua o alerta.
  2. Ele vincula a um runbook — mesmo três linhas: o que significa, primeira consulta a executar, caminho de escalação.
  3. Tem um limite e duração justificados pelo SLO ou por dados históricos, não por um palpite.
  4. Use apenas duas severidades: página (voltado para o usuário, aja agora) e ticket (degradação, aja esta semana). Um terceiro nível se torna ruído que treina as pessoas a ignorar tudo.

Escrevendo Runbooks

A regra 2 acima exige que cada alerta vincule a um runbook. O trabalho de um runbook é responder a três perguntas sem exigir que o leitor pense: o que está acontecendo, o que verificar primeiro e para quem ligar se isso não resolver. Armazene em docs/runbooks/ nomeado conforme o alerta.

Runbook mínimo viável (três linhas):

# Runbook: Alta Taxa de Erro em /api/tasks
**Significa:** Pool de conexões de BD provavelmente esgotado ou uma implantação ruim.
**Primeira verificação:** `SELECT count(*) FROM pg_stat_activity WHERE backend_type = 'client backend';`
  — se contagem > limite do pool, veja Passo 2. (Substitua pelo equivalente do seu banco de dados.)
**Escalar para:** #db-oncall ou a rotação de plantão de engenharia.

Quando expandir além de três linhas: adicione etapas apenas quando a primeira verificação sozinha não for suficiente para decidir. Um runbook de cinco etapas que cobre as três causas mais comuns é melhor do que um documento de vinte etapas que cobre cada caso extremo e é lido superficialmente.

Mantenha os runbooks atualizados. Atualize o runbook como parte do fechamento de cada incidente em que foi usado — um runbook desatualizado gera falsa confiança. Se uma etapa estava errada ou faltando, corrija-a antes de marcar o incidente como resolvido.

7. Verifique a própria telemetria

Instrumentação é código; pode estar errada. Antes de considerar o trabalho concluído, acione os caminhos e veja a saída real:

  • Force um erro em staging → encontre-o nos logs por requestId, confirme que os campos são estruturados (não [object Object])
  • Envie tráfego de teste → confirme que as séries de métricas aparecem com os rótulos esperados e valores sensatos
  • Siga uma requisição entre serviços na interface de tracing → sem spans quebrados
  • Dispare cada novo alerta uma vez (abaixe o limite temporariamente) → confirme que ele atinge o canal certo e o link do runbook funciona

Racionalizações Comuns

RacionalizaçãoRealidade
"Adicionarei logging depois que funcionar""Depois" se torna "depois do primeiro incidente", que é o momento mais caro para descobrir que você está cego. Instrumente enquanto constrói.
"Mais logs = mais observabilidade"Ruído não estruturado torna incidentes mais lentos, não mais rápidos. Três eventos consultáveis vencem trezentas linhas de prosa.
"console.log serve por enquanto"Saída não estruturada não pode ser filtrada, correlacionada ou alertada. O logger estruturado custa cinco minutos extras uma vez.
"Podemos apenas olhar os dashboards quando algo quebrar"Dashboards construídos sem perguntas definidas mostram tudo, exceto a resposta. Comece com as perguntas do plantão.
"Alerta sobre tudo importante, ajustaremos depois"Um pager barulhento treina as pessoas a ignorá-lo. O ajuste nunca acontece; a página real perdida, sim.
"ID do usuário como um rótulo de métrica facilita a depuração"Também faz seu backend de métricas cair. Consultas de alta cardinalidade pertencem a logs e traces.
"Tracing é exagero para nossos dois serviços"Dois serviços já significam perguntas de latência entre serviços que logs não podem responder. Auto-instrumentação torna o custo trivial.

Bandeiras Vermelhas

  • Um PR de funcionalidade com retentativas, filas ou chamadas externas e zero nova telemetria
  • Linhas de log construídas por interpolação de string em vez de campos estruturados
  • Nenhum ID de correlação/requisição — cada linha de log é um órfão
  • Um fluxo de log alimentado por um agendador, um webhook e execuções manuais, sem campo nomeando qual produziu a linha
  • Métricas rotuladas com IDs de usuário, URLs brutas ou texto de mensagem de erro (bomba de cardinalidade)
  • Latência rastreada como uma média sem percentis
  • Alertas que disparam diariamente e são reconhecidos sem ação
  • Alertas sobre causas (CPU, memória) paginando humanos enquanto a taxa de erro voltada para o usuário não é monitorada
  • Segredos, tokens ou corpos de requisição completos aparecendo em logs
  • "Funciona na minha máquina" como a única evidência de que uma funcionalidade em produção está saudável

Verificação

Após instrumentar uma funcionalidade, confirme:

  • As perguntas do plantão para esta funcionalidade estão escritas, e cada sinal mapeia para uma
  • Toda saída de log é estruturada (JSON), com nomes de evento estáveis e um ID de correlação em cada linha
  • Cada coletor de log escrito por mais de um ponto de entrada carrega um campo de ponto de entrada, definido onde a execução começa e propagado com o ID de correlação, em vez de inferido downstream
  • Nenhum segredo, token ou PII não redigido em nenhuma linha de log (verificação pontual da saída real)
  • Métricas RED existem para cada novo endpoint e cada dependência externa, com conjuntos de rótulos limitados
  • Latência é um histograma; p95/p99 são consultáveis
  • Uma única requisição pode ser seguida de ponta a ponta na interface de tracing sem spans quebrados
  • Cada novo alerta é baseado em sintoma, tem um link de runbook e foi disparado em teste uma vez
  • Uma falha induzida em staging foi localizada apenas por meio de telemetria, sem ler o código-fonte

Para a versão resumida desta lista, incluindo o gate de instrumentação pré-lançamento, veja ../../references/observability-checklist.md.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

addyosmani/agent-skills

Builds production-quality, accessible, responsive user-facing UIs. Use when building or modifying interfaces and pages, creating components, implementing layouts, meeting WCAG accessibility requirements, managing state, or when the output needs to look and feel production-quality rather than AI-generated.

addyosmani/agent-skills

Prepares production launches. Use when preparing to deploy to production, or when asking what needs to be in place before shipping. Use when you need a pre-launch checklist, when setting up monitoring, when planning a staged rollout, or when you need a rollback strategy.

addyosmani/agent-skills

Guides stable API and interface design. Use when designing APIs, module boundaries, or any public interface. Use when creating REST or GraphQL endpoints, defining type contracts between modules, or establishing boundaries between frontend and backend.

addyosmani/browser-testing-with-devtools

Tests in real browsers via Chrome DevTools MCP. Use when building or debugging anything that runs in a browser. Use when you need to inspect the DOM, capture console errors, analyze network requests, profile performance, or verify visual output with real runtime data. Requires the chrome-devtools MCP server to be configured.

addyosmani/ci-cd-and-automation

Automates CI/CD pipeline setup. Use when setting up or modifying build and deployment pipelines. Use when you need to automate quality gates, configure test runners in CI, or establish deployment strategies.

addyosmani/code-review-and-quality

Conducts multi-axis code review. Use before merging any change. Use when reviewing code written by yourself, another agent, or a human. Use when you need to assess code quality across multiple dimensions before it enters the main branch.

addyosmani/code-simplification

Simplifies code for clarity. Use when refactoring code for clarity without changing behavior. Use when code works but is harder to read, maintain, or extend than it should be. Use when reviewing code that has accumulated unnecessary complexity.

addyosmani/constraint-driven-development

Establishes a project's quality bar as a written contract and stops agents quietly lowering it. Interviews the user on which dimensions matter, supplies sane default thresholds when they have no number in mind, records everything in CONSTRAINTS.md, and watches the diff for a weakened bar — new @ts-ignore or eslint-disable suppressions, skipped or deleted tests, assertions stripped out, unimplemented stubs, thresholds edited down. Use when no quality bar is written down, when the user says "set up constraints" or "define our standards", when the user wants dimensions they care about — accessibility, web performance, coverage — set up as enforced constraints, when an agent keeps silencing checks or skipping tests to get to green, when you need a coverage or performance threshold and don't know what number to pick, or when an agent writes more code than anyone will read.

addyosmani/debugging-and-error-recovery

Guides systematic root-cause debugging. Use when tests fail, builds break, behavior doesn't match expectations, or you encounter any unexpected error. Use when you need a systematic approach to finding and fixing the root cause rather than guessing.

addyosmani/deprecation-and-migration

Manages deprecation and migration. Use when removing old systems, APIs, or features. Use when migrating users from one implementation to another. Use when deciding whether to maintain or sunset existing code.

addyosmani/documentation-and-adrs

Records decisions and documentation. Use when making architectural decisions, changing public APIs, shipping features, or when you need to record context that future engineers and agents will need to understand the codebase.

addyosmani/doubt-driven-development

Subjects every non-trivial decision to a fresh-context adversarial review before it stands. Use when correctness matters more than speed, when working in unfamiliar code, when stakes are high (production, security-sensitive logic, irreversible operations), or any time a confident output would be cheaper to verify now than to debug later.

addyosmani/git-workflow-and-versioning

Structures git workflow practices. Use when making any code change. Use when committing, branching, resolving conflicts, or when you need to organize work across multiple parallel streams.

addyosmani/idea-refine

Refines raw ideas into sharp, actionable concepts through structured divergent and convergent thinking. Use when an idea is still vague, when you need to stress-test assumptions before committing to a plan, or when you want to expand options before converging on one. Triggers on "ideate", "refine this idea", or "stress-test my plan".

addyosmani/incremental-implementation

Delivers changes incrementally. Use when implementing any feature or change that touches more than one file. Use when you're about to write a large amount of code at once, or when a task feels too big to land in one step.

addyosmani/interview-me

Extracts what the user actually wants instead of what they think they should want. Achieves this through one-question-at-a-time interview until ~95% confidence about the underlying intent. Use when an ask is underspecified ("build me X" without "for whom" or "why now"), when the user explicitly invokes ("interview me", "grill me", "are we sure?", "stress-test my thinking"), or when you catch yourself silently filling in ambiguous requirements before any plan, spec, or code exists.

addyosmani/performance-optimization

Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.

addyosmani/planning-and-task-breakdown

Breaks work into ordered tasks. Use when you have a spec or clear requirements and need to break work into implementable tasks. Use when a task feels too large to start, when you need to estimate scope, or when parallel work is possible.

addyosmani/security-and-hardening

Hardens code against vulnerabilities. Use when handling user input, authentication, data storage, or external integrations. Use when building any feature that accepts untrusted data, manages user sessions, or interacts with third-party services.

addyosmani/source-driven-development

Grounds every implementation decision in official documentation. Use when you want authoritative, source-cited code free from outdated patterns. Use when building with any framework or library where correctness matters.

Habilidades Relacionadas