[{"data":1,"prerenderedAt":3094},["ShallowReactive",2],{"article-\u002Finfraestrutura\u002Fobservabilidade-com-opentelemetry":3},{"id":4,"title":5,"author":6,"body":7,"category":3078,"date":3079,"description":3080,"extension":3081,"keywords":3082,"meta":3088,"navigation":1020,"path":3089,"seo":3090,"slug":3091,"stem":3092,"updated":3079,"__hash__":3093},"content\u002Finfraestrutura\u002Fobservabilidade-com-opentelemetry.md","Observabilidade com OpenTelemetry: guia para iniciantes","Inicialize Tec",{"type":8,"value":9,"toc":3033},"minimark",[10,15,92,95,99,116,135,159,171,176,192,209,211,215,218,228,237,324,334,336,340,343,363,366,370,447,455,457,461,485,489,492,500,511,515,518,539,550,554,626,628,632,638,649,653,663,669,705,722,728,734,738,749,755,762,764,768,778,781,811,822,826,902,909,911,915,922,927,958,1101,1111,1119,1121,1125,1132,1136,1144,1148,1285,1289,1296,1672,1676,1683,1791,1802,1806,1813,2038,2045,2326,2329,2348,2350,2354,2360,2367,2405,2409,2463,2478,2480,2484,2498,2508,2514,2593,2604,2669,2676,2678,2682,2686,2692,2709,2827,2831,2836,2850,2854,2859,2868,2872,2880,2885,2889,2898,2907,2911,2928,2947,2949,2953,2960,2963,2998,3005,3007,3011,3017,3020,3029],[11,12,14],"h2",{"id":13},"índice","Índice",[16,17,18,26,32,38,44,50,56,62,68,74,80,86],"ol",{},[19,20,21],"li",{},[22,23,25],"a",{"href":24},"#o-que-e","O que é observabilidade (e por que você deveria se importar)",[19,27,28],{},[22,29,31],{"href":30},"#monitoramento-vs","Monitoramento vs. observabilidade: a diferença que importa",[19,33,34],{},[22,35,37],{"href":36},"#tres-pilares","Os três pilares: logs, métricas e traces",[19,39,40],{},[22,41,43],{"href":42},"#opentelemetry","OpenTelemetry: o que é e por que existe",[19,45,46],{},[22,47,49],{"href":48},"#tracing","Tracing explicado com analogias",[19,51,52],{},[22,53,55],{"href":54},"#metricas","Métricas explicadas com analogias",[19,57,58],{},[22,59,61],{"href":60},"#logs","Logs explicados com analogias",[19,63,64],{},[22,65,67],{"href":66},"#fastapi","Mão na massa: instrumentando uma API FastAPI",[19,69,70],{},[22,71,73],{"href":72},"#jaeger","Visualizando traces no Jaeger",[19,75,76],{},[22,77,79],{"href":78},"#prometheus","Coletando métricas com Prometheus",[19,81,82],{},[22,83,85],{"href":84},"#erros","Erros comuns (e como evitá-los)",[19,87,88],{},[22,89,91],{"href":90},"#conclusao","Conclusão e próximos passos",[93,94],"hr",{},[11,96,98],{"id":97},"o-que-é-observabilidade-e-por-que-você-deveria-se-importar-o-que-e","O que é observabilidade (e por que você deveria se importar) {#o-que-e}",[100,101,102,103,107,108,111,112,115],"p",{},"Imagine que você dirige um carro. No painel, há alguns indicadores:\nmedidor de combustível, conta-giros, luz de temperatura do motor e a\nluzinha do óleo. Cada um desses indicadores te diz algo sobre o estado\ndo carro ",[104,105,106],"strong",{},"agora",". Mas se o carro enguiçar no meio da estrada, só olhar\no painel não resolve: você precisa abrir o capô, entender o que aconteceu\ne por que aconteceu. É aí que entra a diferença entre ",[104,109,110],{},"saber que algo\ndeu errado"," e ",[104,113,114],{},"entender por que deu errado",".",[100,117,118,121,122,126,127,130,131,134],{},[104,119,120],{},"Observabilidade"," é uma palavra emprestada da engenharia de controle\n(uma área da matemática que estuda sistemas dinâmicos). Em termos\nsimples: um sistema é ",[123,124,125],"em",{},"observável"," quando, apenas olhando para as\ninformações que ele emite para fora, você consegue deduzir o estado\ninterno dele sem precisar \"abrir a caixa\". Em software, isso significa:\nsua aplicação te dá dados suficientes para que você descubra ",[104,128,129],{},"por que","\nalgo deu errado, não apenas ",[104,132,133],{},"que"," deu errado.",[136,137,138],"blockquote",{},[100,139,140,143,144,146,147,150,151,154,155,158],{},[104,141,142],{},"Analogia rápida",": Monitorar é como ter um alarme de incêndio — ele\navisa quando o fogo já começou. Observabilidade é como ter sensores de\nfumaça, temperatura, umidade e um histórico de manutenção do prédio\ninteiros — você entende não só ",[123,145,133],{}," pegou fogo, mas ",[123,148,149],{},"onde",", ",[123,152,153],{},"por quê","\ne ",[123,156,157],{},"como evitar"," da próxima vez.",[100,160,161,162,166,167,170],{},"Em sistemas modernos, especialmente quando usamos\n",[22,163,165],{"href":164},"..\u002Fsistemas\u002Farquitetura-de-microservicos-escalaveis","microserviços",",\na observabilidade deixa de ser um \"nice to have\" e vira necessidade.\nUma simples requisição de \"finalizar compra\" pode passar por 6, 10 ou\n20 serviços diferentes antes de retornar para o usuário. Quando algo\ndemora 3 segundos a mais, você precisa saber ",[104,168,169],{},"em qual daquelas 20\netapas"," o tempo foi gasto.",[172,173,175],"h3",{"id":174},"por-que-isso-custa-caro-quando-ignorado","Por que isso custa caro quando ignorado",[100,177,178,179,111,186,115],{},"Vamos ser diretos sobre dinheiro. Um incidente de indisponibilidade em\nplataformas de médio porte custa, em média, entre R$ 15 mil e R$ 100 mil\npor hora dependendo do segmento — considerando receita perdida, equipe\ntrabalhando em overtime e dano reputacional. Quando sua equipe leva 4\nhoras para descobrir que o problema era uma query lenta no banco, em vez\nde 15 minutos, a diferença é justamente o que a observabilidade te dá:\n",[104,180,181,182,185],{},"tempo de detecção menor (MTTD, ",[123,183,184],{},"Mean Time To Detect",")",[104,187,188,189,185],{},"tempo de\nresolução menor (MTTR, ",[123,190,191],{},"Mean Time To Recovery",[136,193,194],{},[100,195,196,199,200,202,203,199,206,208],{},[104,197,198],{},"MTTD"," (",[123,201,184],{},"): tempo médio entre o problema\nacontecer e você descobrir que aconteceu.\n",[104,204,205],{},"MTTR",[123,207,191],{},"): tempo médio entre o problema\nacontecer e o serviço voltar a funcionar normalmente.",[93,210],{},[11,212,214],{"id":213},"monitoramento-vs-observabilidade-a-diferença-que-importa-monitoramento-vs","Monitoramento vs. observabilidade: a diferença que importa {#monitoramento-vs}",[100,216,217],{},"Esses dois termos são frequentemente usados como sinônimos, mas existe\numa diferença prática importante que vai guiar como você implementa as\ncoisas.",[100,219,220,223,224,227],{},[104,221,222],{},"Monitoramento"," é o conjunto de ferramentas e práticas que te dizem\nse algo está funcionando ou não, baseado em ",[104,225,226],{},"perguntas que você já\nsabia que ia fazer",". \"A API está respondendo?\", \"O uso de CPU passou\nde 80%?\", \"Quantos erros 500 aconteceram na última hora?\" — tudo isso é\nmonitoramento. Você pré-configura alertas e dashboards para responder a\nessas perguntas.",[100,229,230,232,233,236],{},[104,231,120],{}," é mais ampla: é a capacidade de fazer perguntas que\n",[104,234,235],{},"você não sabia que ia precisar fazer",". \"Por que o checkout ficou lento\nsó para usuários do Brasil usando o navegador Safari entre 14h e 15h de\nontem?\" — essa é uma pergunta que nenhum dashboard pré-configurado\nvai responder sozinho. Você só consegue respondê-la se tiver coletado\ndados ricos o suficiente (traces, métricas com dimensões e logs\nestruturados) durante o incidente.",[238,239,240,254],"table",{},[241,242,243],"thead",{},[244,245,246,250,252],"tr",{},[247,248,249],"th",{},"Aspecto",[247,251,222],{},[247,253,120],{},[255,256,257,269,280,291,302,313],"tbody",{},[244,258,259,263,266],{},[260,261,262],"td",{},"Pergunta típica",[260,264,265],{},"\"Está funcionando?\"",[260,267,268],{},"\"Por que não está funcionando?\"",[244,270,271,274,277],{},[260,272,273],{},"Quando configurar",[260,275,276],{},"Antes do problema",[260,278,279],{},"Preparado para o desconhecido",[244,281,282,285,288],{},[260,283,284],{},"Tipo de dado",[260,286,287],{},"Métricas pré-definidas",[260,289,290],{},"Traces + métricas + logs ricos",[244,292,293,296,299],{},[260,294,295],{},"Custo de setup",[260,297,298],{},"Baixo\u002Fmédio",[260,300,301],{},"Médio\u002Falto",[244,303,304,307,310],{},[260,305,306],{},"Resolve incidentes novos?",[260,308,309],{},"Não muito",[260,311,312],{},"Sim, é o objetivo principal",[244,314,315,318,321],{},[260,316,317],{},"Exemplo de ferramenta",[260,319,320],{},"Alerta de CPU no Grafana",[260,322,323],{},"Trace no Jaeger mostrando 200ms em chamada ao Redis",[100,325,326,329,330,333],{},[104,327,328],{},"A boa notícia",": você não precisa escolher um ou outro. Observabilidade\n",[123,331,332],{},"inclui"," monitoramento. Você implementa observabilidade e, como\nsubproduto, ganha monitoramento de graça.",[93,335],{},[11,337,339],{"id":338},"os-três-pilares-logs-métricas-e-traces-tres-pilares","Os três pilares: logs, métricas e traces {#tres-pilares}",[100,341,342],{},"Toda a literatura de observabilidade gira em torno de três tipos de\ndados, frequentemente chamados de \"os três pilares\". Vamos apresentá-los\naqui de forma breve e aprofundar cada um nas seções seguintes.",[16,344,345,351,357],{},[19,346,347,350],{},[104,348,349],{},"Logs",": registros de eventos discretos que aconteceram na sua\naplicação. \"Usuário X fez login às 14:32\", \"Falha ao conectar no\nbanco: timeout após 5s\".",[19,352,353,356],{},[104,354,355],{},"Métricas",": números agregados ao longo do tempo. \"Taxa de requisições\npor segundo\", \"Uso de memória agora\", \"Quantidade de erros na última\nhora\".",[19,358,359,362],{},[104,360,361],{},"Traces",": o caminho completo de uma única requisição atravessando\ntodos os serviços pelos quais ela passou, com a duração de cada\netapa.",[100,364,365],{},"Cada um resolve um problema diferente. Nenhum resolve tudo sozinho.",[172,367,369],{"id":368},"tabela-comparativa-dos-três-pilares","Tabela comparativa dos três pilares",[238,371,372,391],{},[241,373,374],{},[244,375,376,379,382,385,388],{},[247,377,378],{},"Pilar",[247,380,381],{},"Responde a...",[247,383,384],{},"Granularidade",[247,386,387],{},"Custo de armazenar",[247,389,390],{},"Quando usar",[255,392,393,411,429],{},[244,394,395,399,402,405,408],{},[260,396,397],{},[104,398,349],{},[260,400,401],{},"\"O que aconteceu nesse momento exato?\"",[260,403,404],{},"Alta (1 evento por linha)",[260,406,407],{},"Alto (cresce rápido)",[260,409,410],{},"Debugging profundo, auditoria",[244,412,413,417,420,423,426],{},[260,414,415],{},[104,416,355],{},[260,418,419],{},"\"Qual é a tendência ao longo do tempo?\"",[260,421,422],{},"Baixa (números agregados)",[260,424,425],{},"Baixo (só números)",[260,427,428],{},"Dashboards, alertas, tendências",[244,430,431,435,438,441,444],{},[260,432,433],{},[104,434,361],{},[260,436,437],{},"\"Por onde essa requisição passou e onde demorou?\"",[260,439,440],{},"Média (1 trace por requisição)",[260,442,443],{},"Médio",[260,445,446],{},"Diagnóstico de latência, depuração entre serviços",[136,448,449],{},[100,450,451,454],{},[104,452,453],{},"Dica prática",": se você está começando do zero, comece por métricas\n(mais baratas e já resolvem alertas), depois traces (resolvem\ndepuração de latência) e por último logs estruturados (resolvem\nauditoria e debugging detalhado). Inverter essa ordem é um erro\ncomum — logs sem traces e métricas geram muito ruído e pouco sinal.",[93,456],{},[11,458,460],{"id":459},"opentelemetry-o-que-é-e-por-que-existe-opentelemetry","OpenTelemetry: o que é e por que existe {#opentelemetry}",[100,462,463,466,467,470,471,199,474,477,478,111,481,484],{},[104,464,465],{},"OpenTelemetry"," (frequentemente abreviado como ",[104,468,469],{},"OTel",") é um projeto\nopen source mantido pela ",[104,472,473],{},"CNCF",[123,475,476],{},"Cloud Native Computing Foundation",",\na mesma fundação que cuida do Kubernetes). Ele nasceu em 2019 da fusão\nde dois projetos anteriores — ",[104,479,480],{},"OpenTracing",[104,482,483],{},"OpenCensus"," — que\nfaziam coisas parecidas e competiam entre si. A comunidade percebeu\nque fazer dois padrões concorrentes não ajudava ninguém, então unificou\ntudo em um só.",[172,486,488],{"id":487},"o-problema-que-o-opentelemetry-resolve","O problema que o OpenTelemetry resolve",[100,490,491],{},"Antes do OTel, se você quisesse coletar traces da sua aplicação, precisava\ninstalar o SDK (Software Development Kit, o pacote de bibliotecas) de\numa ferramenta específica — Jaeger, Zipkin, Datadog, New Relic, etc. Cada\numa com sua própria API. Se depois você quisesse trocar de Jaeger para\nDatadog, precisava reescrever toda a instrumentação do código. Era\ncaro, chato e prendia você a um fornecedor.",[136,493,494],{},[100,495,496,499],{},[104,497,498],{},"Analogia",": é como comprar uma TV que só funciona com uma marca de\nfone de ouvido. Se você quiser trocar o fone, tem que trocar a TV\njunto. O OpenTelemetry é como uma TV com entrada Bluetooth padrão —\nfunciona com qualquer fone, de qualquer marca.",[100,501,502,503,506,507,510],{},"O OTel resolve isso fornecendo ",[104,504,505],{},"uma única API padrão"," para\ninstrumentar sua aplicação. Você escreve a instrumentação uma vez e\ndecide depois para onde enviar os dados (que chamamos de ",[123,508,509],{},"backend",",\no destino final dos dados) — Jaeger, Prometheus, Datadog, Honeycomb,\nTempo, o que for. A troca de backend vira uma mudança de configuração,\nnão de código.",[172,512,514],{"id":513},"como-o-opentelemetry-é-organizado","Como o OpenTelemetry é organizado",[100,516,517],{},"O projeto se divide em três partes principais:",[519,520,521,527,533],"ul",{},[19,522,523,526],{},[104,524,525],{},"API",": as interfaces e padrões que você importa no código (spans,\nmétricas, logs). É o que você \"chama\" dentro da sua aplicação.",[19,528,529,532],{},[104,530,531],{},"SDK",": a implementação concreta da API. É o motor que de fato coleta,\nprocessa e exporta os dados para algum backend.",[19,534,535,538],{},[104,536,537],{},"Collector",": um processo separado (um \"agente\") que recebe dados de\nvárias aplicações, processa, filtra e envia para um ou mais backends.\nImagine como uma central de triagem dos Correios — todo mundo entrega\nlá e ele distribui para os destinos certos.",[540,541,546],"pre",{"className":542,"code":544,"language":545},[543],"language-text","[App A] ─┐\n[App B] ─┼─→ [OpenTelemetry Collector] ─┬─→ [Jaeger] (traces)\n[App C] ─┘                              ├─→ [Prometheus] (métricas)\n                                         └─→ [Loki] (logs)\n","text",[547,548,544],"code",{"__ignoreMap":549},"",[172,551,553],{"id":552},"por-que-usar-opentelemetry-em-vez-de-ferramentas-diretamente","Por que usar OpenTelemetry em vez de ferramentas diretamente?",[238,555,556,569],{},[241,557,558],{},[244,559,560,563,566],{},[247,561,562],{},"Motivo",[247,564,565],{},"Sem OTel",[247,567,568],{},"Com OTel",[255,570,571,582,593,604,615],{},[244,572,573,576,579],{},[260,574,575],{},"Trocar de backend",[260,577,578],{},"Reescrever código",[260,580,581],{},"Mudar config",[244,583,584,587,590],{},[260,585,586],{},"Padronizar times",[260,588,589],{},"Cada time escolhe uma ferramenta",[260,591,592],{},"Todos falam a mesma língua",[244,594,595,598,601],{},[260,596,597],{},"Vendor lock-in",[260,599,600],{},"Alto (preso a um fornecedor)",[260,602,603],{},"Baixo (padrão aberto)",[244,605,606,609,612],{},[260,607,608],{},"Comunidade",[260,610,611],{},"Fragmentada",[260,613,614],{},"Unificada (CNCF)",[244,616,617,620,623],{},[260,618,619],{},"Suporte a linguagens",[260,621,622],{},"Varia por ferramenta",[260,624,625],{},"11+ linguagens oficiais",[93,627],{},[11,629,631],{"id":630},"tracing-explicado-com-analogias-tracing","Tracing explicado com analogias {#tracing}",[100,633,634,637],{},[104,635,636],{},"Tracing"," é o pilar que mais confunde iniciantes, mas também é o mais\npoderoso quando se trata de depurar sistemas distribuídos. Vamos de\nanalogia antes de definição técnica.",[136,639,640],{},[100,641,642,644,645,648],{},[104,643,498],{},": Tracing é como rastrear um pacote dos Correios. Quando\nvocê envia uma encomenda, recebe um código de rastreio. Com ele, você\nvê cada etapa: \"Objeto postado em São Paulo\", \"Em trânsito para\ncentro de distribuição do Rio\", \"Saiu para entrega\", \"Entregue\". Para\ncada etapa, há um ",[104,646,647],{},"horário",". Subtraindo os horários, você descobre\nque o pacote ficou 2 dias parado no centro de distribuição — foi ali\no gargalo. O tracing de software faz exatamente isso, mas com uma\nrequisição em vez de um pacote.",[172,650,652],{"id":651},"conceitos-chave-do-tracing","Conceitos-chave do tracing",[100,654,655,656,659,660,115],{},"Um ",[104,657,658],{},"Trace"," é o caminho completo de uma requisição, do momento em que\nentra no seu sistema até o momento em que a resposta sai. Um trace é\ncomposto por um ou mais ",[104,661,662],{},"Spans",[100,664,655,665,668],{},[104,666,667],{},"Span"," é uma unidade de trabalho dentro do trace. Cada chamada a\num serviço, cada query de banco, cada chamada a uma API externa pode\nser um span. Um span tem:",[519,670,671,677,683,693,699],{},[19,672,673,676],{},[104,674,675],{},"Nome",": o que foi feito (\"GET \u002Fcheckout\", \"SELECT FROM orders\").",[19,678,679,682],{},[104,680,681],{},"Tempo de início e duração",": quanto tempo levou.",[19,684,685,688,689,692],{},[104,686,687],{},"Atributos"," (ou ",[123,690,691],{},"tags","): metadados extras (\"user.id=42\",\n\"http.status_code=500\").",[19,694,695,698],{},[104,696,697],{},"Eventos",": marcos pontuais dentro do span (\"cache miss às 14:32:05\").",[19,700,701,704],{},[104,702,703],{},"Span pai",": qual span o chamou. É isso que cria a árvore hierárquica.",[100,706,655,707,710,711,714,715,718,719,115],{},[104,708,709],{},"SpanContext"," é a identidade do span: um ",[104,712,713],{},"Trace ID"," (igual para\ntodos os spans do mesmo trace) e um ",[104,716,717],{},"Span ID"," (único por span). É\nessa identidade que permite que spans de serviços diferentes sejam\n\"amarrados\" num único trace — o que chamamos de ",[104,720,721],{},"propagação de\ncontexto",[540,723,726],{"className":724,"code":725,"language":545},[543],"Trace (Trace ID: 7a3f...) — total: 850ms\n├─ Span 1: GET \u002Fcheckout (850ms)        [Serviço: API Gateway]\n   ├─ Span 2: validar_token (12ms)       [Serviço: Auth]\n   ├─ Span 3: buscar_carrinho (180ms)    [Serviço: Carrinho]\n   │  └─ Span 4: SELECT cart_items (165ms) [Banco: PostgreSQL]\n   └─ Span 5: processar_pagamento (640ms) [Serviço: Pagamentos]\n      └─ Span 6: POST \u002Fcharge (620ms)    [API externa: Stripe]\n",[547,727,725],{"__ignoreMap":549},[100,729,730,731,115],{},"Nesse exemplo, fica óbvio que o gargalo está na chamada ao Stripe\n(620ms de 850ms totais). Sem tracing, você saberia só que\n\"o checkout está lento\". Com tracing, você sabe ",[104,732,733],{},"exatamente onde",[172,735,737],{"id":736},"o-que-é-propagação-de-contexto","O que é propagação de contexto?",[100,739,740,741,744,745,748],{},"Quando a API Gateway chama o serviço de Pagamentos, ela precisa \"passar\nadiante\" o Trace ID, senão o Pagamentos vai gerar um trace novo e os\ndois nunca serão conectados. Isso é feito injetando cabeçalhos HTTP\npadronizados (no padrão ",[104,742,743],{},"W3C Trace Context",", um padrão internacional\nreconhecido pelo ",[123,746,747],{},"World Wide Web Consortium",") na requisição:",[540,750,753],{"className":751,"code":752,"language":545},[543],"traceparent: 00-7a3f...-b2c1...-01\n             │  │       │       └── flags\n             │  │       └── span ID atual\n             │  └── trace ID (igual para todo o trace)\n             └── versão do formato\n",[547,754,752],{"__ignoreMap":549},[100,756,757,758,761],{},"O OpenTelemetry faz essa propagação ",[104,759,760],{},"automaticamente"," quando você\nusa as bibliotecas de instrumentação oficiais — você não precisa\nescrever esses cabeçalhos à mão.",[93,763],{},[11,765,767],{"id":766},"métricas-explicadas-com-analogias-metricas","Métricas explicadas com analogias {#metricas}",[136,769,770],{},[100,771,772,774,775,777],{},[104,773,498],{},": Métricas são como o painel do carro. Você não quer\nsaber a velocidade exata em cada milissegundo da viagem (isso seria\num log, e ia gerar uma quantidade absurda de dados). Você quer o\nvelocímetro mostrando ",[104,776,106],{},", e um histórico médio de \"km\u002Fh nos\núltimos 10 minutos\". Métricas são números agregados que te dão uma\nvisão geral, sem armazenar cada evento individual.",[100,779,780],{},"Métricas são números que descrevem algum aspecto do seu sistema,\ncoletados ao longo do tempo. Exemplos clássicos:",[519,782,783,792,801],{},[19,784,785,199,788,791],{},[104,786,787],{},"Contadores",[123,789,790],{},"counters","): só aumentam. Ex.: \"total de requisições\ndesde que o serviço subiu\". Útil para calcular taxas (requisições por\nsegundo derivando o contador).",[19,793,794,199,797,800],{},[104,795,796],{},"Medidores",[123,798,799],{},"gauges","): sobem e descem. Ex.: \"uso de memória agora\",\n\"conexões abertas no banco\".",[19,802,803,806,807,810],{},[104,804,805],{},"Histogramas",": distribuição de valores. Ex.: \"quantas requisições\nlevaram menos de 100ms, entre 100ms e 500ms, mais de 500ms\". É a base\npara calcular percentis como ",[104,808,809],{},"p99"," (o tempo abaixo do qual 99% das\nrequisições são respondidas).",[136,812,813],{},[100,814,815,817,818,821],{},[104,816,809],{}," significa que 99% das requisições foram mais rápidas que esse\nvalor. Se o p99 é 800ms, significa que 1 em cada 100 requisições\ndemorou mais que 800ms. É uma métrica muito usada porque a ",[104,819,820],{},"média","\nesconde os usuários que tiveram a pior experiência — e geralmente\nsão esses os que reclamam.",[172,823,825],{"id":824},"tipos-de-métricas-no-opentelemetry","Tipos de métricas no OpenTelemetry",[238,827,828,844],{},[241,829,830],{},[244,831,832,835,838,841],{},[247,833,834],{},"Instrumento",[247,836,837],{},"O que mede",[247,839,840],{},"Exemplo",[247,842,843],{},"Equivalente em dashboard",[255,845,846,860,874,888],{},[244,847,848,851,854,857],{},[260,849,850],{},"Counter",[260,852,853],{},"Só cresce",[260,855,856],{},"Total de erros 500",[260,858,859],{},"Número que só aumenta",[244,861,862,865,868,871],{},[260,863,864],{},"Up\u002FDown Counter",[260,866,867],{},"Cresce e decresce",[260,869,870],{},"Conexões ativas",[260,872,873],{},"Vai e volta",[244,875,876,879,882,885],{},[260,877,878],{},"Gauge",[260,880,881],{},"Valor instantâneo",[260,883,884],{},"Memória em uso agora",[260,886,887],{},"Velocímetro",[244,889,890,893,896,899],{},[260,891,892],{},"Histogram",[260,894,895],{},"Distribuição",[260,897,898],{},"Latência das requisições",[260,900,901],{},"Gráfico de barras por faixa",[100,903,904,905,908],{},"Métricas são ",[104,906,907],{},"baratas"," de armazenar: são só números com timestamps.\nPor isso são ideais para dashboards de longo prazo (\"como estava a\nlatência no mês passado?\") e para alertas (\"alerte se o p99 passar de\n1 segundo por 5 minutos seguidos\").",[93,910],{},[11,912,914],{"id":913},"logs-explicados-com-analogias-logs","Logs explicados com analogias {#logs}",[136,916,917],{},[100,918,919,921],{},[104,920,498],{},": Logs são como o diário de bordo de um navio. O capitão\nanota tudo que acontece: \"14:00 — partiu do porto\", \"18:30 — tempestade\nà vista, reduzindo velocidade\", \"22:15 — motor 2 com vibração anormal,\nequipe de manutenção acionada\". Cada anotação é um evento isolado,\ncom data e hora. Sozinha não conta muito, mas quando você junta todas\nna ordem certa, reconstrói a história inteira.",[100,923,924,926],{},[104,925,349],{}," são registros de eventos discretos. Cada log é uma linha (ou\nobjeto) que diz: \"nesse timestamp, aconteceu essa coisa, com esses\ndetalhes\". Existem três níveis de maturidade em como escrever logs:",[16,928,929,939,945],{},[19,930,931,934,935,938],{},[104,932,933],{},"Logs em texto livre"," (iniciante): ",[547,936,937],{},"print(\"usuário logado\")",". Fácil\nde escrever, difícil de buscar e filtrar depois.",[19,940,941,944],{},[104,942,943],{},"Logs estruturados"," (intermediário): JSON com campos. Buscável,\nfiltrável, indexável.",[19,946,947,950,951,111,954,957],{},[104,948,949],{},"Logs com contexto de trace"," (avançado): cada log carrega o\n",[547,952,953],{},"trace_id",[547,955,956],{},"span_id"," atuais, permitindo pular de um trace no\nJaeger direto para os logs relacionados.",[540,959,963],{"className":960,"code":961,"language":962,"meta":549,"style":549},"language-json shiki shiki-themes github-light github-dark","\u002F\u002F Log estruturado SEM contexto de trace\n{\"timestamp\": \"2026-08-26T14:32:05Z\", \"level\": \"error\", \"msg\": \"falha no checkout\"}\n\n\u002F\u002F Log estruturado COM contexto de trace (ideal)\n{\"timestamp\": \"2026-08-26T14:32:05Z\", \"level\": \"error\", \"msg\": \"falha no checkout\",\n \"trace_id\": \"7a3f...\", \"span_id\": \"b2c1...\", \"user.id\": 42, \"cart.total\": 199.90}\n","json",[547,964,965,974,1015,1022,1028,1058],{"__ignoreMap":549},[966,967,970],"span",{"class":968,"line":969},"line",1,[966,971,973],{"class":972},"sJ8bj","\u002F\u002F Log estruturado SEM contexto de trace\n",[966,975,977,981,985,988,992,994,997,999,1002,1004,1007,1009,1012],{"class":968,"line":976},2,[966,978,980],{"class":979},"sVt8B","{",[966,982,984],{"class":983},"sj4cs","\"timestamp\"",[966,986,987],{"class":979},": ",[966,989,991],{"class":990},"sZZnC","\"2026-08-26T14:32:05Z\"",[966,993,150],{"class":979},[966,995,996],{"class":983},"\"level\"",[966,998,987],{"class":979},[966,1000,1001],{"class":990},"\"error\"",[966,1003,150],{"class":979},[966,1005,1006],{"class":983},"\"msg\"",[966,1008,987],{"class":979},[966,1010,1011],{"class":990},"\"falha no checkout\"",[966,1013,1014],{"class":979},"}\n",[966,1016,1018],{"class":968,"line":1017},3,[966,1019,1021],{"emptyLinePlaceholder":1020},true,"\n",[966,1023,1025],{"class":968,"line":1024},4,[966,1026,1027],{"class":972},"\u002F\u002F Log estruturado COM contexto de trace (ideal)\n",[966,1029,1031,1033,1035,1037,1039,1041,1043,1045,1047,1049,1051,1053,1055],{"class":968,"line":1030},5,[966,1032,980],{"class":979},[966,1034,984],{"class":983},[966,1036,987],{"class":979},[966,1038,991],{"class":990},[966,1040,150],{"class":979},[966,1042,996],{"class":983},[966,1044,987],{"class":979},[966,1046,1001],{"class":990},[966,1048,150],{"class":979},[966,1050,1006],{"class":983},[966,1052,987],{"class":979},[966,1054,1011],{"class":990},[966,1056,1057],{"class":979},",\n",[966,1059,1061,1064,1066,1069,1071,1074,1076,1079,1081,1084,1086,1089,1091,1094,1096,1099],{"class":968,"line":1060},6,[966,1062,1063],{"class":983}," \"trace_id\"",[966,1065,987],{"class":979},[966,1067,1068],{"class":990},"\"7a3f...\"",[966,1070,150],{"class":979},[966,1072,1073],{"class":983},"\"span_id\"",[966,1075,987],{"class":979},[966,1077,1078],{"class":990},"\"b2c1...\"",[966,1080,150],{"class":979},[966,1082,1083],{"class":983},"\"user.id\"",[966,1085,987],{"class":979},[966,1087,1088],{"class":983},"42",[966,1090,150],{"class":979},[966,1092,1093],{"class":983},"\"cart.total\"",[966,1095,987],{"class":979},[966,1097,1098],{"class":983},"199.90",[966,1100,1014],{"class":979},[100,1102,1103,1104,1106,1107,1110],{},"A diferença entre os dois exemplos acima é enorme na prática: com o\n",[547,1105,953],{}," no log, quando você estiver olhando um trace lento no Jaeger,\npode copiar aquele ID e jogar na ferramenta de logs para ver ",[104,1108,1109],{},"todas as\nmensagens"," geradas durante aquela requisição específica — em todos os\nserviços.",[136,1112,1113],{},[100,1114,1115,1118],{},[104,1116,1117],{},"Aviso de custo",": logs são o pilar mais caro de armazenar. Um\nserviço medianamente usado pode gerar dezenas de GB de logs por dia.\nUse níveis de log (DEBUG, INFO, WARN, ERROR) com consciência e\nconsidere amostragem (sampling) para logs de baixo nível em produção.",[93,1120],{},[11,1122,1124],{"id":1123},"mão-na-massa-instrumentando-uma-api-fastapi-fastapi","Mão na massa: instrumentando uma API FastAPI {#fastapi}",[100,1126,1127,1128,1131],{},"Chegou a hora de ver código real. Vamos criar uma API simples com\n",[104,1129,1130],{},"FastAPI"," (um framework web em Python, rápido e moderno) e\ninstrumentá-la com OpenTelemetry para gerar traces. O objetivo é que,\na cada requisição recebida, a API gere um trace com spans para cada\noperação interna.",[172,1133,1135],{"id":1134},"pré-requisitos","Pré-requisitos",[519,1137,1138,1141],{},[19,1139,1140],{},"Python 3.10 ou superior",[19,1142,1143],{},"Familiaridade básica com terminal e pip",[172,1145,1147],{"id":1146},"passo-1-instalar-as-dependências","Passo 1: instalar as dependências",[540,1149,1153],{"className":1150,"code":1151,"language":1152,"meta":549,"style":549},"language-bash shiki shiki-themes github-light github-dark","# Crie um ambiente virtual (boa prática — isola as bibliotecas do projeto)\npython -m venv .venv\nsource .venv\u002Fbin\u002Factivate  # no Windows: .venv\\Scripts\\activate\n\n# Instale o FastAPI, o servidor ASGI Uvicorn e os pacotes do OpenTelemetry\npip install fastapi uvicorn \\\n    opentelemetry-distro \\\n    opentelemetry-exporter-otlp \\\n    opentelemetry-instrumentation-fastapi \\\n    opentelemetry-instrumentation-requests \\\n    opentelemetry-instrumentation-logging\n\n# O opentelemetry-distro instala automaticamente as instrumentações\n# mais comuns. O \"bootstrap\" abaixo detecta suas libs e ativa as\n# instrumentações correspondentes sem você precisar escrever código.\nopentelemetry-bootstrap -a install\n","bash",[547,1154,1155,1160,1175,1186,1190,1195,1212,1220,1228,1236,1244,1250,1255,1261,1267,1273],{"__ignoreMap":549},[966,1156,1157],{"class":968,"line":969},[966,1158,1159],{"class":972},"# Crie um ambiente virtual (boa prática — isola as bibliotecas do projeto)\n",[966,1161,1162,1166,1169,1172],{"class":968,"line":976},[966,1163,1165],{"class":1164},"sScJk","python",[966,1167,1168],{"class":983}," -m",[966,1170,1171],{"class":990}," venv",[966,1173,1174],{"class":990}," .venv\n",[966,1176,1177,1180,1183],{"class":968,"line":1017},[966,1178,1179],{"class":983},"source",[966,1181,1182],{"class":990}," .venv\u002Fbin\u002Factivate",[966,1184,1185],{"class":972},"  # no Windows: .venv\\Scripts\\activate\n",[966,1187,1188],{"class":968,"line":1024},[966,1189,1021],{"emptyLinePlaceholder":1020},[966,1191,1192],{"class":968,"line":1030},[966,1193,1194],{"class":972},"# Instale o FastAPI, o servidor ASGI Uvicorn e os pacotes do OpenTelemetry\n",[966,1196,1197,1200,1203,1206,1209],{"class":968,"line":1060},[966,1198,1199],{"class":1164},"pip",[966,1201,1202],{"class":990}," install",[966,1204,1205],{"class":990}," fastapi",[966,1207,1208],{"class":990}," uvicorn",[966,1210,1211],{"class":983}," \\\n",[966,1213,1215,1218],{"class":968,"line":1214},7,[966,1216,1217],{"class":990},"    opentelemetry-distro",[966,1219,1211],{"class":983},[966,1221,1223,1226],{"class":968,"line":1222},8,[966,1224,1225],{"class":990},"    opentelemetry-exporter-otlp",[966,1227,1211],{"class":983},[966,1229,1231,1234],{"class":968,"line":1230},9,[966,1232,1233],{"class":990},"    opentelemetry-instrumentation-fastapi",[966,1235,1211],{"class":983},[966,1237,1239,1242],{"class":968,"line":1238},10,[966,1240,1241],{"class":990},"    opentelemetry-instrumentation-requests",[966,1243,1211],{"class":983},[966,1245,1247],{"class":968,"line":1246},11,[966,1248,1249],{"class":990},"    opentelemetry-instrumentation-logging\n",[966,1251,1253],{"class":968,"line":1252},12,[966,1254,1021],{"emptyLinePlaceholder":1020},[966,1256,1258],{"class":968,"line":1257},13,[966,1259,1260],{"class":972},"# O opentelemetry-distro instala automaticamente as instrumentações\n",[966,1262,1264],{"class":968,"line":1263},14,[966,1265,1266],{"class":972},"# mais comuns. O \"bootstrap\" abaixo detecta suas libs e ativa as\n",[966,1268,1270],{"class":968,"line":1269},15,[966,1271,1272],{"class":972},"# instrumentações correspondentes sem você precisar escrever código.\n",[966,1274,1276,1279,1282],{"class":968,"line":1275},16,[966,1277,1278],{"class":1164},"opentelemetry-bootstrap",[966,1280,1281],{"class":983}," -a",[966,1283,1284],{"class":990}," install\n",[172,1286,1288],{"id":1287},"passo-2-criar-a-aplicação","Passo 2: criar a aplicação",[100,1290,1291,1292,1295],{},"Crie um arquivo ",[547,1293,1294],{},"app.py",":",[540,1297,1300],{"className":1298,"code":1299,"language":1165,"meta":549,"style":549},"language-python shiki shiki-themes github-light github-dark","# app.py — API de exemplo para demonstrar observabilidade com OTel\nimport logging\nfrom fastapi import FastAPI\nimport requests\n\n# O pacote abaixo configura o logging do Python para injetar\n# automaticamente trace_id e span_id em cada log gerado dentro de um span.\nfrom opentelemetry.instrumentation.logging import LoggingInstrumentor\n\n# A instrumentação do FastAPI cria um span automaticamente para cada\n# requisição HTTP recebida, com nome, método, status e duração.\nfrom opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\n\n# A instrumentação do requests cria spans para cada chamada HTTP\n# que sua aplicação fizer para serviços externos (propagando o contexto).\nfrom opentelemetry.instrumentation.requests import RequestsInstrumentor\n\n# Biblioteca principal de tracing — usamos para criar spans manuais.\nfrom opentelemetry import trace\n\nlogging.basicConfig(level=logging.INFO)\nlogger = logging.getLogger(__name__)\n\napp = FastAPI()\n\n# Instrumenta automaticamente todas as rotas do FastAPI.\n# A partir daqui, cada request gera um trace com um span raiz.\nFastAPIInstrumentor.instrument_app(app)\n\n# Instrumenta chamadas externas com a lib requests.\nRequestsInstrumentor().instrument()\n\n# Faz cada linha de log carregar o trace_id e span_id atuais.\nLoggingInstrumentor().instrument(set_logging_format=True)\n\n\n@app.get(\"\u002F\")\ndef root():\n    # Rota simples — gera um span automático pelo FastAPIInstrumentor.\n    return {\"status\": \"ok\"}\n\n\n@app.get(\"\u002Flento\")\ndef lento():\n    # Simula uma rota que chama um serviço externo demorado.\n    tracer = trace.get_tracer(__name__)\n\n    # Span manual: vamos medir quanto tempo levamos \"pensando\".\n    with tracer.start_as_current_span(\"processar_pagamento\") as span:\n        # Adicionamos atributos ao span — informações extras pesquisáveis.\n        span.set_attribute(\"pagamento.metodo\", \"cartao\")\n        span.set_attribute(\"pagamento.moeda\", \"BRL\")\n\n        # Simula uma chamada externa (instrumentada, vira subspan).\n        # Substitua por uma URL real quando estiver testando.\n        try:\n            resp = requests.get(\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F2\", timeout=5)\n            span.set_attribute(\"pagamento.status_http\", resp.status_code)\n        except Exception as e:\n            # Registra um evento de erro dentro do span.\n            span.record_exception(e)\n            span.set_status(trace.Status(trace.StatusCode.ERROR))\n            logger.error(\"falha ao chamar gateway de pagamento: %s\", e)\n            return {\"erro\": \"falha no pagamento\"}\n\n        logger.info(\"pagamento processado com sucesso\")\n        return {\"status\": \"pago\", \"tempo_total_ms\": 2000}\n",[547,1301,1302,1307,1312,1317,1322,1326,1331,1336,1341,1345,1350,1355,1360,1364,1369,1374,1379,1384,1390,1396,1401,1407,1413,1418,1424,1429,1435,1441,1447,1452,1458,1464,1469,1475,1481,1486,1491,1497,1503,1509,1515,1520,1525,1531,1537,1543,1549,1554,1560,1566,1572,1578,1584,1589,1595,1601,1607,1613,1619,1625,1631,1637,1643,1649,1655,1660,1666],{"__ignoreMap":549},[966,1303,1304],{"class":968,"line":969},[966,1305,1306],{},"# app.py — API de exemplo para demonstrar observabilidade com OTel\n",[966,1308,1309],{"class":968,"line":976},[966,1310,1311],{},"import logging\n",[966,1313,1314],{"class":968,"line":1017},[966,1315,1316],{},"from fastapi import FastAPI\n",[966,1318,1319],{"class":968,"line":1024},[966,1320,1321],{},"import requests\n",[966,1323,1324],{"class":968,"line":1030},[966,1325,1021],{"emptyLinePlaceholder":1020},[966,1327,1328],{"class":968,"line":1060},[966,1329,1330],{},"# O pacote abaixo configura o logging do Python para injetar\n",[966,1332,1333],{"class":968,"line":1214},[966,1334,1335],{},"# automaticamente trace_id e span_id em cada log gerado dentro de um span.\n",[966,1337,1338],{"class":968,"line":1222},[966,1339,1340],{},"from opentelemetry.instrumentation.logging import LoggingInstrumentor\n",[966,1342,1343],{"class":968,"line":1230},[966,1344,1021],{"emptyLinePlaceholder":1020},[966,1346,1347],{"class":968,"line":1238},[966,1348,1349],{},"# A instrumentação do FastAPI cria um span automaticamente para cada\n",[966,1351,1352],{"class":968,"line":1246},[966,1353,1354],{},"# requisição HTTP recebida, com nome, método, status e duração.\n",[966,1356,1357],{"class":968,"line":1252},[966,1358,1359],{},"from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor\n",[966,1361,1362],{"class":968,"line":1257},[966,1363,1021],{"emptyLinePlaceholder":1020},[966,1365,1366],{"class":968,"line":1263},[966,1367,1368],{},"# A instrumentação do requests cria spans para cada chamada HTTP\n",[966,1370,1371],{"class":968,"line":1269},[966,1372,1373],{},"# que sua aplicação fizer para serviços externos (propagando o contexto).\n",[966,1375,1376],{"class":968,"line":1275},[966,1377,1378],{},"from opentelemetry.instrumentation.requests import RequestsInstrumentor\n",[966,1380,1382],{"class":968,"line":1381},17,[966,1383,1021],{"emptyLinePlaceholder":1020},[966,1385,1387],{"class":968,"line":1386},18,[966,1388,1389],{},"# Biblioteca principal de tracing — usamos para criar spans manuais.\n",[966,1391,1393],{"class":968,"line":1392},19,[966,1394,1395],{},"from opentelemetry import trace\n",[966,1397,1399],{"class":968,"line":1398},20,[966,1400,1021],{"emptyLinePlaceholder":1020},[966,1402,1404],{"class":968,"line":1403},21,[966,1405,1406],{},"logging.basicConfig(level=logging.INFO)\n",[966,1408,1410],{"class":968,"line":1409},22,[966,1411,1412],{},"logger = logging.getLogger(__name__)\n",[966,1414,1416],{"class":968,"line":1415},23,[966,1417,1021],{"emptyLinePlaceholder":1020},[966,1419,1421],{"class":968,"line":1420},24,[966,1422,1423],{},"app = FastAPI()\n",[966,1425,1427],{"class":968,"line":1426},25,[966,1428,1021],{"emptyLinePlaceholder":1020},[966,1430,1432],{"class":968,"line":1431},26,[966,1433,1434],{},"# Instrumenta automaticamente todas as rotas do FastAPI.\n",[966,1436,1438],{"class":968,"line":1437},27,[966,1439,1440],{},"# A partir daqui, cada request gera um trace com um span raiz.\n",[966,1442,1444],{"class":968,"line":1443},28,[966,1445,1446],{},"FastAPIInstrumentor.instrument_app(app)\n",[966,1448,1450],{"class":968,"line":1449},29,[966,1451,1021],{"emptyLinePlaceholder":1020},[966,1453,1455],{"class":968,"line":1454},30,[966,1456,1457],{},"# Instrumenta chamadas externas com a lib requests.\n",[966,1459,1461],{"class":968,"line":1460},31,[966,1462,1463],{},"RequestsInstrumentor().instrument()\n",[966,1465,1467],{"class":968,"line":1466},32,[966,1468,1021],{"emptyLinePlaceholder":1020},[966,1470,1472],{"class":968,"line":1471},33,[966,1473,1474],{},"# Faz cada linha de log carregar o trace_id e span_id atuais.\n",[966,1476,1478],{"class":968,"line":1477},34,[966,1479,1480],{},"LoggingInstrumentor().instrument(set_logging_format=True)\n",[966,1482,1484],{"class":968,"line":1483},35,[966,1485,1021],{"emptyLinePlaceholder":1020},[966,1487,1489],{"class":968,"line":1488},36,[966,1490,1021],{"emptyLinePlaceholder":1020},[966,1492,1494],{"class":968,"line":1493},37,[966,1495,1496],{},"@app.get(\"\u002F\")\n",[966,1498,1500],{"class":968,"line":1499},38,[966,1501,1502],{},"def root():\n",[966,1504,1506],{"class":968,"line":1505},39,[966,1507,1508],{},"    # Rota simples — gera um span automático pelo FastAPIInstrumentor.\n",[966,1510,1512],{"class":968,"line":1511},40,[966,1513,1514],{},"    return {\"status\": \"ok\"}\n",[966,1516,1518],{"class":968,"line":1517},41,[966,1519,1021],{"emptyLinePlaceholder":1020},[966,1521,1523],{"class":968,"line":1522},42,[966,1524,1021],{"emptyLinePlaceholder":1020},[966,1526,1528],{"class":968,"line":1527},43,[966,1529,1530],{},"@app.get(\"\u002Flento\")\n",[966,1532,1534],{"class":968,"line":1533},44,[966,1535,1536],{},"def lento():\n",[966,1538,1540],{"class":968,"line":1539},45,[966,1541,1542],{},"    # Simula uma rota que chama um serviço externo demorado.\n",[966,1544,1546],{"class":968,"line":1545},46,[966,1547,1548],{},"    tracer = trace.get_tracer(__name__)\n",[966,1550,1552],{"class":968,"line":1551},47,[966,1553,1021],{"emptyLinePlaceholder":1020},[966,1555,1557],{"class":968,"line":1556},48,[966,1558,1559],{},"    # Span manual: vamos medir quanto tempo levamos \"pensando\".\n",[966,1561,1563],{"class":968,"line":1562},49,[966,1564,1565],{},"    with tracer.start_as_current_span(\"processar_pagamento\") as span:\n",[966,1567,1569],{"class":968,"line":1568},50,[966,1570,1571],{},"        # Adicionamos atributos ao span — informações extras pesquisáveis.\n",[966,1573,1575],{"class":968,"line":1574},51,[966,1576,1577],{},"        span.set_attribute(\"pagamento.metodo\", \"cartao\")\n",[966,1579,1581],{"class":968,"line":1580},52,[966,1582,1583],{},"        span.set_attribute(\"pagamento.moeda\", \"BRL\")\n",[966,1585,1587],{"class":968,"line":1586},53,[966,1588,1021],{"emptyLinePlaceholder":1020},[966,1590,1592],{"class":968,"line":1591},54,[966,1593,1594],{},"        # Simula uma chamada externa (instrumentada, vira subspan).\n",[966,1596,1598],{"class":968,"line":1597},55,[966,1599,1600],{},"        # Substitua por uma URL real quando estiver testando.\n",[966,1602,1604],{"class":968,"line":1603},56,[966,1605,1606],{},"        try:\n",[966,1608,1610],{"class":968,"line":1609},57,[966,1611,1612],{},"            resp = requests.get(\"https:\u002F\u002Fhttpbin.org\u002Fdelay\u002F2\", timeout=5)\n",[966,1614,1616],{"class":968,"line":1615},58,[966,1617,1618],{},"            span.set_attribute(\"pagamento.status_http\", resp.status_code)\n",[966,1620,1622],{"class":968,"line":1621},59,[966,1623,1624],{},"        except Exception as e:\n",[966,1626,1628],{"class":968,"line":1627},60,[966,1629,1630],{},"            # Registra um evento de erro dentro do span.\n",[966,1632,1634],{"class":968,"line":1633},61,[966,1635,1636],{},"            span.record_exception(e)\n",[966,1638,1640],{"class":968,"line":1639},62,[966,1641,1642],{},"            span.set_status(trace.Status(trace.StatusCode.ERROR))\n",[966,1644,1646],{"class":968,"line":1645},63,[966,1647,1648],{},"            logger.error(\"falha ao chamar gateway de pagamento: %s\", e)\n",[966,1650,1652],{"class":968,"line":1651},64,[966,1653,1654],{},"            return {\"erro\": \"falha no pagamento\"}\n",[966,1656,1658],{"class":968,"line":1657},65,[966,1659,1021],{"emptyLinePlaceholder":1020},[966,1661,1663],{"class":968,"line":1662},66,[966,1664,1665],{},"        logger.info(\"pagamento processado com sucesso\")\n",[966,1667,1669],{"class":968,"line":1668},67,[966,1670,1671],{},"        return {\"status\": \"pago\", \"tempo_total_ms\": 2000}\n",[172,1673,1675],{"id":1674},"passo-3-rodar-com-o-otel-exportando-para-o-collector","Passo 3: rodar com o OTel exportando para o Collector",[100,1677,1678,1679,1682],{},"O OpenTelemetry fornece um comando ",[547,1680,1681],{},"opentelemetry-instrument"," que\nenvolve sua aplicação e configura a exportação dos dados. Aqui vamos\napontar para um Collector rodando localmente na porta 4317 (gRPC).",[540,1684,1686],{"className":1150,"code":1685,"language":1152,"meta":549,"style":549},"# As variáveis de ambiente abaixo dizem ao OTel SDK:\n#  - OTEL_SERVICE_NAME: nome do serviço que aparecerá no Jaeger\n#  - OTEL_EXPORTER_OTLP_ENDPOINT: para onde enviar os dados (Collector)\n#  - OTEL_EXPORTER_OTLP_PROTOCOL: protocolo de transporte (gRPC)\n#  - OTEL_TRACES_EXPORTER: exportar traces via OTLP (protocolo padrão OTel)\nexport OTEL_SERVICE_NAME=\"checkout-api\"\nexport OTEL_EXPORTER_OTLP_ENDPOINT=\"http:\u002F\u002Flocalhost:4317\"\nexport OTEL_EXPORTER_OTLP_PROTOCOL=\"grpc\"\nexport OTEL_TRACES_EXPORTER=\"otlp\"\n\n# Roda a aplicação instrumentada (na porta 8000)\nopentelemetry-instrument uvicorn app:app --reload --port 8000\n",[547,1687,1688,1693,1698,1703,1708,1713,1728,1740,1752,1764,1768,1773],{"__ignoreMap":549},[966,1689,1690],{"class":968,"line":969},[966,1691,1692],{"class":972},"# As variáveis de ambiente abaixo dizem ao OTel SDK:\n",[966,1694,1695],{"class":968,"line":976},[966,1696,1697],{"class":972},"#  - OTEL_SERVICE_NAME: nome do serviço que aparecerá no Jaeger\n",[966,1699,1700],{"class":968,"line":1017},[966,1701,1702],{"class":972},"#  - OTEL_EXPORTER_OTLP_ENDPOINT: para onde enviar os dados (Collector)\n",[966,1704,1705],{"class":968,"line":1024},[966,1706,1707],{"class":972},"#  - OTEL_EXPORTER_OTLP_PROTOCOL: protocolo de transporte (gRPC)\n",[966,1709,1710],{"class":968,"line":1030},[966,1711,1712],{"class":972},"#  - OTEL_TRACES_EXPORTER: exportar traces via OTLP (protocolo padrão OTel)\n",[966,1714,1715,1719,1722,1725],{"class":968,"line":1060},[966,1716,1718],{"class":1717},"szBVR","export",[966,1720,1721],{"class":979}," OTEL_SERVICE_NAME",[966,1723,1724],{"class":1717},"=",[966,1726,1727],{"class":990},"\"checkout-api\"\n",[966,1729,1730,1732,1735,1737],{"class":968,"line":1214},[966,1731,1718],{"class":1717},[966,1733,1734],{"class":979}," OTEL_EXPORTER_OTLP_ENDPOINT",[966,1736,1724],{"class":1717},[966,1738,1739],{"class":990},"\"http:\u002F\u002Flocalhost:4317\"\n",[966,1741,1742,1744,1747,1749],{"class":968,"line":1222},[966,1743,1718],{"class":1717},[966,1745,1746],{"class":979}," OTEL_EXPORTER_OTLP_PROTOCOL",[966,1748,1724],{"class":1717},[966,1750,1751],{"class":990},"\"grpc\"\n",[966,1753,1754,1756,1759,1761],{"class":968,"line":1230},[966,1755,1718],{"class":1717},[966,1757,1758],{"class":979}," OTEL_TRACES_EXPORTER",[966,1760,1724],{"class":1717},[966,1762,1763],{"class":990},"\"otlp\"\n",[966,1765,1766],{"class":968,"line":1238},[966,1767,1021],{"emptyLinePlaceholder":1020},[966,1769,1770],{"class":968,"line":1246},[966,1771,1772],{"class":972},"# Roda a aplicação instrumentada (na porta 8000)\n",[966,1774,1775,1777,1779,1782,1785,1788],{"class":968,"line":1252},[966,1776,1681],{"class":1164},[966,1778,1208],{"class":990},[966,1780,1781],{"class":990}," app:app",[966,1783,1784],{"class":983}," --reload",[966,1786,1787],{"class":983}," --port",[966,1789,1790],{"class":983}," 8000\n",[100,1792,1793,1794,1797,1798,1801],{},"A partir de agora, cada vez que alguém bater em ",[547,1795,1796],{},"http:\u002F\u002Flocalhost:8000\u002F","\nou ",[547,1799,1800],{},"http:\u002F\u002Flocalhost:8000\u002Flento",", sua aplicação vai gerar um trace e\nenviá-lo para o Collector (que então repassa para o Jaeger).",[172,1803,1805],{"id":1804},"passo-4-subir-o-collector-jaeger-e-prometheus-com-docker","Passo 4: subir o Collector, Jaeger e Prometheus com Docker",[100,1807,1808,1809,1812],{},"Para não instalar tudo à mão, use este ",[547,1810,1811],{},"docker-compose.yml"," que sobe os\ntrês componentes conectados:",[540,1814,1818],{"className":1815,"code":1816,"language":1817,"meta":549,"style":549},"language-yaml shiki shiki-themes github-light github-dark","# docker-compose.yml — pilha de observabilidade local\nversion: \"3.8\"\nservices:\n  # Collector: recebe dados via OTLP e distribui para os backends\n  otel-collector:\n    image: otel\u002Fopentelemetry-collector-contrib:0.108.0\n    command: [\"--config=\u002Fetc\u002Fotelcol\u002Fconfig.yaml\"]\n    volumes:\n      - .\u002Fotel-collector-config.yaml:\u002Fetc\u002Fotelcol\u002Fconfig.yaml\n    ports:\n      - \"4317:4317\"   # OTLP gRPC (onde sua app envia)\n      - \"4318:4318\"   # OTLP HTTP (alternativa)\n\n  # Jaeger: visualizador de traces (UI na porta 16686)\n  jaeger:\n    image: jaegertracing\u002Fall-in-one:1.60\n    environment:\n      - COLLECTOR_OTLP_ENABLED=true\n    ports:\n      - \"16686:16686\"   # interface web do Jaeger\n      - \"4317\"          # Jaeger também aceita OTLP direto\n\n  # Prometheus: armazena e consulta métricas (UI na porta 9090)\n  prometheus:\n    image: prom\u002Fprometheus:v2.54.1\n    volumes:\n      - .\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml\n    ports:\n      - \"9090:9090\"\n","yaml",[547,1819,1820,1825,1836,1844,1849,1856,1866,1880,1887,1895,1902,1912,1922,1926,1931,1938,1947,1954,1961,1967,1977,1987,1991,1996,2003,2012,2018,2025,2031],{"__ignoreMap":549},[966,1821,1822],{"class":968,"line":969},[966,1823,1824],{"class":972},"# docker-compose.yml — pilha de observabilidade local\n",[966,1826,1827,1831,1833],{"class":968,"line":976},[966,1828,1830],{"class":1829},"s9eBZ","version",[966,1832,987],{"class":979},[966,1834,1835],{"class":990},"\"3.8\"\n",[966,1837,1838,1841],{"class":968,"line":1017},[966,1839,1840],{"class":1829},"services",[966,1842,1843],{"class":979},":\n",[966,1845,1846],{"class":968,"line":1024},[966,1847,1848],{"class":972},"  # Collector: recebe dados via OTLP e distribui para os backends\n",[966,1850,1851,1854],{"class":968,"line":1030},[966,1852,1853],{"class":1829},"  otel-collector",[966,1855,1843],{"class":979},[966,1857,1858,1861,1863],{"class":968,"line":1060},[966,1859,1860],{"class":1829},"    image",[966,1862,987],{"class":979},[966,1864,1865],{"class":990},"otel\u002Fopentelemetry-collector-contrib:0.108.0\n",[966,1867,1868,1871,1874,1877],{"class":968,"line":1214},[966,1869,1870],{"class":1829},"    command",[966,1872,1873],{"class":979},": [",[966,1875,1876],{"class":990},"\"--config=\u002Fetc\u002Fotelcol\u002Fconfig.yaml\"",[966,1878,1879],{"class":979},"]\n",[966,1881,1882,1885],{"class":968,"line":1222},[966,1883,1884],{"class":1829},"    volumes",[966,1886,1843],{"class":979},[966,1888,1889,1892],{"class":968,"line":1230},[966,1890,1891],{"class":979},"      - ",[966,1893,1894],{"class":990},".\u002Fotel-collector-config.yaml:\u002Fetc\u002Fotelcol\u002Fconfig.yaml\n",[966,1896,1897,1900],{"class":968,"line":1238},[966,1898,1899],{"class":1829},"    ports",[966,1901,1843],{"class":979},[966,1903,1904,1906,1909],{"class":968,"line":1246},[966,1905,1891],{"class":979},[966,1907,1908],{"class":990},"\"4317:4317\"",[966,1910,1911],{"class":972},"   # OTLP gRPC (onde sua app envia)\n",[966,1913,1914,1916,1919],{"class":968,"line":1252},[966,1915,1891],{"class":979},[966,1917,1918],{"class":990},"\"4318:4318\"",[966,1920,1921],{"class":972},"   # OTLP HTTP (alternativa)\n",[966,1923,1924],{"class":968,"line":1257},[966,1925,1021],{"emptyLinePlaceholder":1020},[966,1927,1928],{"class":968,"line":1263},[966,1929,1930],{"class":972},"  # Jaeger: visualizador de traces (UI na porta 16686)\n",[966,1932,1933,1936],{"class":968,"line":1269},[966,1934,1935],{"class":1829},"  jaeger",[966,1937,1843],{"class":979},[966,1939,1940,1942,1944],{"class":968,"line":1275},[966,1941,1860],{"class":1829},[966,1943,987],{"class":979},[966,1945,1946],{"class":990},"jaegertracing\u002Fall-in-one:1.60\n",[966,1948,1949,1952],{"class":968,"line":1381},[966,1950,1951],{"class":1829},"    environment",[966,1953,1843],{"class":979},[966,1955,1956,1958],{"class":968,"line":1386},[966,1957,1891],{"class":979},[966,1959,1960],{"class":990},"COLLECTOR_OTLP_ENABLED=true\n",[966,1962,1963,1965],{"class":968,"line":1392},[966,1964,1899],{"class":1829},[966,1966,1843],{"class":979},[966,1968,1969,1971,1974],{"class":968,"line":1398},[966,1970,1891],{"class":979},[966,1972,1973],{"class":990},"\"16686:16686\"",[966,1975,1976],{"class":972},"   # interface web do Jaeger\n",[966,1978,1979,1981,1984],{"class":968,"line":1403},[966,1980,1891],{"class":979},[966,1982,1983],{"class":990},"\"4317\"",[966,1985,1986],{"class":972},"          # Jaeger também aceita OTLP direto\n",[966,1988,1989],{"class":968,"line":1409},[966,1990,1021],{"emptyLinePlaceholder":1020},[966,1992,1993],{"class":968,"line":1415},[966,1994,1995],{"class":972},"  # Prometheus: armazena e consulta métricas (UI na porta 9090)\n",[966,1997,1998,2001],{"class":968,"line":1420},[966,1999,2000],{"class":1829},"  prometheus",[966,2002,1843],{"class":979},[966,2004,2005,2007,2009],{"class":968,"line":1426},[966,2006,1860],{"class":1829},[966,2008,987],{"class":979},[966,2010,2011],{"class":990},"prom\u002Fprometheus:v2.54.1\n",[966,2013,2014,2016],{"class":968,"line":1431},[966,2015,1884],{"class":1829},[966,2017,1843],{"class":979},[966,2019,2020,2022],{"class":968,"line":1437},[966,2021,1891],{"class":979},[966,2023,2024],{"class":990},".\u002Fprometheus.yml:\u002Fetc\u002Fprometheus\u002Fprometheus.yml\n",[966,2026,2027,2029],{"class":968,"line":1443},[966,2028,1899],{"class":1829},[966,2030,1843],{"class":979},[966,2032,2033,2035],{"class":968,"line":1449},[966,2034,1891],{"class":979},[966,2036,2037],{"class":990},"\"9090:9090\"\n",[100,2039,2040,2041,2044],{},"E o arquivo de configuração do Collector (",[547,2042,2043],{},"otel-collector-config.yaml","):",[540,2046,2048],{"className":1815,"code":2047,"language":1817,"meta":549,"style":549},"# otel-collector-config.yaml — define os pipelines do Collector\nreceivers:\n  otlp:\n    protocols:\n      grpc:\n        endpoint: 0.0.0.0:4317\n      http:\n        endpoint: 0.0.0.0:4318\n\nprocessors:\n  batch:               # agrupa spans antes de enviar (eficiência)\n    timeout: 5s\n    send_batch_size: 1000\n\nexporters:\n  otlp\u002Fjaeger:         # envia traces para o Jaeger\n    endpoint: jaeger:4317\n    tls:\n      insecure: true\n  prometheus:          # expõe métricas em formato Prometheus\n    endpoint: 0.0.0.0:8889\n\nservice:\n  pipelines:\n    traces:            # pipeline de traces: recebe → processa → exporta\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [otlp\u002Fjaeger]\n    metrics:           # pipeline de métricas\n      receivers: [otlp]\n      processors: [batch]\n      exporters: [prometheus]\n",[547,2049,2050,2055,2062,2069,2076,2083,2093,2100,2109,2113,2120,2131,2141,2151,2155,2162,2173,2183,2190,2200,2210,2219,2223,2230,2237,2248,2260,2272,2284,2295,2305,2315],{"__ignoreMap":549},[966,2051,2052],{"class":968,"line":969},[966,2053,2054],{"class":972},"# otel-collector-config.yaml — define os pipelines do Collector\n",[966,2056,2057,2060],{"class":968,"line":976},[966,2058,2059],{"class":1829},"receivers",[966,2061,1843],{"class":979},[966,2063,2064,2067],{"class":968,"line":1017},[966,2065,2066],{"class":1829},"  otlp",[966,2068,1843],{"class":979},[966,2070,2071,2074],{"class":968,"line":1024},[966,2072,2073],{"class":1829},"    protocols",[966,2075,1843],{"class":979},[966,2077,2078,2081],{"class":968,"line":1030},[966,2079,2080],{"class":1829},"      grpc",[966,2082,1843],{"class":979},[966,2084,2085,2088,2090],{"class":968,"line":1060},[966,2086,2087],{"class":1829},"        endpoint",[966,2089,987],{"class":979},[966,2091,2092],{"class":990},"0.0.0.0:4317\n",[966,2094,2095,2098],{"class":968,"line":1214},[966,2096,2097],{"class":1829},"      http",[966,2099,1843],{"class":979},[966,2101,2102,2104,2106],{"class":968,"line":1222},[966,2103,2087],{"class":1829},[966,2105,987],{"class":979},[966,2107,2108],{"class":990},"0.0.0.0:4318\n",[966,2110,2111],{"class":968,"line":1230},[966,2112,1021],{"emptyLinePlaceholder":1020},[966,2114,2115,2118],{"class":968,"line":1238},[966,2116,2117],{"class":1829},"processors",[966,2119,1843],{"class":979},[966,2121,2122,2125,2128],{"class":968,"line":1246},[966,2123,2124],{"class":1829},"  batch",[966,2126,2127],{"class":979},":               ",[966,2129,2130],{"class":972},"# agrupa spans antes de enviar (eficiência)\n",[966,2132,2133,2136,2138],{"class":968,"line":1252},[966,2134,2135],{"class":1829},"    timeout",[966,2137,987],{"class":979},[966,2139,2140],{"class":990},"5s\n",[966,2142,2143,2146,2148],{"class":968,"line":1257},[966,2144,2145],{"class":1829},"    send_batch_size",[966,2147,987],{"class":979},[966,2149,2150],{"class":983},"1000\n",[966,2152,2153],{"class":968,"line":1263},[966,2154,1021],{"emptyLinePlaceholder":1020},[966,2156,2157,2160],{"class":968,"line":1269},[966,2158,2159],{"class":1829},"exporters",[966,2161,1843],{"class":979},[966,2163,2164,2167,2170],{"class":968,"line":1275},[966,2165,2166],{"class":1829},"  otlp\u002Fjaeger",[966,2168,2169],{"class":979},":         ",[966,2171,2172],{"class":972},"# envia traces para o Jaeger\n",[966,2174,2175,2178,2180],{"class":968,"line":1381},[966,2176,2177],{"class":1829},"    endpoint",[966,2179,987],{"class":979},[966,2181,2182],{"class":990},"jaeger:4317\n",[966,2184,2185,2188],{"class":968,"line":1386},[966,2186,2187],{"class":1829},"    tls",[966,2189,1843],{"class":979},[966,2191,2192,2195,2197],{"class":968,"line":1392},[966,2193,2194],{"class":1829},"      insecure",[966,2196,987],{"class":979},[966,2198,2199],{"class":983},"true\n",[966,2201,2202,2204,2207],{"class":968,"line":1398},[966,2203,2000],{"class":1829},[966,2205,2206],{"class":979},":          ",[966,2208,2209],{"class":972},"# expõe métricas em formato Prometheus\n",[966,2211,2212,2214,2216],{"class":968,"line":1403},[966,2213,2177],{"class":1829},[966,2215,987],{"class":979},[966,2217,2218],{"class":990},"0.0.0.0:8889\n",[966,2220,2221],{"class":968,"line":1409},[966,2222,1021],{"emptyLinePlaceholder":1020},[966,2224,2225,2228],{"class":968,"line":1415},[966,2226,2227],{"class":1829},"service",[966,2229,1843],{"class":979},[966,2231,2232,2235],{"class":968,"line":1420},[966,2233,2234],{"class":1829},"  pipelines",[966,2236,1843],{"class":979},[966,2238,2239,2242,2245],{"class":968,"line":1426},[966,2240,2241],{"class":1829},"    traces",[966,2243,2244],{"class":979},":            ",[966,2246,2247],{"class":972},"# pipeline de traces: recebe → processa → exporta\n",[966,2249,2250,2253,2255,2258],{"class":968,"line":1431},[966,2251,2252],{"class":1829},"      receivers",[966,2254,1873],{"class":979},[966,2256,2257],{"class":990},"otlp",[966,2259,1879],{"class":979},[966,2261,2262,2265,2267,2270],{"class":968,"line":1437},[966,2263,2264],{"class":1829},"      processors",[966,2266,1873],{"class":979},[966,2268,2269],{"class":990},"batch",[966,2271,1879],{"class":979},[966,2273,2274,2277,2279,2282],{"class":968,"line":1443},[966,2275,2276],{"class":1829},"      exporters",[966,2278,1873],{"class":979},[966,2280,2281],{"class":990},"otlp\u002Fjaeger",[966,2283,1879],{"class":979},[966,2285,2286,2289,2292],{"class":968,"line":1449},[966,2287,2288],{"class":1829},"    metrics",[966,2290,2291],{"class":979},":           ",[966,2293,2294],{"class":972},"# pipeline de métricas\n",[966,2296,2297,2299,2301,2303],{"class":968,"line":1454},[966,2298,2252],{"class":1829},[966,2300,1873],{"class":979},[966,2302,2257],{"class":990},[966,2304,1879],{"class":979},[966,2306,2307,2309,2311,2313],{"class":968,"line":1460},[966,2308,2264],{"class":1829},[966,2310,1873],{"class":979},[966,2312,2269],{"class":990},[966,2314,1879],{"class":979},[966,2316,2317,2319,2321,2324],{"class":968,"line":1466},[966,2318,2276],{"class":1829},[966,2320,1873],{"class":979},[966,2322,2323],{"class":990},"prometheus",[966,2325,1879],{"class":979},[100,2327,2328],{},"Suba tudo com:",[540,2330,2332],{"className":1150,"code":2331,"language":1152,"meta":549,"style":549},"docker compose up -d\n",[547,2333,2334],{"__ignoreMap":549},[966,2335,2336,2339,2342,2345],{"class":968,"line":969},[966,2337,2338],{"class":1164},"docker",[966,2340,2341],{"class":990}," compose",[966,2343,2344],{"class":990}," up",[966,2346,2347],{"class":983}," -d\n",[93,2349],{},[11,2351,2353],{"id":2352},"visualizando-traces-no-jaeger-jaeger","Visualizando traces no Jaeger {#jaeger}",[100,2355,2356,2359],{},[104,2357,2358],{},"Jaeger"," (pronuncia-se \"iéguer\", é uma palavra alemã que significa\n\"caçador\") é uma ferramenta open source de UI para visualizar traces.\nFoi criada pela Uber e hoje é mantida pela CNCF — mesma casa do\nOpenTelemetry e do Kubernetes.",[100,2361,2362,2363,2366],{},"Depois de subir a pilha e fazer algumas requisições na sua API, abra o\nnavegador em ",[547,2364,2365],{},"http:\u002F\u002Flocalhost:16686",". Você verá:",[16,2368,2369,2383,2393,2399],{},[19,2370,2371,2374,2375,2378,2379,2382],{},[104,2372,2373],{},"Seletor de serviço"," (canto superior esquerdo): um dropdown onde\nvocê escolhe qual serviço quer inspecionar. Deve aparecer\n",[547,2376,2377],{},"checkout-api"," (o nome que definimos em ",[547,2380,2381],{},"OTEL_SERVICE_NAME",").",[19,2384,2385,2388,2389,2392],{},[104,2386,2387],{},"Filtros de busca",": pode filtrar por tag (ex.:\n",[547,2390,2391],{},"http.status_code=500","), por duração mínima, por operação.",[19,2394,2395,2398],{},[104,2396,2397],{},"Botão \"Find Traces\"",": lista os traces recentes que casam com os\nfiltros.",[19,2400,2401,2404],{},[104,2402,2403],{},"Detalhe do trace",": ao clicar num trace, vê-se a cascata (waterfall)\nde spans com a linha do tempo e a hierarquia pai-filho.",[172,2406,2408],{"id":2407},"o-que-procurar-no-jaeger","O que procurar no Jaeger",[238,2410,2411,2421],{},[241,2412,2413],{},[244,2414,2415,2418],{},[247,2416,2417],{},"Sinal visual no Jaeger",[247,2419,2420],{},"O que provavelmente significa",[255,2422,2423,2431,2439,2447,2455],{},[244,2424,2425,2428],{},[260,2426,2427],{},"Um span muito mais largo que os outros",[260,2429,2430],{},"Gargalo de latência — investigue essa operação",[244,2432,2433,2436],{},[260,2434,2435],{},"Span vermelho (com erro)",[260,2437,2438],{},"Exceção capturada — clique para ver a stack",[244,2440,2441,2444],{},[260,2442,2443],{},"Muitos spans filhos em série",[260,2445,2446],{},"Talvez possa paralelizar as chamadas",[244,2448,2449,2452],{},[260,2450,2451],{},"Span de chamada externa dominando",[260,2453,2454],{},"Backend\u002FAPI de terceiros lento",[244,2456,2457,2460],{},[260,2458,2459],{},"Trace com poucos spans",[260,2461,2462],{},"Instrumentação faltando — serviço \"cego\"",[136,2464,2465],{},[100,2466,2467,2470,2471,2473,2474,2477],{},[104,2468,2469],{},"Dica de ouro",": copie o ",[547,2472,953],{}," que aparece no detalhe de um trace\nno Jaeger e cole na sua ferramenta de logs (Loki, Elasticsearch, etc.).\nCom isso, você vê ",[104,2475,2476],{},"todas as mensagens de log"," geradas por aquela\nrequisição específica, em todos os serviços. É a mágica do \"logs com\ncontexto de trace\" que mencionamos antes.",[93,2479],{},[11,2481,2483],{"id":2482},"coletando-métricas-com-prometheus-prometheus","Coletando métricas com Prometheus {#prometheus}",[100,2485,2486,2489,2490,2493,2494,2497],{},[104,2487,2488],{},"Prometheus"," é um banco de dados de séries temporais (TSDB — ",[123,2491,2492],{},"Time\nSeries DataBase",") e um sistema de coleta de métricas. É o padrão de\nfato para métricas no mundo cloud native. Diferente do Jaeger (que\nrecebe traces por push), o Prometheus funciona por ",[104,2495,2496],{},"pull",": ele vai\naté sua aplicação e pergunta \"me dá suas métricas\" em intervalos\nregulares (scrape).",[100,2499,2500,2501,2504,2505,2507],{},"Para que o Prometheus encontre sua aplicação, ela precisa expor um\nendpoint HTTP (geralmente ",[547,2502,2503],{},"\u002Fmetrics",") com as métricas num formato de\ntexto específico. No nosso setup, é o ",[104,2506,537],{}," que expõe esse\nendpoint (na porta 8889, conforme a config), agregando métricas de\ntodas as apps.",[100,2509,2510,2511,1295],{},"Arquivo ",[547,2512,2513],{},"prometheus.yml",[540,2515,2517],{"className":1815,"code":2516,"language":1817,"meta":549,"style":549},"# prometheus.yml — configura o scrape do Prometheus\nglobal:\n  scrape_interval: 15s      # coleta métricas a cada 15s\n\nscrape_configs:\n  - job_name: \"otel-collector\"\n    static_configs:\n      - targets: [\"otel-collector:8889\"]   # onde o Collector expõe métricas\n",[547,2518,2519,2524,2531,2544,2548,2555,2568,2575],{"__ignoreMap":549},[966,2520,2521],{"class":968,"line":969},[966,2522,2523],{"class":972},"# prometheus.yml — configura o scrape do Prometheus\n",[966,2525,2526,2529],{"class":968,"line":976},[966,2527,2528],{"class":1829},"global",[966,2530,1843],{"class":979},[966,2532,2533,2536,2538,2541],{"class":968,"line":1017},[966,2534,2535],{"class":1829},"  scrape_interval",[966,2537,987],{"class":979},[966,2539,2540],{"class":990},"15s",[966,2542,2543],{"class":972},"      # coleta métricas a cada 15s\n",[966,2545,2546],{"class":968,"line":1024},[966,2547,1021],{"emptyLinePlaceholder":1020},[966,2549,2550,2553],{"class":968,"line":1030},[966,2551,2552],{"class":1829},"scrape_configs",[966,2554,1843],{"class":979},[966,2556,2557,2560,2563,2565],{"class":968,"line":1060},[966,2558,2559],{"class":979},"  - ",[966,2561,2562],{"class":1829},"job_name",[966,2564,987],{"class":979},[966,2566,2567],{"class":990},"\"otel-collector\"\n",[966,2569,2570,2573],{"class":968,"line":1214},[966,2571,2572],{"class":1829},"    static_configs",[966,2574,1843],{"class":979},[966,2576,2577,2579,2582,2584,2587,2590],{"class":968,"line":1222},[966,2578,1891],{"class":979},[966,2580,2581],{"class":1829},"targets",[966,2583,1873],{"class":979},[966,2585,2586],{"class":990},"\"otel-collector:8889\"",[966,2588,2589],{"class":979},"]   ",[966,2591,2592],{"class":972},"# onde o Collector expõe métricas\n",[100,2594,2595,2596,2599,2600,2603],{},"Abra ",[547,2597,2598],{},"http:\u002F\u002Flocalhost:9090"," para acessar a UI do Prometheus. Algumas\nqueries úteis para começar (na linguagem ",[104,2601,2602],{},"PromQL",", a query language do\nPrometheus):",[540,2605,2609],{"className":2606,"code":2607,"language":2608,"meta":549,"style":549},"language-promql shiki shiki-themes github-light github-dark","# Taxa de requisições por segundo nos últimos 5 minutos\nrate(http_server_request_duration_seconds_count[5m])\n\n# p99 da latência das requisições\nhistogram_quantile(0.99, rate(\n  http_server_request_duration_seconds_bucket[5m]\n))\n\n# Erros 500 por minuto\nsum(rate(http_server_request_duration_seconds_count{\n  http_status_code=\"500\"\n}[1m])) by (service_name)\n","promql",[547,2610,2611,2616,2621,2625,2630,2635,2640,2645,2649,2654,2659,2664],{"__ignoreMap":549},[966,2612,2613],{"class":968,"line":969},[966,2614,2615],{},"# Taxa de requisições por segundo nos últimos 5 minutos\n",[966,2617,2618],{"class":968,"line":976},[966,2619,2620],{},"rate(http_server_request_duration_seconds_count[5m])\n",[966,2622,2623],{"class":968,"line":1017},[966,2624,1021],{"emptyLinePlaceholder":1020},[966,2626,2627],{"class":968,"line":1024},[966,2628,2629],{},"# p99 da latência das requisições\n",[966,2631,2632],{"class":968,"line":1030},[966,2633,2634],{},"histogram_quantile(0.99, rate(\n",[966,2636,2637],{"class":968,"line":1060},[966,2638,2639],{},"  http_server_request_duration_seconds_bucket[5m]\n",[966,2641,2642],{"class":968,"line":1214},[966,2643,2644],{},"))\n",[966,2646,2647],{"class":968,"line":1222},[966,2648,1021],{"emptyLinePlaceholder":1020},[966,2650,2651],{"class":968,"line":1230},[966,2652,2653],{},"# Erros 500 por minuto\n",[966,2655,2656],{"class":968,"line":1238},[966,2657,2658],{},"sum(rate(http_server_request_duration_seconds_count{\n",[966,2660,2661],{"class":968,"line":1246},[966,2662,2663],{},"  http_status_code=\"500\"\n",[966,2665,2666],{"class":968,"line":1252},[966,2667,2668],{},"}[1m])) by (service_name)\n",[100,2670,2671,2672,2675],{},"Não se assuste com a sintaxe — PromQL parece estranha no começo, mas\nsegue uma lógica consistente. O importante agora é saber que essas\nconsultas alimentam dashboards (no ",[104,2673,2674],{},"Grafana",", por exemplo) e alertas.",[93,2677],{},[11,2679,2681],{"id":2680},"erros-comuns-e-como-evitá-los-erros","Erros comuns (e como evitá-los) {#erros}",[172,2683,2685],{"id":2684},"_1-instrumentar-tudo-e-não-filtrar-nada","1. Instrumentar tudo e não filtrar nada",[100,2687,2688,2691],{},[104,2689,2690],{},"O erro",": ligar a instrumentação automática em tudo, sem ajustar\namostragem, e descobrir no fim do mês que você tem 500GB de traces que\nnão consegue pagar para armazenar.",[100,2693,2694,2697,2698,199,2701,2704,2705,2708],{},[104,2695,2696],{},"A solução",": use ",[104,2699,2700],{},"amostragem",[123,2702,2703],{},"sampling","). Em produção, na maioria\ndos casos, você não precisa de 100% dos traces — 1% a 10% costumam ser\nsuficientes para detectar padrões. Reserve amostragem de 100% só para\ntraces com erro. O OpenTelemetry suporta isso via ",[104,2706,2707],{},"tail sampling"," no\nCollector (decide depois de o trace terminar, mantendo os que tiveram\nerro).",[540,2710,2712],{"className":1815,"code":2711,"language":1817,"meta":549,"style":549},"# Exemplo de tail sampling no Collector — mantém 100% dos traces com erro\nprocessors:\n  tail_sampling:\n    decision_wait: 10s\n    policies:\n      - name: errors\n        type: status_code\n        status_code:\n          status_codes: [ERROR]\n      - name: sample-rest\n        type: probabilistic\n        probabilistic:\n          sampling_percentage: 5\n",[547,2713,2714,2719,2725,2732,2742,2749,2761,2771,2778,2790,2801,2810,2817],{"__ignoreMap":549},[966,2715,2716],{"class":968,"line":969},[966,2717,2718],{"class":972},"# Exemplo de tail sampling no Collector — mantém 100% dos traces com erro\n",[966,2720,2721,2723],{"class":968,"line":976},[966,2722,2117],{"class":1829},[966,2724,1843],{"class":979},[966,2726,2727,2730],{"class":968,"line":1017},[966,2728,2729],{"class":1829},"  tail_sampling",[966,2731,1843],{"class":979},[966,2733,2734,2737,2739],{"class":968,"line":1024},[966,2735,2736],{"class":1829},"    decision_wait",[966,2738,987],{"class":979},[966,2740,2741],{"class":990},"10s\n",[966,2743,2744,2747],{"class":968,"line":1030},[966,2745,2746],{"class":1829},"    policies",[966,2748,1843],{"class":979},[966,2750,2751,2753,2756,2758],{"class":968,"line":1060},[966,2752,1891],{"class":979},[966,2754,2755],{"class":1829},"name",[966,2757,987],{"class":979},[966,2759,2760],{"class":990},"errors\n",[966,2762,2763,2766,2768],{"class":968,"line":1214},[966,2764,2765],{"class":1829},"        type",[966,2767,987],{"class":979},[966,2769,2770],{"class":990},"status_code\n",[966,2772,2773,2776],{"class":968,"line":1222},[966,2774,2775],{"class":1829},"        status_code",[966,2777,1843],{"class":979},[966,2779,2780,2783,2785,2788],{"class":968,"line":1230},[966,2781,2782],{"class":1829},"          status_codes",[966,2784,1873],{"class":979},[966,2786,2787],{"class":990},"ERROR",[966,2789,1879],{"class":979},[966,2791,2792,2794,2796,2798],{"class":968,"line":1238},[966,2793,1891],{"class":979},[966,2795,2755],{"class":1829},[966,2797,987],{"class":979},[966,2799,2800],{"class":990},"sample-rest\n",[966,2802,2803,2805,2807],{"class":968,"line":1246},[966,2804,2765],{"class":1829},[966,2806,987],{"class":979},[966,2808,2809],{"class":990},"probabilistic\n",[966,2811,2812,2815],{"class":968,"line":1252},[966,2813,2814],{"class":1829},"        probabilistic",[966,2816,1843],{"class":979},[966,2818,2819,2822,2824],{"class":968,"line":1257},[966,2820,2821],{"class":1829},"          sampling_percentage",[966,2823,987],{"class":979},[966,2825,2826],{"class":983},"5\n",[172,2828,2830],{"id":2829},"_2-esconder-o-trace_id-dos-logs","2. Esconder o trace_id dos logs",[100,2832,2833,2835],{},[104,2834,2690],{},": usar logging tradicional sem integrar com o OTel. Quando um\nincidente acontece, você tem traces no Jaeger e logs no Loki, mas nenhum\njeito de conectá-los. Cada ferramenta vira uma ilha.",[100,2837,2838,2840,2841,2844,2845,111,2847,2849],{},[104,2839,2696],{},": sempre use ",[547,2842,2843],{},"LoggingInstrumentor"," (ou equivalente na sua\nlinguagem) para injetar ",[547,2846,953],{},[547,2848,956],{}," em cada log. Custo quase\nzero, benefício enorme.",[172,2851,2853],{"id":2852},"_3-usar-a-média-para-latência","3. Usar a média para latência",[100,2855,2856,2858],{},[104,2857,2690],{},": montar um dashboard de \"latência média\" e achar que está\ntudo bem quando ela dá 200ms. O problema: a média esconde os outliers.\nSe 99 pessoas tiveram 50ms e 1 teve 10 segundos, a média parece ok, mas\naquele 1 usuário teve uma experiência terrível.",[100,2860,2861,2863,2864,2867],{},[104,2862,2696],{},": acompanhe ",[104,2865,2866],{},"percentis"," — p50, p90, p95 e p99. O p99\nte diz \"1% dos seus usuários está sofrendo quanto?\".",[172,2869,2871],{"id":2870},"_4-alertar-em-sintoma-não-em-causa","4. Alertar em sintoma, não em causa",[100,2873,2874,2876,2877,2879],{},[104,2875,2690],{},": criar um alerta \"latência > 1s\" sem ter uma forma de saber\n",[123,2878,129],{}," a latência subiu. O alerta dispara, a equipe acorda, e ninguém\nsabe onde olhar.",[100,2881,2882,2884],{},[104,2883,2696],{},": alertas em métricas (sintoma) devem sempre ter um caminho\nclaro para traces e logs (causa). Se um alerta dispara, o primeiro link\nna notificação deveria ser uma query do Jaeger pré-filtrada para o\nserviço e janela de tempo em questão.",[172,2886,2888],{"id":2887},"_5-tratar-observabilidade-como-coisa-de-sre","5. Tratar observabilidade como \"coisa de SRE\"",[100,2890,2891,2893,2894,2897],{},[104,2892,2690],{},": achar que observabilidade é responsabilidade só do time de\nSRE (",[123,2895,2896],{},"Site Reliability Engineering",", engenharia de confiabilidade) ou\nDevOps. Os desenvolvedores escrevem o código \"cego\" e jogam o problema\nde depuração por cima do muro.",[100,2899,2900,2902,2903,2906],{},[104,2901,2696],{},": observabilidade é responsabilidade de quem escreve o\ncódigo. Se você escreve um serviço, você é quem mais entende quais\nspans, métricas e logs fazem sentido ali. Instrumentar deve fazer parte\nda definição de pronto (DoD — ",[123,2904,2905],{},"Definition of Done",") de qualquer feature.",[172,2908,2910],{"id":2909},"_6-espalhar-nomes-de-spans-inconsistentes","6. Espalhar nomes de spans inconsistentes",[100,2912,2913,2915,2916,2919,2920,2923,2924,2927],{},[104,2914,2690],{},": um desenvolvedor chama o span de ",[547,2917,2918],{},"GET \u002Fusers",", outro de\n",[547,2921,2922],{},"buscar_usuarios",", outro de ",[547,2925,2926],{},"UserController.list",". O mesmo trabalho\naparece com três nomes diferentes no Jaeger, dificultando buscas.",[100,2929,2930,2932,2933,2936,2937,150,2940,150,2943,2946],{},[104,2931,2696],{},": defina uma convenção de nomenclatura. O OpenTelemetry\nrecomenda o padrão ",[547,2934,2935],{},"{tipo}.{operação}.{atributo}"," — ex.:\n",[547,2938,2939],{},"http.server.request",[547,2941,2942],{},"db.query.select",[547,2944,2945],{},"messaging.publish",". Padronize\ne documente.",[93,2948],{},[11,2950,2952],{"id":2951},"conclusão-e-próximos-passos-conclusao","Conclusão e próximos passos {#conclusao}",[100,2954,2955,2956,2959],{},"Observabilidade não é uma ferramenta que você compra — é uma ",[104,2957,2958],{},"capacidade","\nque você constrói combinando dados certos (traces, métricas, logs),\nferramentas certas (OpenTelemetry como padrão, Jaeger e Prometheus como\nbackends) e práticas certas (instrumentar desde o início, conectar logs\na traces, alertar com caminho para a causa).",[100,2961,2962],{},"Comece pequeno:",[16,2964,2965,2971,2977,2983,2989],{},[19,2966,2967,2970],{},[104,2968,2969],{},"Instrumente um serviço"," com OpenTelemetry (use nosso exemplo do\nFastAPI como ponto de partida).",[19,2972,2973,2976],{},[104,2974,2975],{},"Suba a pilha local"," com o docker-compose que mostramos.",[19,2978,2979,2982],{},[104,2980,2981],{},"Veja um trace no Jaeger"," — esse \"aha moment\" vale mais que mil\npalavras.",[19,2984,2985,2988],{},[104,2986,2987],{},"Adicione métricas"," e monte um dashboard simples no Grafana.",[19,2990,2991,2994,2995,2997],{},[104,2992,2993],{},"Integre logs"," com ",[547,2996,953],{}," e sinta a diferença ao depurar.",[100,2999,3000,3001,3004],{},"A beleza de usar OpenTelemetry é que, quando você crescer e quiser\ntrocar Jaeger por Tempo, ou Prometheus por Mimir, ou adicionar um\nbackend comercial como Datadog — ",[104,3002,3003],{},"seu código não muda",". Você\ninstrumentou uma vez e fica livre para escolher o melhor destino para\nseus dados.",[93,3006],{},[172,3008,3010],{"id":3009},"a-inicialize-tec-pode-te-ajudar-com-isso","A Inicialize Tec pode te ajudar com isso",[100,3012,3013,3014,3016],{},"Implementar observabilidade do zero pode parecer intimidador — há muitas\ndecisões de arquitetura, configuração de Collector, escolha de backends,\npadronização entre times. A ",[104,3015,6],{}," ajuda empresas a saírem\ndo \"alarme de incêndio\" e chegarem à observabilidade de verdade:\ninstrumentação com OpenTelemetry, pilhas com Jaeger\u002FPrometheus\u002FGrafana\nou soluções comerciais, dashboards e alertas que realmente reduzem\nMTTD e MTTR.",[100,3018,3019],{},"Fale com a gente para uma consultoria de observabilidade sob medida\npara o seu stack. Transformamos \"por que está lento?\" em resposta em\nminutos, não em horas.",[100,3021,3022,3023],{},"→ ",[104,3024,3025],{},[22,3026,3028],{"href":3027},"\u002F#contato","Converse com a Inicialize Tec",[3030,3031,3032],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}",{"title":549,"searchDepth":1017,"depth":1017,"links":3034},[3035,3036,3039,3040,3043,3048,3052,3055,3056,3063,3066,3067,3075],{"id":13,"depth":976,"text":14},{"id":97,"depth":976,"text":98,"children":3037},[3038],{"id":174,"depth":1017,"text":175},{"id":213,"depth":976,"text":214},{"id":338,"depth":976,"text":339,"children":3041},[3042],{"id":368,"depth":1017,"text":369},{"id":459,"depth":976,"text":460,"children":3044},[3045,3046,3047],{"id":487,"depth":1017,"text":488},{"id":513,"depth":1017,"text":514},{"id":552,"depth":1017,"text":553},{"id":630,"depth":976,"text":631,"children":3049},[3050,3051],{"id":651,"depth":1017,"text":652},{"id":736,"depth":1017,"text":737},{"id":766,"depth":976,"text":767,"children":3053},[3054],{"id":824,"depth":1017,"text":825},{"id":913,"depth":976,"text":914},{"id":1123,"depth":976,"text":1124,"children":3057},[3058,3059,3060,3061,3062],{"id":1134,"depth":1017,"text":1135},{"id":1146,"depth":1017,"text":1147},{"id":1287,"depth":1017,"text":1288},{"id":1674,"depth":1017,"text":1675},{"id":1804,"depth":1017,"text":1805},{"id":2352,"depth":976,"text":2353,"children":3064},[3065],{"id":2407,"depth":1017,"text":2408},{"id":2482,"depth":976,"text":2483},{"id":2680,"depth":976,"text":2681,"children":3068},[3069,3070,3071,3072,3073,3074],{"id":2684,"depth":1017,"text":2685},{"id":2829,"depth":1017,"text":2830},{"id":2852,"depth":1017,"text":2853},{"id":2870,"depth":1017,"text":2871},{"id":2887,"depth":1017,"text":2888},{"id":2909,"depth":1017,"text":2910},{"id":2951,"depth":976,"text":2952,"children":3076},[3077],{"id":3009,"depth":1017,"text":3010},"infraestrutura","2026-08-26","O que é observabilidade, por que importa e como implementar com OpenTelemetry: traces, métricas e logs explicados com analogias do dia-a-dia.","md",[3083,465,3084,3085,3086,3087,2358,2488],"observabilidade","tracing","metrics","logs","monitoring",{},"\u002Finfraestrutura\u002Fobservabilidade-com-opentelemetry",{"title":5,"description":3080},"observabilidade-com-opentelemetry","infraestrutura\u002Fobservabilidade-com-opentelemetry","o74CFjeNRpxxEnKaxNOXlzzyoYYHBX1g1-SASroUJYM",1787796309109]