Fundamentos de Observabilidad
9 ejemplos para empezar con Observabilidad - 7 básicos y 2 intermedios.
Busca en todas las páginas de la documentación
9 ejemplos para empezar con Observabilidad - 7 básicos y 2 intermedios.
mkdir oblab && cd oblab && go mod init example.com/oblab.go get github.com/prometheus/client_golang/prometheus/promhttp y los módulos de OpenTelemetry según sea necesario.Go 1.21+ establece un logger estructurado predeterminado que puedes llamar sin configuración.
package main
import (
"log/slog"
)
func main() {
slog.Info("iniciando servidor", "puerto", 8080)
}slog.Info escribe pares clave-valor después del mensaje.Relacionado: Registro Estructurado con slog - manejadores y niveles
Los logs JSON se analizan limpiamente en Loki, Elasticsearch y CloudWatch.
package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
slog.SetDefault(logger)
slog.Info("listo", "servicio", "api")
}NewJSONHandler emite un objeto JSON por línea.SetDefault hace que las llamadas a slog a nivel de paquete usen tu manejador.Level a slog.LevelDebug solo en desarrollo.Relacionado: Producción en Go: Logs, Métricas, Trazas y Señales - resumen de observabilidad
Adjunta un ID de correlación al contexto para logs y llamadas posteriores.
package main
import (
"context"
"crypto/rand"
"encoding/hex"
"net/http"
)
type ctxKey string
const requestIDKey ctxKey = "request_id"
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 == "" {
var b [16]byte
rand.Read(b[:])
id = hex.EncodeToString(b[:])
}
ctx := context.WithValue(r.Context(), requestIDKey, id)
w.Header().Set("X-Request-ID", id)
next.ServeHTTP(w, r.WithContext(ctx))
})
}X-Request-ID entrante cuando esté presente para la continuidad del rastreo.Relacionado: Cadenas de Middleware y Contexto de Solicitud - envolviendo manejadores
Registra el método, la ruta y el estado para cada solicitud HTTP.
package main
import (
"log/slog"
"net/http"
"time"
)
type statusWriter struct {
http.ResponseWriter
code int
}
func (w *statusWriter) WriteHeader(code int) {
w.code = code
w.ResponseWriter.WriteHeader(code)
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
sw := &statusWriter{ResponseWriter: w, code: http.StatusOK}
next.ServeHTTP(sw, r)
slog.Info("solicitud",
"method", r.Method,
"path", r.URL.Path,
"status", sw.code,
"duration_ms", time.Since(start).Milliseconds(),
)
})
}ResponseWriter para capturar el código de estado final.DEBUG en producción para reducir el ruido.Relacionado: Registro Estructurado con slog - patrones de middleware
/healthzLa liveness debe ser barata y nunca llamar a sistemas externos.
package main
import (
"net/http"
)
func healthz(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", healthz)
http.ListenAndServe(":8080", mux)
}livenessProbe de Kubernetes accede a esta ruta en un intervalo corto.Relacionado: Sondas de Salud, Preparación y Liveness - diseño de sondas
/readyzLa readiness controla el tráfico cuando las dependencias no están saludables.
package main
import (
"net/http"
"sync/atomic"
)
var ready atomic.Bool
func readyz(w http.ResponseWriter, r *http.Request) {
if !ready.Load() {
http.Error(w, "no está listo", http.StatusServiceUnavailable)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("listo"))
}
func main() {
ready.Store(true)
mux := http.NewServeMux()
mux.HandleFunc("GET /readyz", readyz)
http.ListenAndServe(":8080", mux)
}ready a false durante el inicio hasta que terminen las migraciones.Relacionado: Sondas de Salud, Preparación y Liveness - verificaciones de dependencias
Las aplicaciones 12-factor leen la configuración del entorno al inicio.
package main
import (
"log/slog"
"os"
)
func main() {
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
slog.Info("configuración cargada", "puerto", port, "env", os.Getenv("APP_ENV"))
}main cuando faltan variables requeridas.Relacionado: Gestión de Configuración: Env, Flags y Viper - patrones de configuración completos
/metricsExpone un endpoint de scraping para totales de solicitudes.
package main
import (
"net/http"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
)
var requests = prometheus.NewCounterVec(
prometheus.CounterOpts{Name: "http_requests_total", Help: "Solicitudes HTTP"},
[]string{"method", "code"},
)
func main() {
prometheus.MustRegister(requests)
mux := http.NewServeMux()
mux.Handle("GET /metrics", promhttp.Handler())
mux.HandleFunc("GET /hello", func(w http.ResponseWriter, r *http.Request) {
requests.WithLabelValues(r.Method, "200").Inc()
w.Write([]byte("hello"))
})
http.ListenAndServe(":8080", mux)
}main, no por manejador de solicitudes./metrics a redes internas o middleware de autenticación.Relacionado: Métricas Prometheus y Dashboards RED/USE - dashboards RED
Procesa las solicitudes HTTP en curso antes de que el proceso termine.
package main
import (
"context"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
srv := &http.Server{Addr: ":8080", Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})}
go func() {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
slog.Error("fallo al escuchar", "err", err)
os.Exit(1)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
slog.Error("fallo al cerrar", "err", err)
}
slog.Info("servidor detenido")
}Shutdown deja de aceptar nuevas conexiones y espera las solicitudes activas.terminationGracePeriodSeconds de Kubernetes.Relacionado: Cierre Elegante y Manejo de Señales - patrones de errgroup
Versiones de la Pila: Esta página fue escrita para Go 1.26.x (predeterminado GC Green Tea, modernizadores de
go fix- verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación) y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 19 jul 2026