Skip to content

Commit

Permalink
lambda: use _X_AMZN_TRACE_ID trace context as a Link not parent
Browse files Browse the repository at this point in the history
  • Loading branch information
tsloughter committed Feb 24, 2023
1 parent d9b1211 commit 4746424
Show file tree
Hide file tree
Showing 8 changed files with 479 additions and 46 deletions.
16 changes: 16 additions & 0 deletions instrumentation/github.com/aws/aws-lambda-go/otellambda/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,30 @@ go 1.18
require (
github.com/aws/aws-lambda-go v1.37.0
github.com/stretchr/testify v1.8.1
go.opentelemetry.io/contrib/propagators/aws v1.14.0
go.opentelemetry.io/otel v1.13.0
go.opentelemetry.io/otel/trace v1.13.0
)

require (
github.com/cenkalti/backoff/v4 v4.2.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
go.opentelemetry.io/contrib/detectors/aws/lambda v0.39.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.13.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.13.0 // indirect
go.opentelemetry.io/otel/sdk v1.13.0 // indirect
go.opentelemetry.io/proto/otlp v0.19.0 // indirect
golang.org/x/net v0.5.0 // indirect
golang.org/x/sys v0.4.0 // indirect
golang.org/x/text v0.6.0 // indirect
google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
google.golang.org/grpc v1.52.3 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
427 changes: 427 additions & 0 deletions instrumentation/github.com/aws/aws-lambda-go/otellambda/go.sum

Large diffs are not rendered by default.

24 changes: 22 additions & 2 deletions instrumentation/github.com/aws/aws-lambda-go/otellambda/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import (
"strings"

"github.com/aws/aws-lambda-go/lambdacontext"

"go.opentelemetry.io/otel"
"go.opentelemetry.io/contrib/propagators/aws/xray"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/attribute"
semconv "go.opentelemetry.io/otel/semconv/v1.17.0"
"go.opentelemetry.io/otel/trace"
Expand Down Expand Up @@ -56,6 +57,23 @@ func newInstrumentor(opts ...Option) instrumentor {
resAttrs: []attribute.KeyValue{}}
}

func xrayEnvToLinks() []trace.Link {
xrayTraceID := os.Getenv("_X_AMZN_TRACE_ID")

if xrayTraceID != "" {
carrier := propagation.HeaderCarrier{"X-Amzn-Trace-Id": []string{xrayTraceID}}

xray := xray.Propagator{}
ctx := xray.Extract(context.Background(), carrier)

link := trace.LinkFromContext(ctx, attribute.String("source", "x-ray-env"))

return []trace.Link{link}
}

return []trace.Link{}
}

// Logic to start OTel Tracing.
func (i *instrumentor) tracingBegin(ctx context.Context, eventJSON []byte) (context.Context, trace.Span) {
// Add trace id to context
Expand Down Expand Up @@ -89,7 +107,9 @@ func (i *instrumentor) tracingBegin(ctx context.Context, eventJSON []byte) (cont
attributes = append(attributes, i.resAttrs...)
}

ctx, span = i.tracer.Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attributes...))
links := xrayEnvToLinks()

ctx, span = i.tracer.Start(ctx, spanName, trace.WithSpanKind(trace.SpanKindServer), trace.WithAttributes(attributes...), trace.WithLinks(links...))

return ctx, span
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ require (
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect
golang.org/x/sys v0.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ go.opentelemetry.io/otel/sdk v1.13.0 h1:BHib5g8MvdqS65yo2vV1s6Le42Hm6rrw08qU6yz5
go.opentelemetry.io/otel/sdk v1.13.0/go.mod h1:YLKPx5+6Vx/o1TCUYYs+bpymtkmazOMT6zoRrC7AQ7I=
go.opentelemetry.io/otel/trace v1.13.0 h1:CBgRZ6ntv+Amuj1jDsMhZtlAPT6gbyIRdaIzFhfBSdY=
go.opentelemetry.io/otel/trace v1.13.0/go.mod h1:muCvmmO9KKpvuXSf3KKAXXB2ygNYHQ+ZfI5X08d3tds=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc=
golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ var (
attribute.String("faas.id", "arn:partition:service:region:account-id:resource-type:resource-id"),
attribute.String("cloud.account.id", "account-id")},
Events: nil,
Links: nil,
Links: []sdktrace.Link{sdktrace.Link{SpanContext: trace.SpanContextFromContext(mockContext), Attributes: []attribute.KeyValue{attribute.String("source", "x-ray-env")}}},
Status: sdktrace.Status{},
DroppedAttributes: 0,
DroppedEvents: 0,
Expand Down Expand Up @@ -330,7 +330,7 @@ var (
attribute.String("faas.id", "arn:partition:service:region:account-id:resource-type:resource-id"),
attribute.String("cloud.account.id", "account-id")},
Events: nil,
Links: nil,
Links: []sdktrace.Link{sdktrace.Link{SpanContext: trace.SpanContextFromContext(mockContext), Attributes: []attribute.KeyValue{attribute.String("source", "x-ray-env")}}},
Status: sdktrace.Status{},
DroppedAttributes: 0,
DroppedEvents: 0,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ package xrayconfig // import "go.opentelemetry.io/contrib/instrumentation/github

import (
"context"
"os"

lambdadetector "go.opentelemetry.io/contrib/detectors/aws/lambda"
"go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda"
Expand All @@ -26,9 +25,10 @@ import (
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)

// TODO: Currently does nothing but should support pulling the propagated
// trace context from attributes depending on the type of Lambda event
func xrayEventToCarrier([]byte) propagation.TextMapCarrier {
xrayTraceID := os.Getenv("_X_AMZN_TRACE_ID")
return propagation.HeaderCarrier{"X-Amzn-Trace-Id": []string{xrayTraceID}}
return propagation.HeaderCarrier{}
}

// NewTracerProvider returns a TracerProvider configured with an exporter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,41 +28,11 @@ import (
"go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda"
"go.opentelemetry.io/contrib/propagators/aws/xray"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
v1common "go.opentelemetry.io/proto/otlp/common/v1"
v1resource "go.opentelemetry.io/proto/otlp/resource/v1"
v1trace "go.opentelemetry.io/proto/otlp/trace/v1"
)

func TestEventToCarrier(t *testing.T) {
os.Clearenv()

_ = os.Setenv("_X_AMZN_TRACE_ID", "traceID")
carrier := xrayEventToCarrier([]byte{})

assert.Equal(t, "traceID", carrier.Get("X-Amzn-Trace-Id"))
}

func TestEventToCarrierWithPropagator(t *testing.T) {
os.Clearenv()

_ = os.Setenv("_X_AMZN_TRACE_ID", "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1")
carrier := xrayEventToCarrier([]byte{})
ctx := xray.Propagator{}.Extract(context.Background(), carrier)

expectedTraceID, _ := trace.TraceIDFromHex("5759e988bd862e3fe1be46a994272793")
expectedSpanID, _ := trace.SpanIDFromHex("53995c3f42cd8ad8")
expectedCtx := trace.ContextWithRemoteSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{
TraceID: expectedTraceID,
SpanID: expectedSpanID,
TraceFlags: trace.FlagsSampled,
TraceState: trace.TraceState{},
Remote: true,
}))

assert.Equal(t, expectedCtx, ctx)
}

func setEnvVars() {
_ = os.Setenv("AWS_LAMBDA_FUNCTION_NAME", "testFunction")
_ = os.Setenv("AWS_REGION", "us-texas-1")
Expand All @@ -88,16 +58,16 @@ var (
}
mockContext = xray.Propagator{}.Extract(lambdacontext.NewContext(context.Background(), &mockLambdaContext),
propagation.HeaderCarrier{
"X-Amzn-Trace-Id": []string{"Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"},
"X-Amzn-Trace-Id": []string{"Root=1-6769e988-bd862e3fe1be46a994272793;Parent=63996c3f42cd8ad8;Sampled=1"},
})

expectedSpans = v1trace.ScopeSpans{
Scope: &v1common.InstrumentationScope{Name: "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda", Version: otellambda.SemVersion()},
Spans: []*v1trace.Span{{
TraceId: []byte{0x57, 0x59, 0xe9, 0x88, 0xbd, 0x86, 0x2e, 0x3f, 0xe1, 0xbe, 0x46, 0xa9, 0x94, 0x27, 0x27, 0x93},
TraceId: []byte{0x67, 0x69, 0xe9, 0x88, 0xbd, 0x86, 0x2e, 0x3f, 0xe1, 0xbe, 0x46, 0xa9, 0x94, 0x27, 0x27, 0x93},
SpanId: nil,
TraceState: "",
ParentSpanId: []byte{0x53, 0x99, 0x5c, 0x3f, 0x42, 0xcd, 0x8a, 0xd8},
ParentSpanId: []byte{0x63, 0x99, 0x6c, 0x3f, 0x42, 0xcd, 0x8a, 0xd8},
Name: "testFunction",
Kind: v1trace.Span_SPAN_KIND_SERVER,
StartTimeUnixNano: 0,
Expand All @@ -108,7 +78,7 @@ var (
DroppedAttributesCount: 0,
Events: nil,
DroppedEventsCount: 0,
Links: nil,
Links: []*v1trace.Span_Link{{TraceId: []byte{0x57, 0x59, 0xe9, 0x88, 0xbd, 0x86, 0x2e, 0x3f, 0xe1, 0xbe, 0x46, 0xa9, 0x94, 0x27, 0x27, 0x93}, SpanId: []byte{0x53, 0x99, 0x5c, 0x3f, 0x42, 0xcd, 0x8a, 0xd8}, Attributes: []*v1common.KeyValue{{Key: "source", Value: &v1common.AnyValue{Value: &v1common.AnyValue_StringValue{StringValue: "x-ray-env"}}}}}},
DroppedLinksCount: 0,
Status: &v1trace.Status{Code: v1trace.Status_STATUS_CODE_UNSET},
}},
Expand Down Expand Up @@ -145,7 +115,7 @@ func assertResourceEquals(t *testing.T, expected *v1resource.Resource, actual *v

// ignore timestamps and SpanID since time is obviously variable,
// and SpanID is randomized when using xray IDGenerator.
func assertSpanEqualsIgnoreTimeAndSpanID(t *testing.T, expected *v1trace.ResourceSpans, actual *v1trace.ResourceSpans) {
func assertSpanEqualsIgnoreTimeAndTraceIDAndSpanID(t *testing.T, expected *v1trace.ResourceSpans, actual *v1trace.ResourceSpans) {
assert.Equal(t, expected.ScopeSpans[0].Scope, actual.ScopeSpans[0].Scope)

actualSpan := actual.ScopeSpans[0].Spans[0]
Expand Down Expand Up @@ -189,5 +159,5 @@ func TestWrapEndToEnd(t *testing.T) {

resSpans := mockCollector.getResourceSpans()
assert.Len(t, resSpans, 1)
assertSpanEqualsIgnoreTimeAndSpanID(t, &expectedResourceSpans, resSpans[0])
assertSpanEqualsIgnoreTimeAndTraceIDAndSpanID(t, &expectedResourceSpans, resSpans[0])
}

0 comments on commit 4746424

Please sign in to comment.