go
41 lines · 1 tab
Leah Thompson
Jan 2026
1 tab
package metrics
import (
"net/http"
"strconv"
"time"
"github.com/prometheus/client_golang/prometheus"
)
type statusWriter struct {
http.ResponseWriter
status int
}
func (w *statusWriter) WriteHeader(code int) {
w.status = code
w.ResponseWriter.WriteHeader(code)
}
var (
dur = prometheus.NewHistogramVec(prometheus.HistogramOpts{
Name: "http_request_duration_seconds",
Help: "HTTP request duration in seconds.",
}, []string{"method", "route"})
codes = prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "http_responses_total",
Help: "HTTP responses by status.",
}, []string{"method", "route", "status"})
)
func Middleware(route string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
sw := &statusWriter{ResponseWriter: w, status: http.StatusOK}
start := time.Now()
next.ServeHTTP(sw, r)
dur.WithLabelValues(r.Method, route).Observe(time.Since(start).Seconds())
codes.WithLabelValues(r.Method, route, strconv.Itoa(sw.status)).Inc()
})
}
1 file · go
Explain with highlit
I like to start observability with two metrics: request duration and response codes. The wrapper below intercepts WriteHeader to capture status codes and then records both a histogram observation and a counter increment. The biggest gotcha is label cardinality: never label on raw URLs; label on a normalized route like /v1/orders/:id. In routers like chi, you can get the route pattern from context; otherwise you can pass a route string into the handler when wiring routes. Once this is in, you can build SLO dashboards for p95 latency and error rate. It also makes regressions obvious during deploys, because you can compare latency distributions before and after.
Related snips
go
package api
import (
"net/http"
"runtime/debug"
)
Expose build metadata for debugging deploys
go
observability
build
by Leah Thompson
1 tab
typescript
export interface RetryOptions {
retries: number;
baseMs: number;
maxMs: number;
signal?: AbortSignal;
onRetry?: (attempt: number, delay: number, err: unknown) => void;
Exponential backoff with jitter for retries
typescript
reliability
retry
by codesnips
2 tabs
go
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
go
postgres
transactions
by Leah Thompson
1 tab
go
package files
import (
"context"
"time"
Presigned S3 upload URLs (AWS SDK v2)
go
aws
s3
by Leah Thompson
1 tab
go
package deps
import (
"net"
"net/http"
"time"
HTTP client tuned for production: timeouts, transport, and connection reuse
go
http
client
by Leah Thompson
1 tab
go
package api
import (
"io"
"net/http"
"os"
Safe multipart uploads using temp files (bounded memory)
go
http
uploads
by Leah Thompson
1 tab
Share this code
Here's the card — post it anywhere.