Documentation | Contributing | Code of Conduct
A minimal boilerplate wrapper for building production-ready Go HTTP services. This library reduces the boilerplate of writing production/enterprise-grade Go services to a minimum.
What this library provides:
- Essential production features out of the box (metrics, health checks, graceful shutdown)
- Kubernetes and containerization boilerplate
- Lightweight wrapper around http.Server for high availability services
What this library does NOT provide:
- HTTP framework or routing
- Business logic or application patterns
- Restrictions on how you write your HTTP handlers
- Opinionated application architecture
Write HTTP handlers exactly as you prefer, using any patterns or frameworks you choose. This library handles the operational concerns while staying out of your application logic.
- Minimal Boilerplate: Reduces production service setup to a few lines of code
- HTTP Server Wrapper: Lightweight wrapper around http.Server with production defaults
- Metrics: Built-in Prometheus metrics collection with automatic request tracking
- Logging: Structured logging with slog integration and context-aware loggers
- Middleware: Extensible middleware system with built-in recovery and logging
- Configuration: Environment-based configuration with sensible defaults
- Graceful Shutdown: Signal handling with configurable shutdown hooks
- Health Checks: Built-in health check endpoints for Kubernetes
- Framework Agnostic: Works with any HTTP patterns or frameworks you prefer (as long as the framework supports the standard
httppackage)
Minimal boilerplate to get a production-ready service with metrics, health checks, and graceful shutdown:
package main
import (
"log/slog"
"net/http"
"os"
"atomicgo.dev/service"
)
func main() {
// Create service with default configuration
svc := service.New("my-service", nil)
// Write HTTP handlers exactly as you prefer
svc.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
logger := service.GetLogger(r) // Easy access to the logger
logger.Info("Hello, World!")
w.Write([]byte("Hello, World!"))
})
// Start service (includes graceful shutdown, metrics, health checks)
if err := svc.Start(); err != nil {
os.Exit(1)
}
}That's it! Your service now has:
- Prometheus metrics at
:9090/metrics - Comprehensive health checks at
:9090/health - Kubernetes readiness probe at
:9090/ready - Kubernetes liveness probe at
:9090/live - Graceful shutdown handling
- Structured logging
- Kubernetes-ready configuration
The framework supports configuration via environment variables with sensible defaults:
| Variable | Default | Description |
|---|---|---|
ADDR |
:8080 |
HTTP server address |
METRICS_ADDR |
:9090 |
Metrics server address |
METRICS_PATH |
/metrics |
Metrics endpoint path |
HEALTH_PATH |
/health |
Health check endpoint path |
READINESS_PATH |
/ready |
Readiness probe endpoint path |
LIVENESS_PATH |
/live |
Liveness probe endpoint path |
SERVICE_VERSION |
v1.0.0 |
Service version for health checks |
READ_TIMEOUT |
10s |
HTTP read timeout |
WRITE_TIMEOUT |
10s |
HTTP write timeout |
IDLE_TIMEOUT |
120s |
HTTP idle timeout |
SHUTDOWN_TIMEOUT |
30s |
Graceful shutdown timeout |
// Load configuration from environment
config, err := service.LoadFromEnv()
if err != nil {
log.Fatal(err)
}
// Create service with custom configuration
svc := service.New("my-service", config)The framework includes several built-in middleware:
- LoggerMiddleware: Injects logger into request context
- RecoveryMiddleware: Recovers from panics and logs errors
- RequestLoggingMiddleware: Logs incoming requests
- MetricsMiddleware: Tracks HTTP metrics for Prometheus
// Add custom middleware
svc.Use(func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Custom", "value")
next.ServeHTTP(w, r)
})
})The framework provides a flexible metrics system with built-in HTTP metrics and support for custom metrics.
The framework automatically collects these Prometheus metrics for every service:
{service_name}_http_requests_total: Total HTTP requests by method, endpoint, and status{service_name}_http_request_duration_seconds: Request duration histogram by method, endpoint, and status{service_name}_http_requests_in_flight: Current number of in-flight requests
These metrics are provided automatically without any configuration required.
You can easily register and use custom metrics in your service:
func main() {
svc := service.New("my-service", nil)
// Register custom metrics
svc.RegisterCounter(service.MetricConfig{
Name: "user_registrations_total",
Help: "Total number of user registrations",
Labels: []string{"source", "status"},
})
svc.RegisterGauge(service.MetricConfig{
Name: "active_users",
Help: "Number of currently active users",
Labels: []string{"user_type"},
})
svc.RegisterHistogram(service.MetricConfig{
Name: "request_processing_duration_seconds",
Help: "Time spent processing requests",
Labels: []string{"operation"},
Buckets: []float64{0.001, 0.01, 0.1, 1.0, 10.0},
})
svc.RegisterSummary(service.MetricConfig{
Name: "response_size_bytes",
Help: "Size of responses in bytes",
Labels: []string{"endpoint"},
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},
})
// Use metrics in handlers
svc.HandleFunc("/register", func(w http.ResponseWriter, r *http.Request) {
// Increment counter
service.IncCounter(r, "user_registrations_total", "web", "success")
// Set gauge value
service.SetGauge(r, "active_users", 42.0, "premium")
// Observe histogram
service.ObserveHistogram(r, "request_processing_duration_seconds", 0.25, "registration")
// Observe summary
service.ObserveSummary(r, "response_size_bytes", 1024.0, "/register")
w.Write([]byte("User registered"))
})
svc.Start()
}The framework supports all standard Prometheus metric types:
- Counter: Monotonically increasing values (e.g., total requests, errors)
- Gauge: Values that can go up and down (e.g., active connections, memory usage)
- Histogram: Observations in configurable buckets (e.g., request duration, response size)
- Summary: Observations with configurable quantiles (e.g., request latency percentiles)
For advanced use cases, you can access the metrics collector directly:
func myHandler(w http.ResponseWriter, r *http.Request) {
metrics := service.GetMetrics(r)
if metrics != nil {
// Direct access to metrics collector
metrics.IncCounter("my_counter", "label_value")
metrics.SetGauge("my_gauge", 42.0, "label_value")
// Access the underlying Prometheus registry
registry := metrics.GetRegistry()
// Use registry for custom integrations
}
}All metrics are available at :9090/metrics by default.
The framework includes graceful shutdown by default with signal handling and custom hooks:
// Add shutdown hooks
svc.AddShutdownHook(func() error {
// Cleanup resources
return nil
})
// Start service (includes graceful shutdown)
svc.Start()The framework uses structured logging with slog and provides context-aware loggers:
func myHandler(w http.ResponseWriter, r *http.Request) {
logger := service.GetLogger(r)
logger.Info("request processed", "path", r.URL.Path)
}The framework integrates with HelloFresh's health-go library to provide comprehensive health checking capabilities.
Health check endpoints are automatically available on the metrics server:
:9090/health: Comprehensive health check with detailed status information:9090/ready: Kubernetes readiness probe endpoint:9090/live: Kubernetes liveness probe endpoint:9090/metrics: Prometheus metrics
You can register custom health checks using the RegisterHealthCheck method:
func main() {
svc := service.New("my-service", nil)
// Register a database health check
svc.RegisterHealthCheck(health.Config{
Name: "database",
Timeout: time.Second * 5,
SkipOnErr: false, // This check is critical
Check: func(ctx context.Context) error {
// Your database health check logic here
return db.PingContext(ctx)
},
})
// Register a Redis health check
svc.RegisterHealthCheck(health.Config{
Name: "redis",
Timeout: time.Second * 3,
SkipOnErr: true, // This check is optional
Check: func(ctx context.Context) error {
// Your Redis health check logic here
return redisClient.Ping(ctx).Err()
},
})
svc.Start()
}The health-go library provides several built-in health checkers for common services:
import (
"github.com/hellofresh/health-go/v5"
healthPostgres "github.com/hellofresh/health-go/v5/checks/postgres"
healthRedis "github.com/hellofresh/health-go/v5/checks/redis"
)
func main() {
svc := service.New("my-service", nil)
// PostgreSQL health check
svc.RegisterHealthCheck(health.Config{
Name: "postgresql",
Timeout: time.Second * 5,
SkipOnErr: false, // Critical check - service is unhealthy if DB is down
Check: healthPostgres.New(healthPostgres.Config{
DSN: dbURL,
}),
})
// Redis health check
svc.RegisterHealthCheck(health.Config{
Name: "redis",
Timeout: time.Second * 3,
Check: healthRedis.New(healthRedis.Config{
Addr: "localhost:6379",
}),
})
svc.Start()
}You can configure health check endpoints using environment variables:
| Variable | Default | Description |
|---|---|---|
HEALTH_PATH |
/health |
Main health check endpoint path |
READINESS_PATH |
/ready |
Kubernetes readiness probe path |
LIVENESS_PATH |
/live |
Kubernetes liveness probe path |
You can access the health checker in your HTTP handlers:
func myHandler(w http.ResponseWriter, r *http.Request) {
healthChecker := service.GetHealthChecker(r)
if healthChecker != nil {
check := healthChecker.Measure(r.Context())
// Use status information
w.Write([]byte(fmt.Sprintf("Health checks: %+v", check)))
}
}The library provides all the boilerplate needed for Kubernetes deployments:
- Graceful shutdown handling SIGTERM
- Health check endpoints for liveness/readiness probes
- Prometheus metrics for monitoring
- Configurable resource limits via environment variables
- No additional Kubernetes-specific code required
See the _examples/ directory for complete working examples demonstrating:
- minimal/: Basic service setup with default configuration
- custom-metrics/: Comprehensive custom metrics registration and usage
- prometheus-counter/: Simple custom counter example (HTTP metrics are automatic)
- health-check-*: Various health check integrations
- shutdown-hook/: Graceful shutdown with custom cleanup
- Minimal setup - Start with default configuration and customize only what you need
- Write HTTP handlers naturally - Use any patterns or frameworks you prefer
- Add custom shutdown hooks for resource cleanup when needed
- Use structured logging for better observability
- Monitor metrics in production environments
We welcome contributions! Please see our Contributing Guide for details.
This project is licensed under the MIT License - see the LICENSE file for details.
AtomicGo.dev Β Β·Β with β€οΈ by @MarvinJWendt | MarvinJWendt.com
