Skip to content

Commit f29ab1d

Browse files
authored
feat: respect jaeger parent sampling configuration (#765)
1 parent acfef3d commit f29ab1d

File tree

2 files changed

+84
-13
lines changed

2 files changed

+84
-13
lines changed

otelx/jaeger.go

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@ import (
1818
"go.opentelemetry.io/otel/trace"
1919
)
2020

21-
// Optionally, Config.Providers.Jaeger.LocalAgentAddress can be set.
22-
// NOTE: If Config.Providers.Jaeger.Sampling.ServerURL is not specfied,
23-
// AlwaysSample is used.
21+
// SetupJaeger configures and returns a Jaeger tracer.
22+
//
23+
// The returned tracer will by default attempt to send spans to a local Jaeger agent.
24+
// Optionally, [otelx.JaegerConfig.LocalAgentAddress] can be set to specify a different target.
25+
//
26+
// By default, unless a parent sampler has taken a sampling decision, every span is sampled.
27+
// [otelx.JaegerSampling.TraceIdRatio] may be used to customize the sampling probability,
28+
// optionally alongside [otelx.JaegerSampling.ServerURL] to consult a remote server
29+
// for the sampling strategy to be used.
2430
func SetupJaeger(t *Tracer, tracerName string, c *Config) (trace.Tracer, error) {
2531
host, port, err := net.SplitHostPort(c.Providers.Jaeger.LocalAgentAddress)
2632
if err != nil {
@@ -45,17 +51,22 @@ func SetupJaeger(t *Tracer, tracerName string, c *Config) (trace.Tracer, error)
4551
}
4652

4753
samplingServerURL := c.Providers.Jaeger.Sampling.ServerURL
54+
traceIdRatio := c.Providers.Jaeger.Sampling.TraceIdRatio
55+
56+
sampler := sdktrace.TraceIDRatioBased(traceIdRatio)
4857

4958
if samplingServerURL != "" {
50-
jaegerRemoteSampler := jaegerremote.New(
59+
sampler = jaegerremote.New(
5160
"jaegerremote",
5261
jaegerremote.WithSamplingServerURL(samplingServerURL),
53-
jaegerremote.WithInitialSampler(sdktrace.TraceIDRatioBased(c.Providers.Jaeger.Sampling.TraceIdRatio)),
62+
jaegerremote.WithInitialSampler(sampler),
5463
)
55-
tpOpts = append(tpOpts, sdktrace.WithSampler(jaegerRemoteSampler))
56-
} else {
57-
tpOpts = append(tpOpts, sdktrace.WithSampler(sdktrace.AlwaysSample()))
5864
}
65+
66+
// Respect any sampling decision taken by the client.
67+
sampler = sdktrace.ParentBased(sampler)
68+
tpOpts = append(tpOpts, sdktrace.WithSampler(sampler))
69+
5970
tp := sdktrace.NewTracerProvider(tpOpts...)
6071
otel.SetTracerProvider(tp)
6172

otelx/otel_test.go

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,16 @@ import (
1313
"net/http"
1414
"net/http/httptest"
1515
"net/url"
16+
"strings"
1617
"testing"
1718
"time"
1819

1920
"github.com/stretchr/testify/assert"
2021
"github.com/stretchr/testify/require"
22+
"go.opentelemetry.io/otel"
2123
"go.opentelemetry.io/otel/attribute"
24+
"go.opentelemetry.io/otel/propagation"
25+
"go.opentelemetry.io/otel/trace"
2226
"golang.org/x/sync/errgroup"
2327
"google.golang.org/protobuf/proto"
2428

@@ -65,8 +69,8 @@ type zipkinSpanRequest struct {
6569
Tags map[string]string
6670
}
6771

68-
func TestJaegerTracer(t *testing.T) {
69-
done := make(chan struct{})
72+
// runTestJaegerAgent starts a mock server listening on a random port for Jaeger spans sent over UDP.
73+
func runTestJaegerAgent(t *testing.T, errs *errgroup.Group, done chan<- struct{}) net.Conn {
7074
addr := "127.0.0.1:0"
7175

7276
udpAddr, err := net.ResolveUDPAddr("udp", addr)
@@ -75,8 +79,6 @@ func TestJaegerTracer(t *testing.T) {
7579
srv, err := net.ListenUDP("udp", udpAddr)
7680
require.NoError(t, err)
7781

78-
errs := errgroup.Group{}
79-
8082
errs.Go(func() error {
8183
t.Logf("Starting test UDP server for Jaeger spans on %s", srv.LocalAddr().String())
8284

@@ -91,20 +93,32 @@ func TestJaegerTracer(t *testing.T) {
9193
continue
9294
}
9395
if len(buf) != 0 {
94-
t.Log("recieved span!")
96+
t.Log("received span!")
9597
done <- struct{}{}
9698
}
9799
break
98100
}
99101
return nil
100102
})
101103

104+
return srv
105+
}
106+
107+
func TestJaegerTracer(t *testing.T) {
108+
done := make(chan struct{})
109+
errs := errgroup.Group{}
110+
111+
srv := runTestJaegerAgent(t, &errs, done)
112+
102113
jt, err := New(testTracingComponent, logrusx.New("ory/x", "1"), &Config{
103114
ServiceName: "Ory X",
104115
Provider: "jaeger",
105116
Providers: ProvidersConfig{
106117
Jaeger: JaegerConfig{
107118
LocalAgentAddress: srv.LocalAddr().String(),
119+
Sampling: JaegerSampling{
120+
TraceIdRatio: 1,
121+
},
108122
},
109123
},
110124
})
@@ -123,6 +137,52 @@ func TestJaegerTracer(t *testing.T) {
123137
require.NoError(t, errs.Wait())
124138
}
125139

140+
func TestJaegerTracerRespectsParentSamplingDecision(t *testing.T) {
141+
done := make(chan struct{})
142+
errs := errgroup.Group{}
143+
144+
srv := runTestJaegerAgent(t, &errs, done)
145+
146+
jt, err := New(testTracingComponent, logrusx.New("ory/x", "1"), &Config{
147+
ServiceName: "Ory X",
148+
Provider: "jaeger",
149+
Providers: ProvidersConfig{
150+
Jaeger: JaegerConfig{
151+
LocalAgentAddress: srv.LocalAddr().String(),
152+
Sampling: JaegerSampling{
153+
// Effectively disable local sampling.
154+
TraceIdRatio: 0,
155+
},
156+
},
157+
},
158+
})
159+
require.NoError(t, err)
160+
161+
traceId := strings.Repeat("a", 32)
162+
spanId := strings.Repeat("b", 16)
163+
sampledFlag := "1"
164+
traceHeaders := map[string]string{"uber-trace-id": traceId + ":" + spanId + ":0:" + sampledFlag}
165+
166+
ctx := otel.GetTextMapPropagator().Extract(context.Background(), propagation.MapCarrier(traceHeaders))
167+
spanContext := trace.SpanContextFromContext(ctx)
168+
169+
assert.True(t, spanContext.IsValid())
170+
assert.True(t, spanContext.IsSampled())
171+
assert.True(t, spanContext.IsRemote())
172+
173+
trc := jt.Tracer()
174+
_, span := trc.Start(ctx, "testSpan", trace.WithLinks(trace.Link{SpanContext: spanContext}))
175+
span.SetAttributes(attribute.Bool("testAttribute", true))
176+
span.End()
177+
178+
select {
179+
case <-done:
180+
case <-time.After(15 * time.Second):
181+
t.Fatalf("Test server did not receive spans")
182+
}
183+
require.NoError(t, errs.Wait())
184+
}
185+
126186
func TestZipkinTracer(t *testing.T) {
127187
done := make(chan struct{})
128188
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

0 commit comments

Comments
 (0)