Documentation
¶
Overview ¶
Example (FromEnv) ¶
Example_fromEnv demonstrates using environment variables for configuration. This is the simplest approach and follows OpenTelemetry best practices.
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
// Set environment variables before running:
// export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
// export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
// export OTEL_SERVICE_NAME=my-service
// export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production,service.version=1.0.0
ctx := context.Background()
// Handler automatically reads all OTEL_* environment variables
handler, err := otlp.NewSDKHandlerFromEnv(ctx)
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
stats.Incr("app.started")
}
Output:
Example (FullyConfiguredByEnvironment) ¶
Example_fullyConfiguredByEnvironment demonstrates relying entirely on OTEL environment variables without specifying any configuration in code. This provides maximum flexibility for deployment environments to control OpenTelemetry configuration without code changes.
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
// The SDK will use these standard OpenTelemetry environment variables:
//
// Required/Common:
// OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 (full URL with scheme)
// OTEL_EXPORTER_OTLP_PROTOCOL=grpc (or http/protobuf)
// OTEL_SERVICE_NAME=my-service
//
// Optional:
// OTEL_EXPORTER_OTLP_HEADERS=key1=value1,key2=value2
// OTEL_EXPORTER_OTLP_TIMEOUT=30s
// OTEL_RESOURCE_ATTRIBUTES=deployment.environment=production
// OTEL_METRIC_EXPORT_INTERVAL=60s
// OTEL_METRIC_EXPORT_TIMEOUT=30s
//
// If no environment variables are set, the SDK uses these defaults:
// - Endpoint: http://localhost:4317 (gRPC) or http://localhost:4318 (HTTP)
// - Protocol: grpc
// - Export Interval: 60 seconds
// - Export Timeout: 30 seconds
ctx := context.Background()
// Pass an empty config - SDK will read all configuration from environment
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
// Your application code remains environment-agnostic
stats.Incr("requests.count", stats.T("method", "GET"))
stats.Observe("request.duration", 0.125)
}
Output:
Example (GRPC) ¶
Example_gRPC demonstrates using the OpenTelemetry SDK handler with gRPC transport.
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Create handler with gRPC transport
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
// Register with the default stats engine
stats.Register(handler)
defer stats.Flush()
// Your application metrics will now be exported via gRPC
stats.Incr("requests.count", stats.T("method", "GET"), stats.T("status", "200"))
stats.Observe("request.duration", 0.250, stats.T("endpoint", "/api/users"))
}
Output:
Example (GRPCWithOptions) ¶
Example_gRPCWithOptions demonstrates advanced gRPC configuration.
package main
import (
"context"
"log"
"time"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Create handler with custom gRPC options
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
GRPCOptions: []otlpmetricgrpc.Option{
otlpmetricgrpc.WithInsecure(),
otlpmetricgrpc.WithTimeout(30 * time.Second),
// For TLS:
// otlpmetricgrpc.WithTLSCredentials(credentials.NewClientTLSFromCert(certPool, "")),
// For custom headers:
// otlpmetricgrpc.WithHeaders(map[string]string{
// "Authorization": "Bearer token",
// }),
},
ExportInterval: 10 * time.Second,
ExportTimeout: 30 * time.Second,
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
stats.Incr("requests.total")
}
Output:
Example (HTTP) ¶
Example_hTTP demonstrates using the OpenTelemetry SDK handler with HTTP transport.
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Create handler with HTTP transport
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolHTTPProtobuf,
EndpointURL: "http://localhost:4318",
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
// Register with the default stats engine
stats.Register(handler)
defer stats.Flush()
// Your application metrics will now be exported via HTTP
stats.Incr("requests.count")
}
Output:
Example (HTTPWithOptions) ¶
Example_hTTPWithOptions demonstrates advanced HTTP configuration.
package main
import (
"context"
"log"
"time"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Create handler with custom HTTP options
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolHTTPProtobuf,
EndpointURL: "http://localhost:4318",
HTTPOptions: []otlpmetrichttp.Option{
otlpmetrichttp.WithInsecure(),
otlpmetrichttp.WithTimeout(30 * time.Second),
// For custom headers:
// otlpmetrichttp.WithHeaders(map[string]string{
// "Authorization": "Bearer token",
// "X-Custom-Header": "value",
// }),
// For compression:
// otlpmetrichttp.WithCompression(otlpmetrichttp.GzipCompression),
},
ExportInterval: 10 * time.Second,
ExportTimeout: 30 * time.Second,
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
stats.Incr("requests.total")
}
Output:
Example (MultipleHandlers) ¶
Example_multipleHandlers demonstrates using multiple handlers simultaneously.
package main
import (
"context"
"log"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"google.golang.org/grpc/credentials/insecure"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Send metrics to both gRPC and HTTP endpoints
grpcHandler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
GRPCOptions: []otlpmetricgrpc.Option{
otlpmetricgrpc.WithTLSCredentials(insecure.NewCredentials()),
},
})
if err != nil {
log.Fatal(err)
}
defer grpcHandler.Shutdown(ctx)
httpHandler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolHTTPProtobuf,
EndpointURL: "http://localhost:4318",
})
if err != nil {
log.Fatal(err)
}
defer httpHandler.Shutdown(ctx)
// Register both handlers
stats.Register(grpcHandler)
stats.Register(httpHandler)
defer stats.Flush()
// Metrics will be sent to both endpoints
stats.Incr("requests.count")
}
Output:
Example (StructBased) ¶
Example_structBased demonstrates using struct-based metrics with OpenTelemetry.
package main
import (
"context"
"log"
"time"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
// Define metrics using struct tags
type ServerMetrics struct {
RequestCount int `metric:"requests.count" type:"counter"`
ActiveConns int `metric:"connections.active" type:"gauge"`
RequestDuration time.Duration `metric:"request.duration" type:"histogram"`
}
metrics := ServerMetrics{
RequestCount: 100,
ActiveConns: 50,
RequestDuration: 250 * time.Millisecond,
}
// Report all metrics from the struct
stats.Report(metrics, stats.T("server", "web-1"), stats.T("region", "us-west-2"))
}
Output:
Index ¶
- Constants
- type Clientdeprecated
- type HTTPClientdeprecated
- type Handlerdeprecated
- type Protocol
- type SDKConfig
- type SDKHandler
Examples ¶
Constants ¶
const ( // DefaultMaxMetrics is the default maximum of metrics kept in memory // by the handler. DefaultMaxMetrics = 5000 // DefaultFlushInterval is the default interval to flush the metrics // to the OpenTelemetry destination. // // Metrics will be flushed to the destination when DefaultFlushInterval or // DefaultMaxMetrics are reached, whichever comes first. DefaultFlushInterval = 10 * time.Second )
const ( // DefaultHistogramMaxSize is the default maximum number of buckets used for // exponential histograms when ExponentialHistogram is enabled. DefaultHistogramMaxSize int32 = 160 // DefaultHistogramMaxScale is the default maximum scale (resolution) used // for exponential histograms when ExponentialHistogram is enabled. DefaultHistogramMaxScale int32 = 20 )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client
deprecated
type Client interface {
Handle(context.Context, *colmetricpb.ExportMetricsServiceRequest) error
}
Deprecated: Client is deprecated and will be removed in v6. It is only used by the deprecated Handler. Use SDKHandler instead.
type HTTPClient
deprecated
type HTTPClient struct {
// contains filtered or unexported fields
}
Deprecated: HTTPClient is deprecated and will be removed in v6. Use SDKHandler with ProtocolHTTPProtobuf instead, which provides the official OpenTelemetry SDK with retry logic, proper timeout handling, and full OTLP support.
Migration example:
// Old (deprecated)
client := otlp.NewHTTPClient("http://localhost:4318/v1/metrics")
handler := &otlp.Handler{Client: client}
// New (recommended)
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolHTTPProtobuf,
EndpointURL: "http://localhost:4318",
})
HTTPClient implements the Client interface and is used to export metrics to an OpenTelemetry Collector through the HTTP interface.
The current implementation is a fire and forget approach where we do not retry or buffer any failed-to-flush data on the client.
func NewHTTPClient
deprecated
func NewHTTPClient(endpoint string) *HTTPClient
Deprecated: NewHTTPClient is deprecated. Use SDKHandler with ProtocolHTTPProtobuf instead. See HTTPClient documentation for migration example.
func (*HTTPClient) Handle ¶
func (c *HTTPClient) Handle(ctx context.Context, request *colmetricpb.ExportMetricsServiceRequest) error
type Handler
deprecated
type Handler struct {
Client Client
Context context.Context
FlushInterval time.Duration
MaxMetrics int
// contains filtered or unexported fields
}
Deprecated: Handler is deprecated and will be removed in v6. Use SDKHandler instead, which provides the official OpenTelemetry SDK with full gRPC and HTTP support, environment variable configuration, and automatic resource detection.
Migration example:
// Old (deprecated)
handler := &otlp.Handler{
Client: otlp.NewHTTPClient("http://localhost:4318"),
}
// New (recommended)
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolHTTPProtobuf,
EndpointURL: "http://localhost:4318",
})
Handler implements stats.Handler to forward metrics to an OpenTelemetry destination. Usually an OpenTelemetry Collector.
With the current implementation this Handler is targeting a Prometheus based backend or any backend expecting cumulative values.
This Handler leverages a doubly linked list with a map to implement a ring buffer with a lookup to ensure a low memory usage.
func NewHandler ¶
NewHandler return an instance of Handler with the default client, flush interval and in-memory metrics limit.
type SDKConfig ¶
type SDKConfig struct {
// Protocol specifies the transport protocol (grpc or http/protobuf).
// If empty, the OTEL_EXPORTER_OTLP_METRICS_PROTOCOL and
// OTEL_EXPORTER_OTLP_PROTOCOL environment variables are consulted (in that
// order), defaulting to gRPC when neither is set. An unrecognized
// environment value causes NewSDKHandler to return an error.
Protocol Protocol
// EndpointURL specifies the full OTLP endpoint URL.
//
// Note: this is deliberately "EndpointURL", not "Endpoint". The underlying
// exporters expose both WithEndpoint (host:port, no scheme) and
// WithEndpointURL (full URL with scheme), and the two are easy to confuse.
// This handler always uses WithEndpointURL, so the value MUST include the
// scheme (http:// or https://).
// For gRPC: "http://localhost:4317" or "https://api.example.com:4317"
// For HTTP: "http://localhost:4318" or "https://api.example.com:4318"
// If empty, uses OTEL_EXPORTER_OTLP_ENDPOINT environment variable
// or SDK defaults (http://localhost:4317 for gRPC, http://localhost:4318 for HTTP)
EndpointURL string
// Resource specifies the resource attributes for all metrics.
// If nil, a resource is built from the SDK defaults: environment
// (OTEL_RESOURCE_ATTRIBUTES, OTEL_SERVICE_NAME), telemetry SDK, host, and
// process attributes. Cloud and Kubernetes detection is not included by
// default; supply a Resource built with the relevant
// go.opentelemetry.io/contrib/detectors/* packages to add it.
Resource *resource.Resource
// ExportInterval specifies how often to export metrics
// If zero or not set, uses the SDK default (60 seconds)
ExportInterval time.Duration
// ExportTimeout specifies the maximum amount of time to wait for a single
// export request to the server to complete. This is distinct from
// ExportInterval, which controls how often exports happen.
// If zero or not set, uses the SDK default (30 seconds)
ExportTimeout time.Duration
// HTTPOptions are additional options for HTTP protocol.
// Only used when Protocol is ProtocolHTTPProtobuf.
// See the available options at
// https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp#Option
HTTPOptions []otlpmetrichttp.Option
// GRPCOptions are additional options for gRPC protocol.
// Only used when Protocol is ProtocolGRPC.
// See the available options at
// https://pkg.go.dev/go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc#Option
GRPCOptions []otlpmetricgrpc.Option
// ExponentialHistogram enables exponential histogram aggregation for histogram metrics.
// When true, histograms use base-2 exponential buckets which provide better accuracy
// and lower memory overhead compared to explicit bucket histograms.
// Default: false (uses explicit bucket histograms)
ExponentialHistogram bool
// ExponentialHistogramMaxSize sets the maximum number of buckets for exponential histograms.
// Larger values provide better accuracy but use more memory.
// Default: DefaultHistogramMaxSize (if ExponentialHistogram is true)
// Ignored if ExponentialHistogram is false
ExponentialHistogramMaxSize int32
// ExponentialHistogramMaxScale sets the maximum scale (resolution) for exponential histograms.
// Higher values provide finer bucket granularity.
// Valid range: -10 to 20
// Default: DefaultHistogramMaxScale (if ExponentialHistogram is true)
// Ignored if ExponentialHistogram is false
ExponentialHistogramMaxScale int32
// TemporalitySelector determines the temporality (cumulative vs delta) for each instrument kind.
// If nil, uses DefaultTemporalitySelector which returns CumulativeTemporality for all instruments.
// This is recommended for Prometheus and most OTLP backends.
//
// Available selectors:
// - sdkmetric.DefaultTemporalitySelector: Cumulative for all (default, Prometheus-compatible)
// - sdkmetric.CumulativeTemporalitySelector: Cumulative for all
// - sdkmetric.DeltaTemporalitySelector: Delta for all
// - sdkmetric.LowMemoryTemporalitySelector: Delta for Counters/Histograms, Cumulative for UpDownCounters
TemporalitySelector sdkmetric.TemporalitySelector
}
SDKConfig contains configuration for the OpenTelemetry SDK handler.
type SDKHandler ¶
type SDKHandler struct {
// contains filtered or unexported fields
}
SDKHandler implements stats.Handler using the official OpenTelemetry SDK. It bridges stats metrics to OTel metrics and supports both HTTP and gRPC transports.
This handler supports all standard OpenTelemetry environment variables:
- OTEL_EXPORTER_OTLP_ENDPOINT
- OTEL_EXPORTER_OTLP_PROTOCOL (grpc, http/protobuf)
- OTEL_EXPORTER_OTLP_HEADERS
- OTEL_EXPORTER_OTLP_TIMEOUT
- OTEL_RESOURCE_ATTRIBUTES
- OTEL_SERVICE_NAME
- And more...
Example usage:
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
Example (ExponentialHistogram) ¶
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Create handler with exponential histogram support
// Exponential histograms provide better accuracy and lower memory overhead
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
ExponentialHistogram: true, // Enable exponential histograms
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
// Record histogram metrics - these will use exponential bucket aggregation
stats.Observe("api.latency", 0.125, stats.T("endpoint", "/users"))
stats.Observe("api.latency", 0.250, stats.T("endpoint", "/users"))
stats.Observe("api.latency", 0.500, stats.T("endpoint", "/users"))
// Exponential histograms automatically adapt to the value range
// providing consistent accuracy without pre-defined bucket boundaries
stats.Observe("db.query.duration", 0.001, stats.T("query", "SELECT"))
stats.Observe("db.query.duration", 0.050, stats.T("query", "SELECT"))
stats.Observe("db.query.duration", 1.500, stats.T("query", "SELECT"))
}
Output:
Example (ExponentialHistogramAdvanced) ¶
package main
import (
"context"
"log"
"github.com/segmentio/stats/v5"
"github.com/segmentio/stats/v5/otlp"
)
func main() {
ctx := context.Background()
// Advanced exponential histogram configuration
handler, err := otlp.NewSDKHandler(ctx, otlp.SDKConfig{
Protocol: otlp.ProtocolGRPC,
EndpointURL: "http://localhost:4317",
ExponentialHistogram: true,
ExponentialHistogramMaxSize: 160, // Max buckets (higher = more accuracy)
ExponentialHistogramMaxScale: 20, // Max resolution (higher = finer granularity)
})
if err != nil {
log.Fatal(err)
}
defer handler.Shutdown(ctx)
stats.Register(handler)
defer stats.Flush()
// Record response time metrics across wide value ranges
// Exponential histograms handle this efficiently
for _, duration := range []float64{0.001, 0.010, 0.100, 1.000, 10.000} {
stats.Observe("response.time", duration, stats.T("service", "api"))
}
}
Output:
func NewSDKHandler ¶
func NewSDKHandler(ctx context.Context, config SDKConfig) (*SDKHandler, error)
NewSDKHandler creates a new handler using the OpenTelemetry SDK. It builds a resource from the SDK defaults (environment, telemetry SDK, host, and process attributes) and supports the standard OTEL environment variables.
func NewSDKHandlerFromEnv ¶
func NewSDKHandlerFromEnv(ctx context.Context) (*SDKHandler, error)
NewSDKHandlerFromEnv creates a handler using only environment variables. This is the simplest way to create a handler with full OpenTelemetry support.
It respects all standard OTEL environment variables including:
- OTEL_EXPORTER_OTLP_ENDPOINT (full URL with scheme, e.g., http://localhost:4317)
- OTEL_EXPORTER_OTLP_PROTOCOL (grpc or http/protobuf)
- OTEL_EXPORTER_OTLP_HEADERS
- OTEL_RESOURCE_ATTRIBUTES
- OTEL_SERVICE_NAME
func (*SDKHandler) HandleMeasures ¶
func (h *SDKHandler) HandleMeasures(_ time.Time, measures ...stats.Measure)
HandleMeasures implements stats.Handler.