1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-01-23 11:14:48 +02:00
imgproxy/metrics/otel/sampler.go

119 lines
2.6 KiB
Go

package otel
import (
"encoding/binary"
"errors"
"fmt"
"os"
"strconv"
"strings"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)
const (
tracesSamplerKey = "OTEL_TRACES_SAMPLER"
tracesSamplerArgKey = "OTEL_TRACES_SAMPLER_ARG"
samplerTraceIDRatio = "traceidratio"
)
var (
errNegativeTraceIDRatio = errors.New("invalid trace ID ratio: less than 0.0")
errGreaterThanOneTraceIDRatio = errors.New("invalid trace ID ratio: greater than 1.0")
)
type samplerArgParseError struct {
parseErr error
}
func (e samplerArgParseError) Error() string {
return fmt.Sprintf("parsing sampler argument: %s", e.parseErr.Error())
}
func (e samplerArgParseError) Unwrap() error {
return e.parseErr
}
type traceIDRatioSampler struct {
traceIDUpperBound uint64
description string
}
func (ts traceIDRatioSampler) ShouldSample(p sdktrace.SamplingParameters) sdktrace.SamplingResult {
psc := trace.SpanContextFromContext(p.ParentContext)
x := binary.BigEndian.Uint64(p.TraceID[len(p.TraceID)-8:]) >> 1
if x < ts.traceIDUpperBound {
return sdktrace.SamplingResult{
Decision: sdktrace.RecordAndSample,
Tracestate: psc.TraceState(),
}
}
return sdktrace.SamplingResult{
Decision: sdktrace.Drop,
Tracestate: psc.TraceState(),
}
}
func (ts traceIDRatioSampler) Description() string {
return ts.description
}
func traceIDRatioBased(fraction float64) sdktrace.Sampler {
if fraction >= 1 {
return sdktrace.AlwaysSample()
}
if fraction <= 0 {
fraction = 0
}
return &traceIDRatioSampler{
traceIDUpperBound: uint64(fraction * (1 << 63)),
description: fmt.Sprintf("traceIDRatioBased{%g}", fraction),
}
}
func parseTraceIDRatio(arg string) (sdktrace.Sampler, error) {
v, err := strconv.ParseFloat(arg, 64)
if err != nil {
return traceIDRatioBased(1.0), samplerArgParseError{err}
}
if v < 0.0 {
return traceIDRatioBased(0.0), errNegativeTraceIDRatio
}
if v > 1.0 {
return traceIDRatioBased(1.0), errGreaterThanOneTraceIDRatio
}
return traceIDRatioBased(v), nil
}
func addTraceIDRatioSampler(opts []sdktrace.TracerProviderOption) ([]sdktrace.TracerProviderOption, error) {
samplerName, ok := os.LookupEnv(tracesSamplerKey)
if !ok {
return opts, nil
}
if strings.ToLower(strings.TrimSpace(samplerName)) != samplerTraceIDRatio {
return opts, nil
}
samplerArg, hasSamplerArg := os.LookupEnv(tracesSamplerArgKey)
samplerArg = strings.TrimSpace(samplerArg)
var (
sampler sdktrace.Sampler
err error
)
if !hasSamplerArg {
sampler = traceIDRatioBased(1.0)
} else {
sampler, err = parseTraceIDRatio(samplerArg)
}
return append(opts, sdktrace.WithSampler(sampler)), err
}