package trace
import (
"context"
"encoding/binary"
"fmt"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/trace"
)
type Sampler interface {
ShouldSample (parameters SamplingParameters ) SamplingResult
Description () string
}
type SamplingParameters struct {
ParentContext context .Context
TraceID trace .TraceID
Name string
Kind trace .SpanKind
Attributes []attribute .KeyValue
Links []trace .Link
}
type SamplingDecision uint8
const (
Drop SamplingDecision = iota
RecordOnly
RecordAndSample
)
type SamplingResult struct {
Decision SamplingDecision
Attributes []attribute .KeyValue
Tracestate trace .TraceState
}
type traceIDRatioSampler struct {
traceIDUpperBound uint64
description string
}
func (ts traceIDRatioSampler ) ShouldSample (p SamplingParameters ) SamplingResult {
psc := trace .SpanContextFromContext (p .ParentContext )
x := binary .BigEndian .Uint64 (p .TraceID [8 :16 ]) >> 1
if x < ts .traceIDUpperBound {
return SamplingResult {
Decision : RecordAndSample ,
Tracestate : psc .TraceState (),
}
}
return SamplingResult {
Decision : Drop ,
Tracestate : psc .TraceState (),
}
}
func (ts traceIDRatioSampler ) Description () string {
return ts .description
}
func TraceIDRatioBased (fraction float64 ) Sampler {
if fraction >= 1 {
return AlwaysSample ()
}
if fraction <= 0 {
fraction = 0
}
return &traceIDRatioSampler {
traceIDUpperBound : uint64 (fraction * (1 << 63 )),
description : fmt .Sprintf ("TraceIDRatioBased{%g}" , fraction ),
}
}
type alwaysOnSampler struct {}
func (alwaysOnSampler ) ShouldSample (p SamplingParameters ) SamplingResult {
return SamplingResult {
Decision : RecordAndSample ,
Tracestate : trace .SpanContextFromContext (p .ParentContext ).TraceState (),
}
}
func (alwaysOnSampler ) Description () string {
return "AlwaysOnSampler"
}
func AlwaysSample () Sampler {
return alwaysOnSampler {}
}
type alwaysOffSampler struct {}
func (alwaysOffSampler ) ShouldSample (p SamplingParameters ) SamplingResult {
return SamplingResult {
Decision : Drop ,
Tracestate : trace .SpanContextFromContext (p .ParentContext ).TraceState (),
}
}
func (alwaysOffSampler ) Description () string {
return "AlwaysOffSampler"
}
func NeverSample () Sampler {
return alwaysOffSampler {}
}
func ParentBased (root Sampler , samplers ...ParentBasedSamplerOption ) Sampler {
return parentBased {
root : root ,
config : configureSamplersForParentBased (samplers ),
}
}
type parentBased struct {
root Sampler
config samplerConfig
}
func configureSamplersForParentBased(samplers []ParentBasedSamplerOption ) samplerConfig {
c := samplerConfig {
remoteParentSampled : AlwaysSample (),
remoteParentNotSampled : NeverSample (),
localParentSampled : AlwaysSample (),
localParentNotSampled : NeverSample (),
}
for _ , so := range samplers {
c = so .apply (c )
}
return c
}
type samplerConfig struct {
remoteParentSampled, remoteParentNotSampled Sampler
localParentSampled, localParentNotSampled Sampler
}
type ParentBasedSamplerOption interface {
apply(samplerConfig ) samplerConfig
}
func WithRemoteParentSampled (s Sampler ) ParentBasedSamplerOption {
return remoteParentSampledOption {s }
}
type remoteParentSampledOption struct {
s Sampler
}
func (o remoteParentSampledOption ) apply (config samplerConfig ) samplerConfig {
config .remoteParentSampled = o .s
return config
}
func WithRemoteParentNotSampled (s Sampler ) ParentBasedSamplerOption {
return remoteParentNotSampledOption {s }
}
type remoteParentNotSampledOption struct {
s Sampler
}
func (o remoteParentNotSampledOption ) apply (config samplerConfig ) samplerConfig {
config .remoteParentNotSampled = o .s
return config
}
func WithLocalParentSampled (s Sampler ) ParentBasedSamplerOption {
return localParentSampledOption {s }
}
type localParentSampledOption struct {
s Sampler
}
func (o localParentSampledOption ) apply (config samplerConfig ) samplerConfig {
config .localParentSampled = o .s
return config
}
func WithLocalParentNotSampled (s Sampler ) ParentBasedSamplerOption {
return localParentNotSampledOption {s }
}
type localParentNotSampledOption struct {
s Sampler
}
func (o localParentNotSampledOption ) apply (config samplerConfig ) samplerConfig {
config .localParentNotSampled = o .s
return config
}
func (pb parentBased ) ShouldSample (p SamplingParameters ) SamplingResult {
psc := trace .SpanContextFromContext (p .ParentContext )
if psc .IsValid () {
if psc .IsRemote () {
if psc .IsSampled () {
return pb .config .remoteParentSampled .ShouldSample (p )
}
return pb .config .remoteParentNotSampled .ShouldSample (p )
}
if psc .IsSampled () {
return pb .config .localParentSampled .ShouldSample (p )
}
return pb .config .localParentNotSampled .ShouldSample (p )
}
return pb .root .ShouldSample (p )
}
func (pb parentBased ) Description () string {
return fmt .Sprintf ("ParentBased{root:%s,remoteParentSampled:%s," +
"remoteParentNotSampled:%s,localParentSampled:%s,localParentNotSampled:%s}" ,
pb .root .Description (),
pb .config .remoteParentSampled .Description (),
pb .config .remoteParentNotSampled .Description (),
pb .config .localParentSampled .Description (),
pb .config .localParentNotSampled .Description (),
)
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .