diff --git a/CHANGELOG.md b/CHANGELOG.md index a499af2a30d..2b43db8da57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,11 +17,15 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Added - Add the `zpages` span processor. (#894) +- Add `WithoutSubSpans`, `WithRedactedHeaders`, `WithoutHeaders`, and `WithInsecureHeaders` options for `otelhttptrace.NewClientTrace`. (#879) + ### Changed - The `b3.B3` type has been removed. `b3.New()` and `b3.WithInjectEncoding(encoding)` are added to replace it. (#868) +- `otelhttptrace.NewClientTrace` now redacts known sensitive headers by default. (#879) + ### Fixed @@ -29,14 +33,6 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm The `messaging.message_id` and `messaging.kafka.partition` attributes are now not set if a message was not processed. (#754) (#755) (#881) - Fix `otelsarama.WrapAsyncProducer` so that the messages from the `Errors` channel contain the original `Metadata`. (#754) -### Added - -- Add `WithoutSubSpans`, `WithRedactedHeaders`, `WithoutHeaders`, and `WithInsecureHeaders` options for `otelhttptrace.NewClientTrace`. (#879) - -### Changed - -- `otelhttptrace.NewClientTrace` now redacts known sensitive headers by default. (#879) - ## [0.21.0] - 2021-06-18 ### Fixed diff --git a/instrumentation/net/http/httptrace/otelhttptrace/clienttrace_test.go b/instrumentation/net/http/httptrace/otelhttptrace/clienttrace_test.go index d6de5f15936..77e9a6f6629 100644 --- a/instrumentation/net/http/httptrace/otelhttptrace/clienttrace_test.go +++ b/instrumentation/net/http/httptrace/otelhttptrace/clienttrace_test.go @@ -255,21 +255,33 @@ func TestEndBeforeStartCreatesSpan(t *testing.T) { require.Len(t, spans, 1) } -func TestClientTraceOptions(t *testing.T) { - sr := &oteltest.SpanRecorder{} +type clientTraceTestFixture struct { + Address string + URL string + Client *http.Client + SpanRecorder *oteltest.SpanRecorder +} + +func prepareClientTraceTest(t *testing.T) clientTraceTestFixture { + fixture := clientTraceTestFixture{} + fixture.SpanRecorder = &oteltest.SpanRecorder{} otel.SetTracerProvider( - oteltest.NewTracerProvider(oteltest.WithSpanRecorder(sr)), + oteltest.NewTracerProvider(oteltest.WithSpanRecorder(fixture.SpanRecorder)), ) - // Mock http server ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { }), ) - defer ts.Close() - address := ts.Listener.Addr().String() + t.Cleanup(ts.Close) + fixture.Client = ts.Client() + fixture.URL = ts.URL + fixture.Address = ts.Listener.Addr().String() + return fixture +} - // Test WithoutSubSpans +func TestWithoutSubSpans(t *testing.T) { + fixture := prepareClientTraceTest(t) ctx := context.Background() ctx = httptrace.WithClientTrace(ctx, @@ -277,13 +289,13 @@ func TestClientTraceOptions(t *testing.T) { otelhttptrace.WithoutSubSpans(), ), ) - req, err := http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) - resp, err := ts.Client().Do(req) + resp, err := fixture.Client.Do(req) require.NoError(t, err) resp.Body.Close() // no spans created because we were just using background context without span - require.Len(t, sr.Completed(), 0) + require.Len(t, fixture.SpanRecorder.Completed(), 0) // Start again with a "real" span in the context, now tracing should add // events and annotations. @@ -293,17 +305,17 @@ func TestClientTraceOptions(t *testing.T) { otelhttptrace.WithoutSubSpans(), ), ) - req, err = http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) req.Header.Set("User-Agent", "oteltest/1.1") req.Header.Set("Authorization", "Bearer token123") require.NoError(t, err) - resp, err = ts.Client().Do(req) + resp, err = fixture.Client.Do(req) require.NoError(t, err) resp.Body.Close() span.End() // we just have the one span we created - require.Len(t, sr.Completed(), 1) - recSpan := sr.Completed()[0] + require.Len(t, fixture.SpanRecorder.Completed(), 1) + recSpan := fixture.SpanRecorder.Completed()[0] gotAttributes := recSpan.Attributes() require.Len(t, gotAttributes, 4) @@ -321,7 +333,7 @@ func TestClientTraceOptions(t *testing.T) { gotAttributes[attribute.Key("http.authorization")], ) assert.Equal(t, - attribute.StringValue(address), + attribute.StringValue(fixture.Address), gotAttributes[attribute.Key("http.host")], ) @@ -332,7 +344,7 @@ func TestClientTraceOptions(t *testing.T) { }{ {"http.getconn.start", func(t *testing.T, got attrMap) { assert.Equal(t, - attribute.StringValue(address), + attribute.StringValue(fixture.Address), got[attribute.Key("http.host")], ) }}, @@ -348,7 +360,7 @@ func TestClientTraceOptions(t *testing.T) { got[attribute.Key("http.conn.wasidle")], ) assert.Equal(t, - attribute.StringValue(address), + attribute.StringValue(fixture.Address), got[attribute.Key("http.remote")], ) // value is dynamic, just verify we have the attribute @@ -372,72 +384,78 @@ func TestClientTraceOptions(t *testing.T) { }) } } +} - // Test WithRedactedHeaders +func TestWithRedactedHeaders(t *testing.T) { + fixture := prepareClientTraceTest(t) - ctx, span = otel.Tracer("oteltest").Start(context.Background(), "root") + ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithRedactedHeaders("user-agent"), ), ) - req, err = http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) - resp, err = ts.Client().Do(req) + resp, err := fixture.Client.Do(req) require.NoError(t, err) resp.Body.Close() span.End() - require.Len(t, sr.Completed(), 2) - recSpan = sr.Completed()[1] + require.Len(t, fixture.SpanRecorder.Completed(), 1) + recSpan := fixture.SpanRecorder.Completed()[0] - gotAttributes = recSpan.Attributes() + gotAttributes := recSpan.Attributes() assert.Equal(t, attribute.StringValue("****"), gotAttributes[attribute.Key("http.user-agent")], ) +} - // Test WithoutHeaders +func TestWithoutHeaders(t *testing.T) { + fixture := prepareClientTraceTest(t) - ctx, span = otel.Tracer("oteltest").Start(context.Background(), "root") + ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithoutHeaders(), ), ) - req, err = http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) require.NoError(t, err) - resp, err = ts.Client().Do(req) + resp, err := fixture.Client.Do(req) require.NoError(t, err) resp.Body.Close() span.End() - require.Len(t, sr.Completed(), 3) - recSpan = sr.Completed()[2] + require.Len(t, fixture.SpanRecorder.Completed(), 1) + recSpan := fixture.SpanRecorder.Completed()[0] - gotAttributes = recSpan.Attributes() + gotAttributes := recSpan.Attributes() require.Len(t, gotAttributes, 0) +} - // Test WithInsecureHeaders +func TestWithInsecureHeaders(t *testing.T) { + fixture := prepareClientTraceTest(t) - ctx, span = otel.Tracer("oteltest").Start(context.Background(), "root") + ctx, span := otel.Tracer("oteltest").Start(context.Background(), "root") ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx, otelhttptrace.WithoutSubSpans(), otelhttptrace.WithInsecureHeaders(), ), ) - req, err = http.NewRequestWithContext(ctx, http.MethodGet, ts.URL, nil) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, fixture.URL, nil) req.Header.Set("Authorization", "Bearer token123") require.NoError(t, err) - resp, err = ts.Client().Do(req) + resp, err := fixture.Client.Do(req) require.NoError(t, err) resp.Body.Close() span.End() - require.Len(t, sr.Completed(), 4) - recSpan = sr.Completed()[3] + require.Len(t, fixture.SpanRecorder.Completed(), 1) + recSpan := fixture.SpanRecorder.Completed()[0] - gotAttributes = recSpan.Attributes() + gotAttributes := recSpan.Attributes() assert.Equal(t, attribute.StringValue("Bearer token123"), gotAttributes[attribute.Key("http.authorization")],