Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion tracing/plugin/otlp.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"fmt"
"io"
"net/url"
"strings"
"time"

"github.com/containerd/containerd/errdefs"
Expand Down Expand Up @@ -101,6 +102,7 @@ type OTLPConfig struct {
type TraceConfig struct {
ServiceName string `toml:"service_name"`
TraceSamplingRatio float64 `toml:"sampling_ratio"`
AllowedNames string `toml:"allowed_names"`
}

type closer struct {
Expand Down Expand Up @@ -159,12 +161,23 @@ func newTracer(ctx context.Context, config *TraceConfig, procs []trace.SpanProce
// Service name used to displace traces in backends
semconv.ServiceNameKey.String(config.ServiceName),
),
resource.WithFromEnv(),
)
if err != nil {
return nil, fmt.Errorf("failed to create resource: %w", err)
}

sampler := trace.ParentBased(trace.TraceIDRatioBased(config.TraceSamplingRatio))
if config.TraceSamplingRatio < 1 && config.AllowedNames == "" {
return nil, fmt.Errorf("only one of trace_sampling_ratio or allowed_names can be set")
}

var sampler trace.Sampler
if config.AllowedNames == "" {
sampler = trace.ParentBased(trace.TraceIDRatioBased(config.TraceSamplingRatio))
} else {
allowedNames := strings.Split(config.AllowedNames, ",")
sampler = trace.ParentBased(NameBased(allowedNames))
}

opts := []trace.TracerProviderOption{
trace.WithSampler(sampler),
Expand Down
46 changes: 46 additions & 0 deletions tracing/plugin/sampler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package plugin

import (
"fmt"

sdkTrace "go.opentelemetry.io/otel/sdk/trace"
"go.opentelemetry.io/otel/trace"
)

type NameSampler struct {
// allow is a set of names that should be sampled.
// Uses a map of empty structs for O(1) lookups and no memory overhead.
allow map[string]struct{}
}

// NameBased returns a Sampler that samples every span having a certain name.
// It should be used in conjunction with the ParentBased sampler so that the child spans are also sampled.
func NameBased(allowedNames []string) NameSampler {
allowedNamesMap := make(map[string]struct{}, len(allowedNames))
for _, name := range allowedNames {
allowedNamesMap[name] = struct{}{}
}
return NameSampler{
allow: allowedNamesMap,
}
}

func (ns NameSampler) ShouldSample(parameters sdkTrace.SamplingParameters) sdkTrace.SamplingResult {
psc := trace.SpanContextFromContext(parameters.ParentContext)

if _, ok := ns.allow[parameters.Name]; ok {
return sdkTrace.SamplingResult{
Decision: sdkTrace.RecordAndSample,
Tracestate: psc.TraceState(),
}
}

return sdkTrace.SamplingResult{
Decision: sdkTrace.Drop,
Tracestate: psc.TraceState(),
}
}

func (ns NameSampler) Description() string {
return fmt.Sprintf("NameBased:{%v}", ns.allow)
}