Skip to content

Commit

Permalink
Add support for AWS Lambda entry spans triggered by API GW and ALB
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrey Slotin committed Nov 13, 2020
1 parent 9d7c30c commit ae3920f
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 17 deletions.
56 changes: 39 additions & 17 deletions json_span.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,31 +558,53 @@ func NewGCPPubSubSpanTags(span *spanS) GCPPubSubSpanTags {
return tags
}

// AWSLambdaSpanData is the base span data type for AWS Lambda entry spans
type AWSLambdaSpanData struct {
Snapshot struct {
ARN string `json:"arn"`
Runtime string `json:"runtime"`
Name string `json:"functionName,omitempty"`
Version string `json:"functionVersion,omitempty"`
} `json:"lambda"`
}

// NewAWSLambdaSpanData initializes a new AWSLambdaSpanData from span
func NewAWSLambdaSpanData(span *spanS) AWSLambdaSpanData {
var d AWSLambdaSpanData
d.Snapshot.Runtime = "go"
// AWSLambdaSpanTags contains fields within the `data.lambda` section of an OT span document
type AWSLambdaSpanTags struct {
// ARN is the ARN of invoked AWS Lambda function with the version attached
ARN string `json:"arn"`
// Runtime is an Instana constant for this AWS lambda runtime (always "go")
Runtime string `json:"runtime"`
// Name is the name of invoked function
Name string `json:"functionName,omitempty"`
// Version is either the numeric version or $LATEST
Version string `json:"functionVersion,omitempty"`
}

// NewAWSLambdaSpanTags extracts AWS Lambda entry span tags from a tracer span
func NewAWSLambdaSpanTags(span *spanS) AWSLambdaSpanTags {
tags := AWSLambdaSpanTags{Runtime: "go"}

if v, ok := span.Tags["lambda.arn"]; ok {
readStringTag(&d.Snapshot.ARN, v)
readStringTag(&tags.ARN, v)
}

if v, ok := span.Tags["lambda.name"]; ok {
readStringTag(&d.Snapshot.Name, v)
readStringTag(&tags.Name, v)
}

if v, ok := span.Tags["lambda.version"]; ok {
readStringTag(&d.Snapshot.Version, v)
readStringTag(&tags.Version, v)
}

return tags
}

// AWSLambdaSpanData is the base span data type for AWS Lambda entry spans
type AWSLambdaSpanData struct {
Snapshot AWSLambdaSpanTags `json:"lambda"`
HTTP *HTTPSpanTags `json:"http,omitempty"`
}

// NewAWSLambdaSpanData initializes a new AWSLambdaSpanData from span
func NewAWSLambdaSpanData(span *spanS) AWSLambdaSpanData {
d := AWSLambdaSpanData{
Snapshot: NewAWSLambdaSpanTags(span),
}

switch span.Tags["lambda.trigger"] {
case "aws:api.gateway", "aws:application.load.balancer":
tags := NewHTTPSpanTags(span)
d.HTTP = &tags
}

return d
Expand Down
66 changes: 66 additions & 0 deletions json_span_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

instana "github.com/instana/go-sensor"
"github.com/instana/testify/assert"
"github.com/opentracing/opentracing-go"
)

func TestRegisteredSpanType_ExtractData(t *testing.T) {
Expand Down Expand Up @@ -84,3 +85,68 @@ func TestSpanKind_String(t *testing.T) {
})
}
}

func TestNewAWSLambdaSpanData(t *testing.T) {
examples := map[string]struct {
Tags opentracing.Tags
Expected instana.AWSLambdaSpanData
}{
"aws:api.gateway": {
Tags: opentracing.Tags{
"http.protocol": "https",
"http.url": "https://example.com/lambda",
"http.host": "example.com",
"http.method": "GET",
"http.path": "/lambda",
"http.params": "q=test&secret=classified",
"http.header": map[string]string{"x-custom-header-1": "test"},
"http.status": 404,
"http.error": "Not Found",
},
Expected: instana.AWSLambdaSpanData{
Snapshot: instana.AWSLambdaSpanTags{
ARN: "lambda-arn-1",
Runtime: "go",
Name: "test-lambda",
Version: "42",
},
HTTP: &instana.HTTPSpanTags{
URL: "https://example.com/lambda",
Status: 404,
Method: "GET",
Path: "/lambda",
Params: "q=test&secret=classified",
Headers: map[string]string{"x-custom-header-1": "test"},
Host: "example.com",
Protocol: "https",
Error: "Not Found",
},
},
},
}

// ALB tags set is the same as for API Gateway, so we just copy it over
examples["aws:application.load.balancer"] = examples["aws:api.gateway"]

for trigger, example := range examples {
t.Run(trigger, func(t *testing.T) {
recorder := instana.NewTestRecorder()
tracer := instana.NewTracerWithEverything(&instana.Options{}, recorder)

sp := tracer.StartSpan("aws.lambda.entry", opentracing.Tags{
"lambda.arn": "lambda-arn-1",
"lambda.name": "test-lambda",
"lambda.version": "42",
"lambda.trigger": trigger,
}, example.Tags)
sp.Finish()

spans := recorder.GetQueuedSpans()
assert.Equal(t, 1, len(spans))
span := spans[0]

assert.Equal(t, "aws.lambda.entry", span.Name)
assert.Equal(t, example.Expected, span.Data)
})
}
}

0 comments on commit ae3920f

Please sign in to comment.