Skip to content

Commit 787e3f4

Browse files
jcchavezscbandyAneurysm9MrAlias
authored
chore(zipkin-exporter): relay on the status code for the request but still read the response body. (open-telemetry#1328)
* chore(zipkin-exporter): relay on the status code for the request but still read the response body. * fix(zipkin-exporter): fix tests. * chore(zipkin-exporter): adds changelog. * chore: 202 -> http.StatusAccepted Co-authored-by: Chris Bandy <[email protected]> * chore: 202 -> http.StatusAccepted Co-authored-by: Anthony Mirabella <[email protected]> Co-authored-by: Chris Bandy <[email protected]> Co-authored-by: Anthony Mirabella <[email protected]> Co-authored-by: Tyler Yahn <[email protected]>
1 parent 66db2d8 commit 787e3f4

File tree

3 files changed

+17
-14
lines changed

3 files changed

+17
-14
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1212

1313
- Move the OpenCensus example into `example` directory. (#1359)
1414
- `NewExporter` and `Start` functions in `go.opentelemetry.io/otel/exporters/otlp` now receive `context.Context` as a first parameter. (#1357)
15+
- Zipkin exporter relies on the status code for success rather than body read but still read the response body. (#1328)
1516

1617
## [0.14.0] - 2020-11-19
1718

exporters/trace/zipkin/zipkin.go

+14-11
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"errors"
2222
"fmt"
23+
"io"
2324
"io/ioutil"
2425
"log"
2526
"net/http"
@@ -112,14 +113,14 @@ func NewRawExporter(collectorURL, serviceName string, opts ...Option) (*Exporter
112113
// NewExportPipeline sets up a complete export pipeline
113114
// with the recommended setup for trace provider
114115
func NewExportPipeline(collectorURL, serviceName string, opts ...Option) (*sdktrace.TracerProvider, error) {
115-
exp, err := NewRawExporter(collectorURL, serviceName, opts...)
116+
exporter, err := NewRawExporter(collectorURL, serviceName, opts...)
116117
if err != nil {
117118
return nil, err
118119
}
119120

120-
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exp))
121-
if exp.o.config != nil {
122-
tp.ApplyConfig(*exp.o.config)
121+
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
122+
if exporter.o.config != nil {
123+
tp.ApplyConfig(*exporter.o.config)
123124
}
124125

125126
return tp, err
@@ -166,19 +167,21 @@ func (e *Exporter) ExportSpans(ctx context.Context, batch []*export.SpanData) er
166167
if err != nil {
167168
return e.errf("request to %s failed: %v", e.url, err)
168169
}
169-
e.logf("zipkin responded with status %d", resp.StatusCode)
170+
defer resp.Body.Close()
170171

171-
_, err = ioutil.ReadAll(resp.Body)
172+
// Zipkin API returns a 202 on success and the content of the body isn't interesting
173+
// but it is still being read because according to https://golang.org/pkg/net/http/#Response
174+
// > The default HTTP client's Transport may not reuse HTTP/1.x "keep-alive" TCP connections
175+
// > if the Body is not read to completion and closed.
176+
_, err = io.Copy(ioutil.Discard, resp.Body)
172177
if err != nil {
173-
// Best effort to clean up here.
174-
resp.Body.Close()
175178
return e.errf("failed to read response body: %v", err)
176179
}
177180

178-
err = resp.Body.Close()
179-
if err != nil {
180-
return e.errf("failed to close response body: %v", err)
181+
if resp.StatusCode != http.StatusAccepted {
182+
return e.errf("failed to send spans to zipkin server with status %d", resp.StatusCode)
181183
}
184+
182185
return nil
183186
}
184187

exporters/trace/zipkin/zipkin_test.go

+2-3
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ func (c *mockZipkinCollector) handler(w http.ResponseWriter, r *http.Request) {
192192
c.lock.Lock()
193193
defer c.lock.Unlock()
194194
c.models = append(c.models, models...)
195+
w.WriteHeader(http.StatusAccepted)
195196
}
196197

197198
func (c *mockZipkinCollector) Close() {
@@ -340,17 +341,15 @@ func TestExportSpans(t *testing.T) {
340341
ctx := context.Background()
341342
require.Len(t, ls.Messages, 0)
342343
require.NoError(t, exporter.ExportSpans(ctx, spans[0:1]))
343-
require.Len(t, ls.Messages, 2)
344+
require.Len(t, ls.Messages, 1)
344345
require.Contains(t, ls.Messages[0], "send a POST request")
345-
require.Contains(t, ls.Messages[1], "zipkin responded")
346346
ls.Messages = nil
347347
require.NoError(t, exporter.ExportSpans(ctx, nil))
348348
require.Len(t, ls.Messages, 1)
349349
require.Contains(t, ls.Messages[0], "no spans to export")
350350
ls.Messages = nil
351351
require.NoError(t, exporter.ExportSpans(ctx, spans[1:2]))
352352
require.Contains(t, ls.Messages[0], "send a POST request")
353-
require.Contains(t, ls.Messages[1], "zipkin responded")
354353
checkFunc := func() bool {
355354
return collector.ModelsLen() == len(models)
356355
}

0 commit comments

Comments
 (0)