Noções Básicas de Solução de Problemas em Produção
10 exemplos para você começar com Solução de Problemas em Produção - 7 básicos e 3 intermediários.
Busque em todas as páginas da documentação
10 exemplos para você começar com Solução de Problemas em Produção - 7 básicos e 3 intermediários.
mkdir triagelab && cd triagelab && go mod init example.com/triagelab.go get github.com/prometheus/client_golang/prometheus/promhttp ao exportar métricas.Pacotes de suporte precisam da versão exata do Go e metadados de build durante incidentes.
package main
import (
"log/slog"
"runtime"
"runtime/debug"
)
func main() {
info, _ := debug.ReadBuildInfo()
slog.Info("iniciando",
"go", runtime.Version(),
"module", info.Main.Path,
"version", info.Main.Version,
)
}runtime.Version() relata a toolchain que compilou o binário.debug.ReadBuildInfo() incorpora a versão do módulo de -ldflags ou releases marcadas.Relacionado: Resposta a Incidentes para Serviços Go - modelo mental de triagem
Logs estruturados conectam mensagens de timeout espalhadas a uma única requisição do cliente.
package main
import (
"log/slog"
"net/http"
)
func withRequestID(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
id := r.Header.Get("X-Request-ID")
if id == "" {
id = "generated-" + r.URL.Path
}
logger := slog.With("request_id", id)
ctx := r.Context()
_ = logger
next.ServeHTTP(w, r.WithContext(ctx))
})
}X-Request-ID da entrada ou gere um por requisição.slog.With para que cada linha de log na cadeia de handlers a compartilhe.request_id durante a triagem de incidentes.Relacionado: Logging Estruturado com slog - handlers de produção
Perfis de runtime são o caminho mais rápido de "lento" para "qual função".
package main
import (
"log"
"net/http"
_ "net/http/pprof"
)
func main() {
go func() {
admin := http.NewServeMux()
admin.Handle("/debug/", http.DefaultServeMux)
log.Println(http.ListenAndServe("127.0.0.1:6060", admin))
}()
select {}
}_ "net/http/pprof" registra os manipuladores de perfil padrão no DefaultServeMux.127.0.0.1 ou apenas a uma rede interna.go tool pprof http://127.0.0.1:6060/debug/pprof/profile?seconds=20 sob carga.Relacionado: Perfilamento de CPU e Heap ao Vivo Sob Carga de Incidentes - coleta segura contra incidentes
Taxa, erros e histogramas de duração respondem "isso é um problema do Go ou do tráfego?"
package main
import (
"net/http"
"time"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var reqDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Buckets: prometheus.DefBuckets,
}, []string{"route", "code"})
func main() {
http.Handle("/metrics", promhttp.Handler())
http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
w.WriteHeader(http.StatusOK)
reqDuration.WithLabelValues("/api", "200").Observe(time.Since(start).Seconds())
})
http.ListenAndServe(":8080", nil)
}http_request_duration_seconds alimenta dashboards p99.Relacionado: Métricas Prometheus & Dashboards RED-USE - design de dashboard
Uma contagem crescente de goroutines muitas vezes precede incidentes de memória e latência.
package main
import (
"expvar"
"runtime"
)
func init() {
expvar.Publish("goroutines", expvar.Func(func() any {
return runtime.NumGoroutine()
}))
}expvar expõe valores em /debug/vars quando montado em seu mux de administração.goroutines ao lado do heap e da taxa de requisições durante incidentes.Relacionado: Análise de Dump de Goroutines & Perfil de Vazamento - leitura de stacks
O esgotamento do pool se parece com timeouts do aplicativo enquanto o banco de dados está saudável.
package main
import (
"database/sql"
"log"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
)
func logDBStats(db *sql.DB) {
ticker := time.NewTicker(30 * time.Second)
for range ticker.C {
s := db.Stats()
log.Printf("db open=%d inUse=%d idle=%d waitCount=%d waitDur=%s",
s.OpenConnections, s.InUse, s.Idle, s.WaitCount, s.WaitDuration)
}
}WaitCount e WaitDuration crescentes significam que os handlers bloqueiam em db.Conn.Relacionado: Esgotamento do Pool de Conexões de Banco de Dados - playbook de saturação
A correlação de deploy é a hipótese de incidente mais rápida.
package main
import (
"encoding/json"
"net/http"
"os"
)
var buildSHA = os.Getenv("BUILD_SHA")
func health(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "ok",
"build": buildSHA,
})
}BUILD_SHA do CI no ambiente do contêiner.Relacionado: Probes de Saúde, Prontidão e Vivacidade - semântica de probes
Acione um perfil curto de um endpoint seguro durante um incidente ativo.
package main
import (
"net/http"
_ "net/http/pprof"
"os"
"time"
)
func profileHandler(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("X-On-Call-Token") != os.Getenv("ONCALL_TOKEN") {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
http.Redirect(w, r, "/debug/pprof/profile?seconds=20", http.StatusTemporaryRedirect)
}Relacionado: Perfilamento de CPU e Heap com pprof - leitura de flame graphs
Reiniciar no meio de uma requisição causa picos falsos de 5xx que parecem regressões de código.
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
srv := &http.Server{Addr: ":8080"}
go srv.ListenAndServe()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal(err)
}
}Shutdown para de aceitar novas conexões e aguarda as requisições em andamento.terminationGracePeriodSeconds do Kubernetes.Relacionado: Desligamento Gracioso & Tratamento de Sinais - padrões de produção
Post-mortems precisam de arquivos, não apenas capturas de tela.
mkdir -p /tmp/incident-$(date +%Y%m%d%H%M)
curl -s "http://127.0.0.1:6060/debug/pprof/profile?seconds=20" > /tmp/incident-*/cpu.prof
curl -s "http://127.0.0.1:6060/debug/pprof/heap" > /tmp/incident-*/heap.prof
curl -s "http://127.0.0.1:6060/debug/pprof/goroutine?debug=2" > /tmp/incident-*/goroutine.txt
go tool pprof -top /tmp/incident-*/cpu.prof > /tmp/incident-*/cpu-top.txtRelacionado: Modelo de Post-Mortem para Incidentes Go - estrutura de RCA
Versões da Stack: Esta página foi escrita para Go 1.26.x (padrão Green Tea GC, go fix modernizers - verifique o patch na build), chi (última - verifique na build), gin (última - verifique na build), echo (última - verifique na build), google.golang.org/grpc (última - verifique na build), sigs.k8s.io/controller-runtime (última - verifique na build), kubebuilder (última - verifique na build), tinygo (última - verifique os alvos de placa na build), wazero (última - verifique na build) e golangci-lint (última - verifique o conjunto de linters na build).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026