Skip to content

dash0hq/kubecon26EU-sampling

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenTelemetry sampling — KubeCon EU 2026

Companion material for the KubeCon EU 2026 talk on OpenTelemetry sampling strategies. Each directory contains a self-contained Kubernetes setup for a different approach.

Strategies

Strategy Directory When to use
Head sampling head-sampling/ Simple, stateless volume reduction by a fixed percentage
Tail sampling tail-sampling/ Keep errors and slow traces; drop only healthy, fast traces

Head sampling

The sampling decision is made upfront, before the trace completes, based on the trace ID alone. Every Collector replica independently reaches the same decision — no coordination needed.

Head sampling architecture

See head-sampling/README.md.

Tail sampling

The sampling decision is made after the full trace is collected, so errors and slow requests can always be retained regardless of sampling rate. Requires a two-tier Collector setup.

Tail sampling architecture

See tail-sampling/README.md.

Prerequisites

  • Kubernetes cluster with kubectl configured

Each setup is self-contained and includes Jaeger as the trace backend. Jaeger uses in-memory storage — suitable for demos, not for production.

Depending on your cluster's setup, you may need to use port-forwarding or an ingress controller to expose Jaeger.

Deploy both scenarios side by side

The two scenarios can run simultaneously in separate namespaces. The commands below substitute the namespace in every manifest on the fly, so no files need to be edited.

1. Build the application images

docker build -t node-frontend:latest apps/node-frontend
docker build -t go-backend:latest    apps/go-backend

Load them into your local cluster if you are using kind:

kind load docker-image node-frontend:latest
kind load docker-image go-backend:latest

2. Deploy head sampling

kubectl create namespace head-sampling

for f in head-sampling/*.yaml; do
  sed 's/namespace: otel/namespace: head-sampling/g
       s/namespace: default/namespace: head-sampling/g
       s/\.otel\.svc\.cluster\.local/.head-sampling.svc.cluster.local/g' "$f" \
  | kubectl apply -f -
done

3. Deploy tail sampling

kubectl create namespace tail-sampling

for f in tail-sampling/*.yaml; do
  sed 's/namespace: otel/namespace: tail-sampling/g
       s/namespace: default/namespace: tail-sampling/g
       s/\.otel\.svc\.cluster\.local/.tail-sampling.svc.cluster.local/g' "$f" \
  | kubectl apply -f -
done

4. Open the Jaeger UIs

# Head sampling — http://localhost:16686
kubectl port-forward -n head-sampling svc/jaeger 16686:16686 &

# Tail sampling — http://localhost:16687
kubectl port-forward -n tail-sampling svc/jaeger 16687:16686 &

The load generator sends one request per second to each scenario automatically. After a few minutes, both Jaeger instances will show sampled traces from the node-frontend and go-backend services.

5. Tear down

kubectl delete namespace head-sampling
kubectl delete namespace tail-sampling

About

Sample repository that accompanies the "Theory and practice of sampling in OpenTelemetry" at KubeCon EU 26

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors