Skip to content

Commit 4d0ee15

Browse files
authored
Merge pull request #134 from basvanbeek/http-server-request-sampler
Improved http server request sampler logic
2 parents 1277a5f + 8774349 commit 4d0ee15

File tree

5 files changed

+44
-24
lines changed

5 files changed

+44
-24
lines changed

middleware/http/request_sampler.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package http
2+
3+
import "net/http"
4+
5+
// RequestSamplerFunc can be implemented for client and/or server side sampling decisions that can override the existing
6+
// upstream sampling decision. If the implementation returns nil, the existing sampling decision stays as is.
7+
type RequestSamplerFunc func(r *http.Request) *bool
8+
9+
// Sample is a convenience function that returns a pointer to a boolean true. Use this for RequestSamplerFuncs when
10+
// wanting the RequestSampler to override the sampling decision to yes.
11+
func Sample() *bool {
12+
sample := true
13+
return &sample
14+
}
15+
16+
// Discard is a convenience function that returns a pointer to a boolean false. Use this for RequestSamplerFuncs when
17+
// wanting the RequestSampler to override the sampling decision to no.
18+
func Discard() *bool {
19+
sample := false
20+
return &sample
21+
}

middleware/http/server.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type handler struct {
3131
next http.Handler
3232
tagResponseSize bool
3333
defaultTags map[string]string
34-
requestSampler func(r *http.Request) bool
34+
requestSampler RequestSamplerFunc
3535
errHandler ErrHandler
3636
}
3737

@@ -64,8 +64,9 @@ func SpanName(name string) ServerOption {
6464
}
6565

6666
// RequestSampler allows one to set the sampling decision based on the details
67-
// found in the http.Request.
68-
func RequestSampler(sampleFunc func(r *http.Request) bool) ServerOption {
67+
// found in the http.Request. If wanting to keep the existing sampling decision
68+
// from upstream as is, this function should return nil.
69+
func RequestSampler(sampleFunc RequestSamplerFunc) ServerOption {
6970
return func(h *handler) {
7071
h.requestSampler = sampleFunc
7172
}
@@ -100,9 +101,10 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
100101
// try to extract B3 Headers from upstream
101102
sc := h.tracer.Extract(b3.ExtractHTTP(r))
102103

103-
if h.requestSampler != nil && sc.Sampled == nil {
104-
sample := h.requestSampler(r)
105-
sc.Sampled = &sample
104+
if h.requestSampler != nil {
105+
if sample := h.requestSampler(r); sample != nil {
106+
sc.Sampled = sample
107+
}
106108
}
107109

108110
remoteEndpoint, _ := zipkin.NewEndpoint("", r.RemoteAddr)

middleware/http/server_test.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,14 @@ func TestHTTPRequestSampler(t *testing.T) {
214214
httpHandlerFunc = http.HandlerFunc(httpHandler(200, nil, bytes.NewBufferString("")))
215215
)
216216

217-
samplers := [](func(r *http.Request) bool){
217+
samplers := [](func(r *http.Request) *bool){
218218
nil,
219-
func(r *http.Request) bool { return true },
220-
func(r *http.Request) bool { return false },
219+
func(r *http.Request) *bool { return mw.Sample() },
220+
func(r *http.Request) *bool { return mw.Discard() },
221+
func(r *http.Request) *bool { return nil },
221222
}
222223

223-
for _, sampler := range samplers {
224+
for idx, sampler := range samplers {
224225
tr, _ := zipkin.NewTracer(spanRecorder, zipkin.WithLocalEndpoint(lep), zipkin.WithSampler(zipkin.AlwaysSample))
225226

226227
request, err := http.NewRequest(methodType, "/test", requestBuf)
@@ -235,16 +236,16 @@ func TestHTTPRequestSampler(t *testing.T) {
235236
spans := spanRecorder.Flush()
236237

237238
sampledSpans := 0
238-
if sampler == nil || sampler(request) {
239+
if sampler == nil || sampler(request) == nil || *(sampler(request)) {
239240
sampledSpans = 1
240241
}
241242

242243
if want, have := sampledSpans, len(spans); want != have {
243-
t.Errorf("Expected %d spans, got %d", want, have)
244+
t.Errorf("[%d] Expected %d spans, got %d", idx, want, have)
244245
}
245246
}
246247

247-
for _, sampler := range samplers {
248+
for idx, sampler := range samplers {
248249
tr, _ := zipkin.NewTracer(spanRecorder, zipkin.WithLocalEndpoint(lep), zipkin.WithSampler(zipkin.NeverSample))
249250

250251
request, err := http.NewRequest(methodType, "/test", requestBuf)
@@ -259,12 +260,12 @@ func TestHTTPRequestSampler(t *testing.T) {
259260
spans := spanRecorder.Flush()
260261

261262
sampledSpans := 0
262-
if sampler != nil && sampler(request) {
263+
if sampler != nil && sampler(request) != nil && *(sampler(request)) {
263264
sampledSpans = 1
264265
}
265266

266267
if want, have := sampledSpans, len(spans); want != have {
267-
t.Errorf("Expected %d spans, got %d", want, have)
268+
t.Errorf("[%d] Expected %d spans, got %d", idx, want, have)
268269
}
269270
}
270271

middleware/http/transport.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type transport struct {
5757
errHandler ErrHandler
5858
errResponseReader *ErrResponseReader
5959
logger *log.Logger
60-
requestSampler func(r *http.Request) *bool
60+
requestSampler RequestSamplerFunc
6161
}
6262

6363
// TransportOption allows one to configure optional transport configuration.
@@ -112,7 +112,7 @@ func TransportLogger(l *log.Logger) TransportOption {
112112
// sampling decision contained in the context. The function returns a *bool,
113113
// if returning nil, sampling decision is not being changed whereas returning
114114
// something else than nil is being used as sampling decision.
115-
func TransportRequestSampler(sampleFunc func(r *http.Request) *bool) TransportOption {
115+
func TransportRequestSampler(sampleFunc RequestSamplerFunc) TransportOption {
116116
return func(t *transport) {
117117
t.requestSampler = sampleFunc
118118
}

middleware/http/transport_test.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,10 @@ func TestRoundTripErrResponseReadingSuccess(t *testing.T) {
128128
}
129129
}
130130

131-
func boolToPtr(b bool) *bool {
132-
return &b
133-
}
134-
135131
func TestTransportRequestSamplerOverridesSamplingFromContext(t *testing.T) {
136132
cases := []struct {
137133
Sampler func(uint64) bool
138-
RequestSampler func(*http.Request) *bool
134+
RequestSampler RequestSamplerFunc
139135
ExpectedSampling string
140136
}{
141137
// Test proper handling when there is no RequestSampler
@@ -153,13 +149,13 @@ func TestTransportRequestSamplerOverridesSamplingFromContext(t *testing.T) {
153149
// Test RequestSampler override sample -> no sample
154150
{
155151
Sampler: zipkin.AlwaysSample,
156-
RequestSampler: func(_ *http.Request) *bool { return boolToPtr(false) },
152+
RequestSampler: func(_ *http.Request) *bool { return Discard() },
157153
ExpectedSampling: "0",
158154
},
159155
// Test RequestSampler override no sample -> sample
160156
{
161157
Sampler: zipkin.NeverSample,
162-
RequestSampler: func(_ *http.Request) *bool { return boolToPtr(true) },
158+
RequestSampler: func(_ *http.Request) *bool { return Sample() },
163159
ExpectedSampling: "1",
164160
},
165161
// Test RequestSampler pass through of sampled decision

0 commit comments

Comments
 (0)