Skip to content

Commit f2e3397

Browse files
authored
HTTPReporter: Adds b3:0 header and unit test for custom headers using HTTPDoer (#176)
* add b3:0 to http reporter and added test for custom headers using HTTPDoer * Fix: Go < 1.14 does not support http.Header.Values()
1 parent dc18516 commit f2e3397

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

reporter/http/http.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type httpReporter struct {
6060
reqCallback RequestCallbackFn
6161
reqTimeout time.Duration
6262
serializer reporter.SpanSerializer
63+
doNotSample bool
6364
}
6465

6566
// Send implements reporter
@@ -152,6 +153,9 @@ func (r *httpReporter) sendBatch() error {
152153
r.logger.Printf("failed when creating the request: %s\n", err.Error())
153154
return err
154155
}
156+
if r.doNotSample {
157+
req.Header.Set("b3", "0")
158+
}
155159
req.Header.Set("Content-Type", r.serializer.ContentType())
156160
if r.reqCallback != nil {
157161
r.reqCallback(req)
@@ -237,6 +241,17 @@ func Serializer(serializer reporter.SpanSerializer) ReporterOption {
237241
}
238242
}
239243

244+
// AllowSamplingReporterCalls if set to true will remove the b3:0 header on
245+
// outgoing calls to the Zipkin collector.
246+
// By default we send b3:0 header to mitigate trace reporting amplification in
247+
// service mesh environments where the sidecar proxies might trace the call
248+
// we do here towards the Zipkin collector.
249+
func AllowSamplingReporterCalls(allow bool) ReporterOption {
250+
return func(r *httpReporter) {
251+
r.doNotSample = !allow
252+
}
253+
}
254+
240255
// NewReporter returns a new HTTP Reporter.
241256
// url should be the endpoint to send the spans to, e.g.
242257
// http://localhost:9411/api/v2/spans
@@ -256,6 +271,7 @@ func NewReporter(url string, opts ...ReporterOption) reporter.Reporter {
256271
batchMtx: &sync.Mutex{},
257272
serializer: reporter.JSONSerializer{},
258273
reqTimeout: defaultTimeout,
274+
doNotSample: true,
259275
}
260276

261277
for _, opt := range opts {

reporter/http/http_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"io/ioutil"
2121
"net/http"
2222
"net/http/httptest"
23+
"reflect"
2324
"sync/atomic"
2425
"testing"
2526
"time"
@@ -167,3 +168,91 @@ func TestSpanIsReportedAfterBatchSize(t *testing.T) {
167168
t.Errorf("unexpected number of spans received\nhave: %d, want: %d", aNumSpans, eNumSpans)
168169
}
169170
}
171+
172+
func TestSpanCustomHeaders(t *testing.T) {
173+
serializer := reporter.JSONSerializer{}
174+
175+
hc := headerClient{
176+
headers: http.Header{
177+
"Key1": []string{"val1a", "val1b"},
178+
"Key2": []string{"val2"},
179+
},
180+
}
181+
var haveHeaders http.Header
182+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
183+
haveHeaders = r.Header
184+
}))
185+
defer ts.Close()
186+
187+
spans := generateSpans(1)
188+
189+
rep := zipkinhttp.NewReporter(
190+
ts.URL,
191+
zipkinhttp.Serializer(serializer),
192+
zipkinhttp.Client(hc),
193+
)
194+
for _, span := range spans {
195+
rep.Send(*span)
196+
}
197+
rep.Close()
198+
199+
for _, key := range []string{"Key1", "Key2"} {
200+
if want, have := hc.headers[key], haveHeaders[key]; !reflect.DeepEqual(want, have) {
201+
t.Errorf("header %s: want: %v, have: %v\n", key, want, have)
202+
}
203+
}
204+
}
205+
206+
func TestB3SamplingHeader(t *testing.T) {
207+
serializer := reporter.JSONSerializer{}
208+
209+
var haveHeaders map[string][]string
210+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
211+
haveHeaders = r.Header
212+
}))
213+
defer ts.Close()
214+
215+
spans := generateSpans(1)
216+
217+
rep := zipkinhttp.NewReporter(
218+
ts.URL,
219+
zipkinhttp.Serializer(serializer),
220+
zipkinhttp.AllowSamplingReporterCalls(true),
221+
)
222+
for _, span := range spans {
223+
rep.Send(*span)
224+
}
225+
rep.Close()
226+
227+
if len(haveHeaders["B3"]) > 0 {
228+
t.Errorf("Expected B3 header to not exist, got %v", haveHeaders["B3"])
229+
}
230+
231+
rep = zipkinhttp.NewReporter(
232+
ts.URL,
233+
zipkinhttp.Serializer(serializer),
234+
)
235+
for _, span := range spans {
236+
rep.Send(*span)
237+
}
238+
rep.Close()
239+
240+
if want, have := []string{"0"}, haveHeaders["B3"]; !reflect.DeepEqual(want, have) {
241+
t.Errorf("B3 header: want: %v, have %v", want, have)
242+
}
243+
244+
}
245+
246+
type headerClient struct {
247+
client http.Client
248+
headers map[string][]string
249+
}
250+
251+
func (h headerClient) Do(req *http.Request) (*http.Response, error) {
252+
for key, item := range h.headers {
253+
for _, val := range item {
254+
req.Header.Add(key, val)
255+
}
256+
}
257+
return h.client.Do(req)
258+
}

0 commit comments

Comments
 (0)