mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-04-15 11:36:44 +02:00
Add WithHeaders option for Zipkin exporter (#5530)
- 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>
This commit is contained in:
parent
6d45f283c7
commit
af317f05ef
@ -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
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
@ -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
|
||||
@ -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.
|
||||
@ -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 {
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@ -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"))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user