API Reference
8 minute read
Complete API reference for the metrics package core types and methods.
Recorder Type
The Recorder is the main type for collecting metrics. It is thread-safe. You can use it concurrently.
type Recorder struct {
// contains filtered or unexported fields
}
Creation Functions
New
func New(opts ...Option) (*Recorder, error)
Creates a new Recorder with the given options. Returns an error if configuration is invalid.
Parameters:
opts ...Option- Configuration options.
Returns:
*Recorder- Configured recorder.error- Configuration error, if any.
Example:
recorder, err := metrics.New(
metrics.WithPrometheus(":9090", "/metrics"),
metrics.WithServiceName("my-api"),
)
if err != nil {
log.Fatal(err)
}
Errors:
- Multiple provider options specified.
- Invalid service name.
- Invalid port or endpoint configuration.
MustNew
func MustNew(opts ...Option) *Recorder
Creates a new Recorder with the given options. Panics if configuration is invalid.
Parameters:
opts ...Option- Configuration options.
Returns:
*Recorder- Configured recorder.
Panics: If configuration is invalid.
Example:
recorder := metrics.MustNew(
metrics.WithPrometheus(":9090", "/metrics"),
metrics.WithServiceName("my-api"),
)
Use Case: Applications that should fail fast on invalid metrics configuration.
Lifecycle Methods
Start
func (r *Recorder) Start(ctx context.Context) error
Starts the metrics recorder. For Prometheus, starts the HTTP server. For OTLP, establishes connection. For stdout, this is a no-op but safe to call.
Parameters:
ctx context.Context- Lifecycle context for the recorder
Returns:
error- Startup error, if any
Example:
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
if err := recorder.Start(ctx); err != nil {
log.Fatal(err)
}
Errors:
- Port already in use (Prometheus with
WithStrictPort) - Cannot connect to OTLP endpoint
- Context already canceled
Provider Behavior:
- Prometheus: Starts HTTP server on configured port
- OTLP: Establishes connection to collector
- Stdout: No-op, safe to call
Shutdown
func (r *Recorder) Shutdown(ctx context.Context) error
Gracefully shuts down the metrics recorder, flushing any pending metrics.
Parameters:
ctx context.Context- Shutdown context with timeout
Returns:
error- Shutdown error, if any
Example:
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := recorder.Shutdown(shutdownCtx); err != nil {
log.Printf("Shutdown error: %v", err)
}
Behavior:
- Stops accepting new metrics
- Flushes pending metrics
- Closes network connections
- Stops HTTP server (Prometheus)
- Idempotent (safe to call multiple times)
Best Practice: Always defer Shutdown with a timeout context.
ForceFlush
func (r *Recorder) ForceFlush(ctx context.Context) error
Forces immediate export of all pending metrics. Primarily useful for push-based providers (OTLP, stdout).
Parameters:
ctx context.Context- Flush context with timeout
Returns:
error- Flush error, if any
Example:
// Before critical operation
if err := recorder.ForceFlush(ctx); err != nil {
log.Printf("Failed to flush metrics: %v", err)
}
Provider Behavior:
- OTLP: Immediately exports all pending metrics
- Stdout: Immediately prints all pending metrics
- Prometheus: Typically a no-op (pull-based)
Use Cases:
- Before deployment or shutdown
- Checkpointing during long operations
- Ensuring metrics visibility
Custom Metrics Methods
IncrementCounter
func (r *Recorder) IncrementCounter(ctx context.Context, name string, attrs ...attribute.KeyValue) error
Increments a counter metric by 1.
Parameters:
ctx context.Context- Context for the operationname string- Metric name (must be valid)attrs ...attribute.KeyValue- Optional metric attributes
Returns:
error- Error if metric name is invalid or limit reached
Example:
err := recorder.IncrementCounter(ctx, "requests_total",
attribute.String("method", "GET"),
attribute.String("status", "success"),
)
Naming Rules:
- Must start with letter
- Can contain letters, numbers, underscores, dots, hyphens
- Cannot use reserved prefixes:
__,http_,router_ - Maximum 255 characters
AddCounter
func (r *Recorder) AddCounter(ctx context.Context, name string, value int64, attrs ...attribute.KeyValue) error
Adds a specific value to a counter metric.
Parameters:
ctx context.Context- Context for the operationname string- Metric name (must be valid)value int64- Amount to add (must be non-negative)attrs ...attribute.KeyValue- Optional metric attributes
Returns:
error- Error if metric name is invalid, value is negative, or limit reached
Example:
bytesProcessed := int64(1024)
err := recorder.AddCounter(ctx, "bytes_processed_total", bytesProcessed,
attribute.String("direction", "inbound"),
)
RecordHistogram
func (r *Recorder) RecordHistogram(ctx context.Context, name string, value float64, attrs ...attribute.KeyValue) error
Records a value in a histogram metric.
Parameters:
ctx context.Context- Context for the operationname string- Metric name (must be valid)value float64- Value to recordattrs ...attribute.KeyValue- Optional metric attributes
Returns:
error- Error if metric name is invalid or limit reached
Example:
start := time.Now()
// ... operation ...
duration := time.Since(start).Seconds()
err := recorder.RecordHistogram(ctx, "operation_duration_seconds", duration,
attribute.String("operation", "create_user"),
)
Bucket Configuration: Use WithDurationBuckets or WithSizeBuckets to customize histogram boundaries.
SetGauge
func (r *Recorder) SetGauge(ctx context.Context, name string, value float64, attrs ...attribute.KeyValue) error
Sets a gauge metric to a specific value.
Parameters:
ctx context.Context- Context for the operationname string- Metric name (must be valid)value float64- Value to setattrs ...attribute.KeyValue- Optional metric attributes
Returns:
error- Error if metric name is invalid or limit reached
Example:
activeConnections := float64(pool.Active())
err := recorder.SetGauge(ctx, "active_connections", activeConnections,
attribute.String("pool", "database"),
)
Provider-Specific Methods
ServerAddress
func (r *Recorder) ServerAddress() string
Returns the server address (port) for Prometheus provider. Returns empty string for other providers or if server is disabled.
Returns:
string- Server address in port format (e.g.,:9090)
Example:
recorder := metrics.MustNew(
metrics.WithPrometheus(":9090", "/metrics"),
metrics.WithServiceName("my-api"),
)
recorder.Start(ctx)
address := recorder.ServerAddress()
log.Printf("Metrics at: http://localhost%s/metrics", address)
Use Cases:
- Logging actual port (when not using strict mode)
- Testing with dynamic port allocation
- Health check registration
Note: Returns the port string (e.g., :9090), not a full hostname. Prepend localhost for local access.
Handler
func (r *Recorder) Handler() (http.Handler, error)
Returns the HTTP handler for metrics endpoint. Only works with Prometheus provider.
Returns:
http.Handler- Metrics endpoint handlererror- Error if not using Prometheus provider or server disabled
Example:
recorder := metrics.MustNew(
metrics.WithPrometheus(":9090", "/metrics"),
metrics.WithServerDisabled(),
metrics.WithServiceName("my-api"),
)
handler, err := recorder.Handler()
if err != nil {
log.Fatal(err)
}
http.Handle("/metrics", handler)
http.ListenAndServe(":8080", nil)
Errors:
- Not using Prometheus provider
- Server not disabled (use
WithServerDisabled)
CustomMetricCount
func (r *Recorder) CustomMetricCount() int
Returns the number of custom metrics created.
Returns:
int- Number of custom metrics
Example:
count := recorder.CustomMetricCount()
log.Printf("Custom metrics: %d/%d", count, maxLimit)
// Expose as a metric
_ = recorder.SetGauge(ctx, "custom_metrics_count", float64(count))
Use Cases:
- Monitoring metric cardinality
- Debugging metric limit issues
- Capacity planning
Note: Built-in HTTP metrics do not count toward this total.
Middleware Function
Middleware
func Middleware(recorder *Recorder, opts ...MiddlewareOption) func(http.Handler) http.Handler
Returns HTTP middleware that automatically collects metrics for requests.
Parameters:
recorder *Recorder- Metrics recorderopts ...MiddlewareOption- Middleware configuration options
Returns:
func(http.Handler) http.Handler- Middleware function
Example:
handler := metrics.Middleware(recorder,
metrics.WithExcludePaths("/health", "/metrics"),
metrics.WithHeaders("X-Request-ID"),
)(httpHandler)
Collected Metrics:
http_request_duration_seconds- Request duration histogramhttp_requests_total- Request counterhttp_requests_active- Active requests gaugehttp_request_size_bytes- Request size histogramhttp_response_size_bytes- Response size histogramhttp_errors_total- Error counter
Middleware Options: See Middleware Options for details.
Testing Functions
TestingRecorder
func TestingRecorder(tb testing.TB, serviceName string, opts ...Option) *Recorder
Creates a test recorder with stdout provider. Automatically registers cleanup via t.Cleanup().
Parameters:
tb testing.TB- Test or benchmark instanceserviceName string- Service name for metricsopts ...Option- Optional additional configuration options
Returns:
*Recorder- Test recorder
Example:
func TestHandler(t *testing.T) {
t.Parallel()
recorder := metrics.TestingRecorder(t, "test-service")
// Use recorder in tests...
// Cleanup is automatic
}
// With additional options
func TestWithOptions(t *testing.T) {
recorder := metrics.TestingRecorder(t, "test-service",
metrics.WithMaxCustomMetrics(100),
)
}
Features:
- No port conflicts (uses stdout)
- Automatic cleanup
- Parallel test safe
- Works with both
*testing.Tand*testing.B
TestingRecorderWithPrometheus
func TestingRecorderWithPrometheus(tb testing.TB, serviceName string, opts ...Option) *Recorder
Creates a test recorder with Prometheus provider and dynamic port allocation. Automatically registers cleanup via t.Cleanup().
Parameters:
tb testing.TB- Test or benchmark instanceserviceName string- Service name for metricsopts ...Option- Optional additional configuration options
Returns:
*Recorder- Test recorder with Prometheus
Example:
func TestMetricsEndpoint(t *testing.T) {
t.Parallel()
recorder := metrics.TestingRecorderWithPrometheus(t, "test-service")
// Wait for server
err := metrics.WaitForMetricsServer(t, recorder.ServerAddress(), 5*time.Second)
if err != nil {
t.Fatal(err)
}
// Test metrics endpoint...
}
Features:
- Dynamic port allocation
- Real Prometheus endpoint
- Automatic cleanup
- Works with both
*testing.Tand*testing.B
WaitForMetricsServer
func WaitForMetricsServer(tb testing.TB, address string, timeout time.Duration) error
Waits for Prometheus metrics server to be ready.
Parameters:
tb testing.TB- Test or benchmark instance for loggingaddress string- Server address (e.g.,:9090)timeout time.Duration- Maximum wait time
Returns:
error- Error if server not ready within timeout
Example:
recorder := metrics.TestingRecorderWithPrometheus(t, "test-service")
err := metrics.WaitForMetricsServer(t, recorder.ServerAddress(), 5*time.Second)
if err != nil {
t.Fatalf("Server not ready: %v", err)
}
// Server is ready, make requests
Event Types
EventType
type EventType int
const (
EventError EventType = iota // Error events
EventWarning // Warning events
EventInfo // Informational events
EventDebug // Debug events
)
Severity levels for internal operational events.
Event
type Event struct {
Type EventType
Message string
Args []any // slog-style key-value pairs
}
Internal operational event from the metrics package.
Example:
metrics.WithEventHandler(func(e metrics.Event) {
switch e.Type {
case metrics.EventError:
sentry.CaptureMessage(e.Message)
case metrics.EventWarning:
log.Printf("WARN: %s", e.Message)
case metrics.EventInfo:
log.Printf("INFO: %s", e.Message)
}
})
EventHandler
type EventHandler func(Event)
Function type for handling internal operational events.
Example:
handler := func(e metrics.Event) {
slog.Default().Info(e.Message, e.Args...)
}
recorder := metrics.MustNew(
metrics.WithPrometheus(":9090", "/metrics"),
metrics.WithEventHandler(handler),
)
Error Handling
All metric recording methods return error. Common error types:
Invalid Metric Name
err := recorder.IncrementCounter(ctx, "__reserved")
// Error: metric name uses reserved prefix "__"
Metric Limit Reached
err := recorder.IncrementCounter(ctx, "new_metric_1001")
// Error: custom metric limit reached (1000/1000)
Provider Not Started
recorder := metrics.MustNew(metrics.WithOTLP("http://localhost:4318"))
err := recorder.IncrementCounter(ctx, "metric")
// Error: OTLP provider not started (call Start first)
Thread Safety
All methods are thread-safe and can be called concurrently:
// Safe to call from multiple goroutines
go func() {
_ = recorder.IncrementCounter(ctx, "worker_1")
}()
go func() {
_ = recorder.IncrementCounter(ctx, "worker_2")
}()
Next Steps
- See Options for all configuration options
- Check Middleware Options for HTTP middleware
- Review Troubleshooting for common issues
- Read Guides for usage patterns
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.