← Voltar para o blog

Flight Recorder: Nova Ferramenta de Diagnóstico no Go 1.25

Go 1.25 traz o Flight Recorder, uma ferramenta poderosa para diagnosticar problemas de performance em serviços web de longa duração.

Em 2024, introduzimos ao mundo os execution traces mais poderosos do Go. Naquele post, demos uma prévia de novas funcionalidades que poderíamos desbloquear, incluindo o flight recording. Estamos felizes em anunciar que o flight recording está agora disponível no Go 1.25.

O Problema com Traces Tradicionais

O pacote runtime/trace fornece uma API para coletar traces de execução chamando runtime/trace.Start e runtime/trace.Stop. Isso funciona bem para testes e benchmarks.

Porém, em serviços web de longa duração — o tipo de aplicação pelo qual Go é conhecido — isso não é suficiente. Servidores web podem ficar no ar por dias ou semanas, e coletar um trace da execução inteira produziria dados demais.

Frequentemente, apenas uma parte da execução dá errado, como um request com timeout ou uma health check falhando. Quando isso acontece, já é tarde demais para chamar Start!

A Solução: Flight Recorder

O flight recorder funciona como uma “caixa preta” de avião:

  1. Coleta contínua: O trace de execução é coletado normalmente
  2. Buffer circular: Os últimos segundos são mantidos em memória
  3. Snapshot sob demanda: Quando algo dá errado, você captura exatamente a janela problemática

O flight recorder é como um bisturi cortando direto na área problemática.

Exemplo Prático

Imagine um servidor HTTP que implementa um jogo de “adivinhe o número”:

type bucket struct {
    mu      sync.Mutex
    guesses int
}

func main() {
    buckets := make([]bucket, 100)
    
    // Envio de relatório a cada minuto
    go func() {
        for range time.Tick(1 * time.Minute) {
            sendReport(buckets)
        }
    }()
    
    answer := rand.Intn(len(buckets))
    
    http.HandleFunc("/guess-number", func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        guess, err := strconv.Atoi(r.URL.Query().Get("guess"))
        if err != nil || !(0 <= guess && guess < len(buckets)) {
            http.Error(w, "invalid 'guess' value", http.StatusBadRequest)
            return
        }
        
        b := &buckets[guess]
        b.mu.Lock()
        b.guesses++
        b.mu.Unlock()
        
        fmt.Fprintf(w, "guess: %d, correct: %t", guess, guess == answer)
        
        log.Printf("HTTP request: guess=%d duration=%s", guess, time.Since(start))
    })
    
    log.Fatal(http.ListenAndServe(":8090", nil))
}

O Problema

Após deploy, usuários reclamam que algumas chamadas a /guess-number demoram mais de 100ms, enquanto a maioria leva microsegundos.

2025/09/19 16:52:02 HTTP request: guess=69 duration=625ns
2025/09/19 16:52:02 HTTP request: guess=42 duration=150ms  // ← problema!

A Solução com Flight Recorder

Com o flight recorder, podemos capturar exatamente o que aconteceu nos segundos antes da lentidão, identificando a causa raiz (spoiler: provavelmente um lock contention com a goroutine de relatório).

Como Usar

import "runtime/trace"

// Iniciar flight recorder (buffer de 5 segundos)
fr := trace.NewFlightRecorder()
fr.Start()

// Quando algo der errado...
if requestDuration > 100*time.Millisecond {
    data := fr.Snapshot()
    // Salvar ou analisar o trace
    os.WriteFile("slow-request.trace", data, 0644)
}

Conclusão

O flight recorder é uma ferramenta poderosa para diagnosticar problemas de performance em produção. Diferente de traces tradicionais que exigem antecipar o problema, o flight recorder permite olhar para o passado quando algo dá errado.


Traduzido e adaptado do Go Blog