Observabilidade
Um sistema que você não consegue observar é um sistema que você não consegue operar. O monitoramento diz que algo está errado; a observabilidade diz por quê. A distinção importa em microsserviços: uma requisição que passa por oito serviços e três bancos de dados não pode ser diagnosticada a partir de uma única métrica em um único dashboard. Observabilidade é a propriedade de um sistema que permite inferir seu estado interno a partir de suas saídas externas.
Imagine um cliente reclamando que "o checkout está lento" na loja. A requisição passou pelo Nginx, pelo gateway, pela verificação de autenticação, pelo serviço de pedidos, pelo serviço de produtos e pelo Postgres, e talvez tenha publicado um evento no Kafka. Qual deles foi lento? Foi lento para todo mundo ou só para esse cliente? Sem telemetria projetada de antemão — números, registros e caminhos de requisição emitidos por cada serviço —, a única resposta é chutar.
Objetivos de aprendizagem
Ao final desta aula, você deve ser capaz de:
- Explicar a diferença entre monitoramento e observabilidade, e qual pergunta cada pilar (métricas, logs, traces) responde.
- Escrever consultas PromQL para a taxa de requisições, a proporção de erros e os percentis de latência de um serviço Spring Boot, e construir dashboards RED / USE.
- Configurar logs estruturados que carregam o trace ID e correlacionar uma linha de log com seu trace.
- Explicar como o contexto de rastreamento atravessa os serviços com o cabeçalho W3C
traceparente escolher uma estratégia de amostragem. - Instrumentar um serviço Spring Boot com OpenTelemetry (agente Java e spans manuais) e projetar alertas baseados em sintomas.
Slides
Clique nos slides e use ← → para navegar; F abre em tela cheia e P abre a visão do apresentador, com as notas. Abrir os slides em uma nova aba
Os três pilares
A observabilidade se apoia em três tipos de dados complementares. Cada um responde a uma pergunta diferente sobre o comportamento do sistema.
| Pilar | Responde | Ferramentas | Retenção |
|---|---|---|---|
| Métricas | O sistema está saudável agora? A tendência é de alta ou de queda? | Prometheus → Grafana | Semanas a meses (agregadas) |
| Logs | O que exatamente aconteceu, e em que sequência? | ELK / EFK / Loki | Dias a semanas |
| Traces | Qual serviço desta requisição foi lento? Onde o erro se originou? | Jaeger / Tempo / Zipkin | Dias |
Os três descrevem os mesmos eventos sob ângulos diferentes. Um POST /orders que falha produz: um incremento de um contador http_server_requests_seconds_count{status="500"} (métrica), uma linha JSON {"level":"ERROR","msg":"product not found",...} (log) e um trace com um span por salto, o último marcado como ERROR (trace). Métricas são baratas e dizem que algo mudou; logs e traces são mais caros e dizem o quê e onde.
Observabilidade ≠ Monitoramento
O monitoramento faz perguntas predefinidas: "A taxa de erros está abaixo de 1%?" A observabilidade permite fazer perguntas em que você não pensou na fase de projeto: "Por que exatamente 7% das requisições de clientes móveis em São Paulo estão dando timeout numa terça-feira?" A observabilidade exige os três pilares funcionando juntos2.
Métricas
Modelo de dados do Prometheus
Toda série temporal tem um nome de métrica e um conjunto de labels chave-valor:
| Tipo | O que mede | Exemplo |
|---|---|---|
| Counter | Valor monotonicamente crescente; nunca diminui | http_requests_total, errors_total |
| Gauge | Valor atual, que pode subir ou descer | memory_bytes, active_connections |
| Histogram | Distribuição de valores em buckets configuráveis | http_request_duration_seconds{le="0.1"} |
| Summary | Quantis pré-calculados (menos flexível que o histogram) | http_request_duration_seconds{quantile="0.99"} |
Um label é uma dimensão da série: cada combinação distinta de valores de labels é uma série temporal separada armazenada pelo Prometheus.
Noções básicas de PromQL
PromQL é a linguagem de consulta do Prometheus. As consultas abaixo usam a métrica que o Spring Boot (Micrometer) exporta para cada endpoint HTTP, http_server_requests_seconds, com os labels application, uri, method e status:
| Consulta | Significado |
|---|---|
rate(http_server_requests_seconds_count[5m]) | Requisições por segundo, em média nos últimos 5 minutos |
sum by (application) (rate(http_server_requests_seconds_count{status=~"5.."}[5m])) | Erros 5xx por segundo, por serviço |
sum(rate(http_server_requests_seconds_count{status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_count[5m])) | Proporção de erros (0–1) — a base de um SLI de disponibilidade |
histogram_quantile(0.99, sum by (le) (rate(http_server_requests_seconds_bucket[5m]))) | Latência P99 considerando todas as instâncias |
increase(http_server_requests_seconds_count[1h]) | Total de requisições na última hora |
Duas regras: aplique rate() ou increase() a um counter antes de somar (essas funções tratam os zeramentos do contador quando um pod reinicia) e mantenha o label le ao somar os buckets de um histogram (sum by (le)), porque o histogram_quantile precisa dele. As séries _bucket só existem se os histogramas estiverem habilitados: management.metrics.distribution.percentiles-histogram.http.server.requests=true.
Por que percentis, e não médias
Se 99 requisições levam 50 ms e 1 leva 5 s, a média é ~100 ms — parece ótimo, mas um em cada cem usuários espera 5 segundos. O P99 (o valor abaixo do qual estão 99% das requisições) expõe essa cauda; com muitas chamadas por página, a maioria dos usuários cai na cauda em algum momento.
RED, USE e os Golden Signals
| Método | Para | Métricas |
|---|---|---|
| RED (Tom Wilkie) | Serviços / APIs | Rate (requisições/s), Errors (taxa de erros), Duration (percentis de latência) |
| USE (Brendan Gregg) | Infraestrutura / Recursos | Utilisation (% ocupado), Saturation (tamanho da fila), Errors |
| Quatro golden signals (Google SRE1) | Qualquer sistema voltado ao usuário | Latência, Tráfego, Erros, Saturação |
Qual método usar?
Use RED para dashboards no nível do serviço (o que os usuários experimentam) e USE para dashboards de infraestrutura (o que os recursos experimentam). Os dois juntos dão cobertura completa.
Pipeline de métricas
flowchart LR
app["Spring Boot\n(Actuator + Micrometer)"]
prom["Prometheus"]
grafana["Grafana\n(dashboards + alertas)"]
prom -->|"coleta /actuator/prometheus (ex.: a cada 15 s)"| app
prom -->|"consultas PromQL"| grafana O Prometheus usa um modelo pull: a aplicação apenas expõe seus valores atuais em um endpoint HTTP, e o Prometheus os busca (faz o scrape) periodicamente e os armazena como séries temporais. É isso que o Hands-on 6 configura para a loja.
Configuração do Spring Boot Actuator para expor o endpoint do Prometheus (também é necessária a dependência io.micrometer:micrometer-registry-prometheus):
management:
endpoints:
web:
exposure:
include: health,info,prometheus
metrics:
tags:
application: ${spring.application.name}
Cardinalidade de labels
Nunca coloque valores ilimitados — ID de usuário, ID de pedido, e-mail, URL completa com IDs — em um label de métrica. Cada valor distinto cria uma nova série temporal; 100.000 usuários × 10 endpoints × 5 códigos de status são 5 milhões de séries, e o Prometheus fica sem memória. Detalhes de alta cardinalidade pertencem a logs e traces. (É por isso que o Spring Boot usa o template da URI, /orders/{id}, como label uri, e não /orders/42.)
Alertas
Dashboards precisam de alguém olhando para eles; alertas notificam uma pessoa quando é preciso agir. O Prometheus avalia regras de alerta e envia os alertas disparados ao Alertmanager (ou ao Grafana Alerting), que os encaminha para e-mail, Slack ou um pager.
groups:
- name: order-service
rules:
- alert: OrderHighErrorRatio
expr: |
sum(rate(http_server_requests_seconds_count{application="order", status=~"5.."}[5m]))
/
sum(rate(http_server_requests_seconds_count{application="order"}[5m])) > 0.05
for: 5m # must hold for 5 minutes, avoids flapping
labels:
severity: page
annotations:
summary: "More than 5% of order requests are failing"
Alerte sobre sintomas, não sobre causas
Acione pessoas pelo que os usuários sentem — proporção de erros, latência, um error budget de SLO sendo consumido rápido (veja SLI / SLO / SLA) — e não por "CPU acima de 80%". CPU alta com usuários satisfeitos não é emergência; um alerta que dispara sem exigir ação ensina as pessoas a ignorar alertas.
Logs
Estruturados vs não estruturados
| Não estruturado | Estruturado (JSON) | |
|---|---|---|
| Exemplo | 2024-01-15 ERROR Order 42 failed | {"level":"ERROR","orderId":42,"msg":"failed","traceId":"abc123"} |
| Pesquisável | Só com grep / regex | Consultas completas por campo |
| Agregável | Difícil | Fácil (Kibana, Loki) |
| Processável por máquina | Frágil | Confiável |
Níveis de log
| Nível | Uso |
|---|---|
| TRACE | Extremamente detalhado — cada entrada/saída de método. Nunca em produção. |
| DEBUG | Diagnóstico — valores de variáveis, pontos de decisão. Só em dev/staging. |
| INFO | Eventos significativos — inicialização, configuração carregada, requisição recebida |
| WARN | Algo inesperado, mas tratado — retry disparado, fallback usado |
| ERROR | Falha que exige atenção — exceção capturada, downstream inacessível |
Correlation IDs e MDC
Quando uma requisição passa por vários serviços, um ID compartilhado em todas as linhas de log — um correlation ID — permite reconstruir a sequência completa de chamadas buscando por esse único valor. Com rastreamento distribuído, o correlation ID natural é o trace ID.
Em Java, o lugar para colocá-lo é o MDC (Mapped Diagnostic Context) do SLF4J/Logback: um mapa de pares chave-valor por thread que o framework de logging pode imprimir em todas as linhas com %X{key}. Quem preenche o MDC depende de como o serviço é instrumentado:
Com o agente Java do OTel anexado (veja abaixo e o Hands-on 10), você não escreve nenhum código de MDC para o contexto de rastreamento. A instrumentação de Logback/Log4j do agente coloca trace_id, span_id e trace_flags ativos no MDC sempre que há um span corrente, e os remove em seguida. Você só referencia as chaves no padrão:
Sem o agente, as mesmas chaves podem ser preenchidas pela biblioteca opentelemetry-logback-mdc-1.0; o próprio Micrometer Tracing do Spring Boot preenche, em vez delas, as chaves traceId e spanId. Use os nomes de chave da ferramenta que você de fato executa.
MDC.put serve para contexto de negócio que nenhuma ferramenta tem como conhecer — o ID do cliente, o ID do pedido — ou para um correlation ID quando não há rastreamento nenhum. Sempre remova o que você colocou: as threads são reaproveitadas pelo pool do servidor, e uma chave esquecida vaza para os logs da próxima requisição.
O MDC é por thread
O MDC vive em um ThreadLocal. Trabalho entregue a outra thread (@Async, CompletableFuture, código reativo como o gateway WebFlux) não o enxerga, a menos que o contexto seja propagado; o agente do OTel faz isso para as bibliotecas que instrumenta, mas os seus próprios valores de MDC.put não são copiados automaticamente.
Pipeline de agregação de logs
flowchart LR
svc1["Serviço A\n(logs JSON → stdout)"]
svc2["Serviço B\n(logs JSON → stdout)"]
svc3["Serviço C\n(logs JSON → stdout)"]
collector["Filebeat / Fluentd\n(coletor)"]
elastic["Elasticsearch\n(indexação + armazenamento)"]
kibana["Kibana\n(busca + dashboards)"]
svc1 --> collector
svc2 --> collector
svc3 --> collector
collector --> elastic
elastic --> kibana Loki como alternativa mais leve
O Loki (Grafana Labs) indexa apenas labels, não o texto completo, o que o torna muito mais barato de operar do que o Elasticsearch. Se você já roda Prometheus e Grafana, adicionar o Loki dá agregação de logs sem nenhuma interface nova para aprender — todos os sinais ficam nos mesmos dashboards do Grafana.
Traces distribuídos
Anatomia de um trace
Um trace representa uma única requisição de ponta a ponta. Ele é composto de spans — um por operação (chamada de serviço, consulta ao banco, acesso ao cache etc.).
| Campo | Descrição | Exemplo |
|---|---|---|
traceId | ID globalmente único da requisição inteira (128 bits) | 4bf92f3577b34da6a3ce929d0e0e4736 |
spanId | ID único desta operação | 00f067aa0ba902b7 |
parentSpanId | Span que disparou este | a2fb4a1d1a96d312 |
name | Nome da operação | GET /orders/{id} |
startTime / duration | Quando começou e quanto tempo levou | 2024-01-15T10:30:00Z, 45ms |
status | OK / ERROR | ERROR |
attributes | Tags chave-valor | http.status_code=500, db.type=postgresql |
Cabeçalho W3C traceparent
O cabeçalho traceparent propaga o contexto de rastreamento entre fronteiras de serviço usando o formato version-traceId-parentSpanId-flags:
| Campo | Valor | Significado |
|---|---|---|
version | 00 | Versão da especificação W3C |
traceId | 4bf92f3577b34da6a3ce929d0e0e4736 | ID de trace globalmente único de 128 bits |
parentSpanId | 00f067aa0ba902b7 | ID de 64 bits do span que enviou esta requisição |
flags | 01 | Flag de amostragem (01 = amostrado) |
Em cada chamada downstream, um serviço mantém version, traceId e (normalmente) flags exatamente como recebidos, e substitui o campo parentSpanId pelo ID do seu próprio span corrente. É assim que o contexto de rastreamento atravessa as fronteiras de serviço sem que nenhum serviço precise entender o trace completo. O cabeçalho é definido pela recomendação W3C Trace Context5; o OpenTelemetry o usa por padrão.
Fluxo de uma requisição com spans
sequenceDiagram
autonumber
actor User as Usuário
participant GW as Gateway [span: raiz, 120ms]
participant OS as OrderService [span: filho, 95ms]
participant DB as PostgreSQL [span: folha, 40ms]
User->>+GW: GET /orders/42<br/>traceparent: 00-abc...-root-01
GW->>+OS: GET /orders/42<br/>traceparent: 00-abc...-gw_span-01
OS->>+DB: SELECT * FROM orders WHERE id=42
DB-->>-OS: dados da linha
OS-->>-GW: 200 OK (95ms)
GW-->>-User: 200 OK (120ms) Estratégias de amostragem
Registrar todos os spans de todas as requisições é caro em escala, então os sistemas de rastreamento guardam apenas uma amostra dos traces.
| Estratégia | Como | Trade-off |
|---|---|---|
| Head sampling | A decisão é tomada no primeiro span (por exemplo, manter 10% pelo trace ID: parentbased_traceidratio) e viaja nas flags do traceparent, então todos os serviços concordam | Barato e simples, mas cego: descarta também 90% dos raros traces de erro |
| Tail sampling | Todos os spans são enviados ao OTel Collector, que espera o trace ficar completo e então decide | Consegue manter todo trace de erro ou lento, mas o Collector precisa manter todos os spans em memória |
| Rate-limiting | Manter no máximo N traces por segundo | Custo previsível; num pico, a maioria dos traces é descartada |
Recomendação para produção
Head e tail sampling são aplicados em sequência, então um trace descartado no head nunca pode ser "resgatado" pelo tail. Para manter todo trace de erro, amostre 100% no head (ou uma proporção alta) nos serviços e deixe uma política de tail sampling no OTel Collector manter todos os traces com um span ERROR ou alta latência, mais uma pequena porcentagem (1–10%) dos normais. Se não puder usar tail sampling, uma proporção de 1–10% no head é um padrão razoável — aceitando que alguns traces de erro serão perdidos e que os logs deles serão sua alternativa.
OpenTelemetry (OTel)
O OpenTelemetry é o padrão da CNCF para gerar, coletar e exportar telemetria3. Ele substitui SDKs específicos de fornecedores (cliente Zipkin, cliente Jaeger etc.) por uma única API neutra, de modo que trocar de backend exige apenas uma mudança de configuração, não de código.
| Componente | Papel |
|---|---|
| API | Interfaces específicas de cada linguagem — Tracer, Meter, Logger |
| SDK | Implementação da API; inclui amostragem, envio em lotes, exporters |
| Collector | Processo independente que recebe, processa e exporta telemetria |
| Exporter | Adaptador de protocolo que envia os dados: OTLP (o padrão), Zipkin, Prometheus, console |
| OTLP | O OpenTelemetry Protocol, sobre gRPC (porta 4317) ou HTTP/protobuf (porta 4318); Jaeger, Tempo e a maioria dos fornecedores o aceitam nativamente |
flowchart LR
app["Aplicação\n(OTel SDK)"]
collector["OTel Collector"]
prom["Prometheus\n(métricas)"]
jaeger["Jaeger\n(traces)"]
loki["Loki\n(logs)"]
app -->|"OTLP (gRPC/HTTP)"| collector
collector --> prom
collector --> jaeger
collector --> loki Instrumentação Java sem código
O agente Java do OTel instrumenta o Spring Boot automaticamente por injeção de bytecode — sem nenhuma alteração de código.
# pin a version: "latest" makes builds unreproducible
ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.4.0/opentelemetry-javaagent.jar /app/opentelemetry-javaagent.jar
ENTRYPOINT ["java", \
"-javaagent:/app/opentelemetry-javaagent.jar", \
"-jar", "/app/app.jar"]
Configure o agente por variáveis de ambiente no Docker Compose:
environment:
OTEL_SERVICE_NAME: order-service
OTEL_EXPORTER_OTLP_PROTOCOL: grpc # agent 2.x defaults to http/protobuf (port 4318)
OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317
OTEL_METRICS_EXPORTER: none
OTEL_LOGS_EXPORTER: none
Combine o protocolo com a porta
Desde a versão 2.0, o agente Java envia OTLP sobre HTTP/protobuf por padrão, que escuta na porta 4318. Ou aponte-o para http://jaeger:4318, ou mantenha a porta 4317 e defina OTEL_EXPORTER_OTLP_PROTOCOL=grpc, como acima. Uma incompatibilidade não produz nenhum trace, apenas um erro de exportação no log do serviço.
Por que desabilitar os exporters de métricas/logs?
O agente Java pode exportar os três sinais via OTLP. Aqui desabilitamos métricas e logs porque o Prometheus já coleta as métricas via Actuator e o Loki (ou o ELK) cuida dos logs separadamente. Habilitar os três no agente duplicaria dados e inflaria os custos de armazenamento.
Spans manuais
Quando a instrumentação automática não tem granularidade suficiente — você quer ver quanto tempo levou o seu cálculo de preço, e não apenas as chamadas HTTP e SQL ao redor dele —, adicione spans personalizados. Adicione a dependência da API do OTel (sua versão é gerenciada pelo opentelemetry-bom, ou defina-a explicitamente):
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
</dependency>
A forma mais simples, com o agente anexado, é uma anotação (dependência io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations):
@WithSpan("calculateTotal")
public BigDecimal calculateTotal(@SpanAttribute("order.items") int items, ...) { ... }
Para ter controle total, crie o span você mesmo. O agente registra a instância global de OpenTelemetry, então obtenha o tracer a partir dela (ele não é um bean do Spring, a menos que você declare um):
private static final Tracer tracer =
GlobalOpenTelemetry.getTracer("store.order");
public Order processOrder(OrderRequest request) {
Span span = tracer.spanBuilder("processOrder").startSpan();
try (Scope scope = span.makeCurrent()) {
span.setAttribute("order.customerId", request.customerId());
// ... business logic
return order;
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getMessage());
throw e;
} finally {
span.end();
}
}
Stack unificada do Grafana (LGTM)
Loki + Grafana + Tempo + Mimir/Prometheus — a stack LGTM — reúne os três sinais de observabilidade em uma única interface. A grande vantagem é a correlação de sinais: você pode saltar de um pico em uma métrica para os traces que o causaram e daí para as linhas de log que o explicam, tudo sem sair do Grafana.
flowchart LR
app["Aplicação"]
prom["Prometheus\n(métricas)"]
loki["Loki\n(logs)"]
tempo["Tempo\n(traces)"]
grafana["Grafana"]
app --> prom
app --> loki
app --> tempo
prom --> grafana
loki --> grafana
tempo --> grafana Um fluxo típico de investigação: um alerta de métrica dispara no Grafana → clique em "View Traces" para abrir o trace correlacionado no Tempo → clique em um span para ver as linhas de log correlacionadas no Loki. Essa navegação entre sinais é o que separa uma plataforma de observabilidade de três ferramentas de monitoramento isoladas.
Métricas DORA
O DORA (DevOps Research and Assessment) identificou quatro métricas que predizem o desempenho na entrega de software e o desempenho organizacional4. Duas medem vazão (com que rapidez as mudanças fluem) e duas medem estabilidade (com que frequência as mudanças quebram algo e com que rapidez você se recupera). Equipes de desempenho elite pontuam bem nas quatro ao mesmo tempo — velocidade e estabilidade não são um trade-off.
| Métrica | Mede | Referência elite (State of DevOps 2024) |
|---|---|---|
| Deployment Frequency (frequência de deploy) | Com que frequência o código chega à produção | Sob demanda (vários deploys por dia) |
| Change Lead Time (lead time de mudanças) | Do commit até rodar em produção | Menos de um dia |
| Change Failure Rate (taxa de falha de mudanças) | % dos deploys que exigem correção ou rollback | ~5% |
| Failed Deployment Recovery Time (antes MTTR / tempo para restaurar o serviço) | Quanto tempo leva para se recuperar de um deploy com falha | Menos de uma hora |
DORA e observabilidade
As métricas DORA são, elas mesmas, telemetria. A frequência de deploy vem dos logs de CI/CD (Hands-on 4). O tempo de recuperação exige marcações precisas de início e fim dos incidentes, vindas do seu sistema de monitoramento. A Change Failure Rate exige correlacionar eventos de deploy com picos na taxa de erros. Você não consegue melhorar o que não consegue medir — e não consegue medir sem infraestrutura de observabilidade.
Retrato da observabilidade: simulação de um pico
O gráfico abaixo simula como os três pilares da observabilidade aparecem durante um pico de tráfego. O painel 1 mostra a taxa de requisições subindo bruscamente nos passos 10–12; o painel 2 mostra os eventos de erro concentrados na mesma janela; o painel 3 mostra as durações dos spans dos traces se alongando sob carga.
Os três painéis compartilham a mesma linha do tempo: o pico visível no painel 1 explica diretamente o agrupamento de erros no painel 2, e os dois explicam o alongamento das durações dos spans no painel 3. Sem os três pilares, você veria apenas uma parte do quadro.
Armadilhas comuns
- Registrar tudo em INFO (ou DEBUG em produção): o volume e o custo dos logs explodem, e as linhas úteis se afogam.
- Registrar segredos ou dados pessoais: senhas, JWTs, números de cartão e e-mails nunca devem chegar ao pipeline de logs.
- Labels de métrica ilimitados: IDs de usuário ou de pedido como labels derrubam o Prometheus — coloque-os em logs e traces.
- Propagação de contexto quebrada: um único serviço sem instrumentação (ou um proxy que descarta o
traceparent) parte cada trace em dois. - Alertar sobre causas, não sobre sintomas: dezenas de alertas de CPU e memória sobre os quais ninguém age escondem aquele que importa.
Conexões
- Hands-on 6 — Prometheus e Grafana para as métricas da loja.
- Hands-on 10 — agente Java do OpenTelemetry, Jaeger e
trace_idnos logs. - Confiabilidade e SLI / SLO / SLA — SLIs são consultas PromQL sobre essas métricas; os alertas de burn rate as usam.
- Arquitetura Orientada a Eventos — rastreamento através de tópicos do Kafka e monitoramento do consumer lag.
- Exercício: Gargalos — usar a observabilidade para descobrir onde a plataforma está lenta.
Pontos-chave
- O monitoramento responde a perguntas conhecidas; a observabilidade permite investigar perguntas novas a partir de métricas (que algo mudou), logs (o quê) e traces (onde).
- O Prometheus coleta
/actuator/prometheus; userate()em counters,histogram_quantilecomsum by (le)para percentis, e mantenha os labels com baixa cardinalidade. - Monte dashboards com RED (serviços) e USE (recursos); alerte sobre sintomas que os usuários sentem.
- Os logs devem ser estruturados e carregar o
trace_id— preenchido automaticamente pelo agente do OTel; useMDC.putsó para suas próprias chaves de negócio. - Um trace é uma árvore de spans ligados pelo
traceparent; o head sampling é barato, mas cego, e o tail sampling mantém os traces interessantes. - O OpenTelemetry é o padrão neutro em relação a fornecedores; meça o desempenho de entrega com as quatro métricas DORA.
-
BEYER, B. et al. Site Reliability Engineering: How Google Runs Production Systems. O'Reilly, 2016. ↩
-
MAJORS, C.; FONG-JONES, L.; MIRANDA, G. Observability Engineering. O'Reilly, 2022. ↩
-
OPENTELEMETRY. opentelemetry.io — especificação, SDKs, Collector. ↩
-
FORSGREN, N.; HUMBLE, J.; KIM, G. Accelerate: The Science of Lean Software and DevOps. IT Revolution, 2018. Veja também os relatórios anuais DORA State of DevOps. ↩
-
W3C. Trace Context. W3C Recommendation. ↩