Skip to content

Commit

Permalink
Add WithHeaders option for Zipkin exporter (#5530)
Browse files Browse the repository at this point in the history
- Added `WithHeaders` option func, which allows user to set custom http
request headers while exporting spans.
- Closes: #3474

---------

Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com>
  • Loading branch information
srijan-27 and MrAlias authored Jun 26, 2024
1 parent 6d45f28 commit af317f0
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
- Store and provide the emitted `context.Context` in `ScopeRecords` of `go.opentelemetry.io/otel/sdk/log/logtest`. (#5468)
- `SimpleProcessor.OnEmit` in `go.opentelemetry.io/otel/sdk/log` no longer allocates a slice which makes it possible to have a zero-allocation log processing using `SimpleProcessor`. (#5493)
- The `AssertRecordEqual` method to `go.opentelemetry.io/otel/log/logtest` to allow comparison of two log records in tests. (#5499)
- The `WithHeaders` option to `go.opentelemetry.io/otel/exporters/zipkin` to allow configuring custom http headers while exporting spans. (#5530)
- `service.instance.id` is populated for a `Resource` created with `"go.opentelemetry.io/otel/sdk/resource".Default` with a default value when `OTEL_GO_X_RESOURCE` is set. (#5520)

### Changed
Expand Down
37 changes: 29 additions & 8 deletions exporters/zipkin/zipkin.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"log"
"net/http"
"net/url"
"strings"
"sync"

"github.com/go-logr/logr"
Expand All @@ -26,9 +27,10 @@ const (

// Exporter exports spans to the zipkin collector.
type Exporter struct {
url string
client *http.Client
logger logr.Logger
url string
client *http.Client
logger logr.Logger
headers map[string]string

stoppedMu sync.RWMutex
stopped bool
Expand All @@ -40,8 +42,9 @@ var emptyLogger = logr.Logger{}

// Options contains configuration for the exporter.
type config struct {
client *http.Client
logger logr.Logger
client *http.Client
logger logr.Logger
headers map[string]string
}

// Option defines a function that configures the exporter.
Expand Down Expand Up @@ -70,6 +73,14 @@ func WithLogr(logger logr.Logger) Option {
})
}

// WithHeaders configures the exporter to use the passed HTTP request headers.
func WithHeaders(headers map[string]string) Option {
return optionFunc(func(cfg config) config {
cfg.headers = headers
return cfg
})
}

// WithClient configures the exporter to use the passed HTTP client.
func WithClient(client *http.Client) Option {
return optionFunc(func(cfg config) config {
Expand Down Expand Up @@ -101,9 +112,10 @@ func New(collectorURL string, opts ...Option) (*Exporter, error) {
cfg.client = http.DefaultClient
}
return &Exporter{
url: collectorURL,
client: cfg.client,
logger: cfg.logger,
url: collectorURL,
client: cfg.client,
logger: cfg.logger,
headers: cfg.headers,
}, nil
}

Expand Down Expand Up @@ -132,6 +144,15 @@ func (e *Exporter) ExportSpans(ctx context.Context, spans []sdktrace.ReadOnlySpa
return e.errf("failed to create request to %s: %v", e.url, err)
}
req.Header.Set("Content-Type", "application/json")

for k, v := range e.headers {
if strings.ToLower(k) == "host" {
req.Host = v
} else {
req.Header.Set(k, v)
}
}

resp, err := e.client.Do(req)
if err != nil {
return e.errf("request to %s failed: %v", e.url, err)
Expand Down
46 changes: 46 additions & 0 deletions exporters/zipkin/zipkin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"log"
"net"
"net/http"
"net/http/httptest"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -375,3 +376,48 @@ func TestLogrFormatting(t *testing.T) {
got := buf.String()
assert.Equal(t, want, got)
}

func TestWithHeaders(t *testing.T) {
headers := map[string]string{
"name1": "value1",
"name2": "value2",
"host": "example",
}

exp, err := New("", WithHeaders(headers))
require.NoError(t, err)

want := headers
got := exp.headers
assert.Equal(t, want, got)

spans := tracetest.SpanStubs{
{
SpanContext: trace.NewSpanContext(trace.SpanContextConfig{
TraceID: trace.TraceID{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F},
SpanID: trace.SpanID{0xFF, 0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8},
}),
},
}.Snapshots()

var req *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
req = r
w.WriteHeader(http.StatusOK)
}

srv := httptest.NewServer(http.HandlerFunc(handler))
defer srv.Close()

e := &Exporter{
url: srv.URL,
client: srv.Client(),
headers: headers,
}

_ = e.ExportSpans(context.Background(), spans)

assert.Equal(t, headers["host"], req.Host)
assert.Equal(t, headers["name1"], req.Header.Get("name1"))
assert.Equal(t, headers["name2"], req.Header.Get("name2"))
}

0 comments on commit af317f0

Please sign in to comment.