-
Notifications
You must be signed in to change notification settings - Fork 440
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fasthttptrace: Add trace context propagation support for libraries bu…
…ilt on fasthttp (#2218)
- Loading branch information
Showing
7 changed files
with
210 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package fasthttptrace | ||
|
||
import ( | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
|
||
"github.com/valyala/fasthttp" | ||
) | ||
|
||
// FastHTTPHeadersCarrier implements tracer.TextMapWriter and tracer.TextMapReader on top | ||
// of fasthttp's RequestHeader object, allowing it to be used as a span context carrier for | ||
// distributed tracing. | ||
type FastHTTPHeadersCarrier struct { | ||
ReqHeader *fasthttp.RequestHeader | ||
} | ||
|
||
var _ tracer.TextMapWriter = (*FastHTTPHeadersCarrier)(nil) | ||
var _ tracer.TextMapReader = (*FastHTTPHeadersCarrier)(nil) | ||
|
||
// ForeachKey iterates over fasthttp request header keys and values | ||
func (f *FastHTTPHeadersCarrier) ForeachKey(handler func(key, val string) error) error { | ||
keys := f.ReqHeader.PeekKeys() | ||
for _, key := range keys { | ||
sKey := string(key) | ||
v := f.ReqHeader.Peek(sKey) | ||
if err := handler(sKey, string(v)); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
// Set adds the given value to request header for key. Key will be lowercased to match | ||
// the metadata implementation. | ||
func (f *FastHTTPHeadersCarrier) Set(key, val string) { | ||
f.ReqHeader.Set(key, val) | ||
} |
96 changes: 96 additions & 0 deletions
96
contrib/internal/fasthttptrace/fasthttpheaderscarrier_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package fasthttptrace | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer" | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"github.com/valyala/fasthttp" | ||
) | ||
|
||
func TestFastHTTPHeadersCarrierSet(t *testing.T) { | ||
assert := assert.New(t) | ||
fcc := &FastHTTPHeadersCarrier{ | ||
ReqHeader: new(fasthttp.RequestHeader), | ||
} | ||
t.Run("key-val", func(t *testing.T) { | ||
// add one item | ||
fcc.Set("k1", "v1") | ||
assert.Len(fcc.ReqHeader.PeekAll("k1"), 1) | ||
assert.Equal("v1", string(fcc.ReqHeader.Peek("k1"))) | ||
}) | ||
t.Run("key-multival", func(t *testing.T) { | ||
// add a second value, ensure the second value overwrites the first | ||
fcc.Set("k1", "v1") | ||
fcc.Set("k1", "v2") | ||
vals := fcc.ReqHeader.PeekAll("k1") | ||
assert.Len(vals, 1) | ||
assert.Equal("v2", string(vals[0])) | ||
}) | ||
t.Run("multi-key", func(t *testing.T) { | ||
// // add a second key | ||
fcc.Set("k1", "v1") | ||
fcc.Set("k2", "v21") | ||
assert.Len(fcc.ReqHeader.PeekAll("k2"), 1) | ||
assert.Equal("v21", string(fcc.ReqHeader.Peek("k2"))) | ||
}) | ||
t.Run("case insensitive", func(t *testing.T) { | ||
// new key | ||
fcc.Set("K3", "v31") | ||
assert.Equal("v31", string(fcc.ReqHeader.Peek("k3"))) | ||
assert.Equal("v31", string(fcc.ReqHeader.Peek("K3"))) | ||
// access existing, lowercase key with uppercase input | ||
fcc.Set("K3", "v32") | ||
vals := fcc.ReqHeader.PeekAll("k3") | ||
assert.Equal("v32", string(vals[0])) | ||
}) | ||
} | ||
|
||
func TestFastHTTPHeadersCarrierForeachKey(t *testing.T) { | ||
assert := assert.New(t) | ||
h := new(fasthttp.RequestHeader) | ||
headers := map[string][]string{ | ||
"K1": {"v1"}, | ||
"K2": {"v2", "v22"}, | ||
} | ||
assert.Len(headers, 2) | ||
for k, vs := range headers { | ||
for _, v := range vs { | ||
h.Add(k, v) | ||
} | ||
} | ||
fcc := &FastHTTPHeadersCarrier{ | ||
ReqHeader: h, | ||
} | ||
err := fcc.ForeachKey(func(k, v string) error { | ||
delete(headers, k) | ||
return nil | ||
}) | ||
assert.NoError(err) | ||
assert.Len(headers, 0) | ||
} | ||
|
||
func TestInjectExtract(t *testing.T) { | ||
assert := assert.New(t) | ||
mt := mocktracer.Start() | ||
defer mt.Stop() | ||
pspan, _ := tracer.StartSpanFromContext(context.Background(), "test") | ||
fcc := &FastHTTPHeadersCarrier{ | ||
ReqHeader: &fasthttp.RequestHeader{}, | ||
} | ||
err := tracer.Inject(pspan.Context(), fcc) | ||
require.NoError(t, err) | ||
sctx, err := tracer.Extract(fcc) | ||
require.NoError(t, err) | ||
assert.Equal(sctx.TraceID(), pspan.Context().TraceID()) | ||
assert.Equal(sctx.SpanID(), pspan.Context().SpanID()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package fasthttptrace | ||
|
||
import ( | ||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" | ||
"gopkg.in/DataDog/dd-trace-go.v1/internal" | ||
|
||
"github.com/valyala/fasthttp" | ||
) | ||
|
||
// StartSpanFromContext returns a new span with the given operation name and options. | ||
// If a span is found in the `fctx`, it will be used as the parent of the resulting span. | ||
// The resulting span is then set on the given `fctx`. | ||
// This function is similar to tracer.StartSpanFromContext, but it modifies the given fasthttp context directly. | ||
// If the ChildOf option is passed, it will only be used as the parent if there is no span found in `fctx`. | ||
func StartSpanFromContext(fctx *fasthttp.RequestCtx, operationName string, opts ...tracer.StartSpanOption) tracer.Span { | ||
s, _ := tracer.StartSpanFromContext(fctx, operationName, opts...) | ||
fctx.SetUserValue(internal.ActiveSpanKey, s) | ||
return s | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package fasthttptrace | ||
|
||
import ( | ||
"testing" | ||
|
||
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer" | ||
"gopkg.in/DataDog/dd-trace-go.v1/internal" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/valyala/fasthttp" | ||
) | ||
|
||
func TestStartSpanFromContext(t *testing.T) { | ||
assert := assert.New(t) | ||
mt := mocktracer.Start() | ||
defer mt.Stop() | ||
fctx := &fasthttp.RequestCtx{} | ||
activeSpan := StartSpanFromContext(fctx, "myOp") | ||
keySpan := fctx.UserValue(internal.ActiveSpanKey) | ||
assert.Equal(activeSpan, keySpan) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016 Datadog, Inc. | ||
|
||
package internal | ||
|
||
type contextKey struct{} | ||
|
||
// ActiveSpanKey is used to set tracer context on a context.Context objects with a unique key | ||
var ActiveSpanKey = contextKey{} |