AWS Distro for OpenTelemetry

AWS Distro for OpenTelemetry Lambda Support For Go

AWS Distro for OpenTelemetry Lambda Support For Go

There is no ADOT Lambda layer with Application Signals support for Go. To trace a Go function, instrument it with the OpenTelemetry Go SDK and the otellambda instrumentation, and add the ADOT Collector Lambda layer. The function sends spans to the collector, which runs as a Lambda extension and forwards them to the Amazon CloudWatch OTLP traces endpoint.

📋
Application Signals lists Go functions that are set up this way as services in the lambda:default environment, with latency, error, fault, and throttle metrics.



Prerequisites

  • Transaction Search enabled in CloudWatch. The OTLP traces endpoint requires it.
  • A function that uses the provided.al2023 runtime, on x86_64 or arm64. Go functions on the provided.al2 and go1.x runtimes need to move to provided.al2023; for how to build and package the bootstrap binary, see Deploy Go Lambda functions with .zip file archives.
  • An execution role with the CloudWatchLambdaApplicationSignalsExecutionRolePolicy managed policy, which allows xray:PutTraceSegments.



1. Instrument the function

Add the OpenTelemetry Go SDK and the Lambda instrumentation to your module:

go get github.com/aws/aws-lambda-go/lambda \
go.opentelemetry.io/otel \
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda \
go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig \
go.opentelemetry.io/contrib/propagators/aws/xray \
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp

Create the tracer provider in main(), outside the handler, and wrap the handler with otellambda.InstrumentHandler. xrayconfig exports spans over OTLP to the collector extension and flushes them at the end of each invocation. To trace outgoing HTTP requests, use an otelhttp transport and pass the request context:

1package main
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7
8 "github.com/aws/aws-lambda-go/lambda"
9 "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda"
10 "go.opentelemetry.io/contrib/instrumentation/github.com/aws/aws-lambda-go/otellambda/xrayconfig"
11 "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
12 "go.opentelemetry.io/contrib/propagators/aws/xray"
13 "go.opentelemetry.io/otel"
14)
15
16var client = http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
17
18func handler(ctx context.Context) (map[string]int, error) {
19 req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://aws.amazon.com", nil)
20 if err != nil {
21 return nil, err
22 }
23 resp, err := client.Do(req)
24 if err != nil {
25 return nil, err
26 }
27 defer resp.Body.Close()
28 return map[string]int{"statusCode": 200, "http_status": resp.StatusCode}, nil
29}
30
31func main() {
32 ctx := context.Background()
33 tp, err := xrayconfig.NewTracerProvider(ctx)
34 if err != nil {
35 fmt.Printf("error creating tracer provider: %v\n", err)
36 }
37 defer func(ctx context.Context) {
38 if err := tp.Shutdown(ctx); err != nil {
39 fmt.Printf("error shutting down tracer provider: %v\n", err)
40 }
41 }(ctx)
42 otel.SetTracerProvider(tp)
43 otel.SetTextMapPropagator(xray.Propagator{})
44
45 lambda.Start(otellambda.InstrumentHandler(handler, xrayconfig.WithRecommendedOptions(tp)...))
46}

For other libraries, such as the AWS SDK for Go and gRPC, see OpenTelemetry Go instrumentation.




2. Configure the collector

By default, the ADOT Collector Lambda layer exports traces with the awsxray exporter. To send them to the CloudWatch OTLP traces endpoint instead, add this collector.yaml to your deployment package:

1extensions:
2 sigv4auth:
3 region: ${env:AWS_REGION}
4 service: xray
5
6receivers:
7 otlp:
8 protocols:
9 grpc:
10 endpoint: localhost:4317
11 http:
12 endpoint: localhost:4318
13
14exporters:
15 otlp_http:
16 compression: gzip
17 traces_endpoint: https://xray.${env:AWS_REGION}.amazonaws.com/v1/traces
18 auth:
19 authenticator: sigv4auth
20
21service:
22 extensions: [sigv4auth]
23 pipelines:
24 traces:
25 receivers: [otlp]
26 exporters: [otlp_http]

For other collector options, see the OpenTelemetry Lambda Collector configuration.




3. Build and deploy

Build the function as bootstrap and package it with the collector configuration. For arm64, set GOARCH=arm64.

GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -tags lambda.norpc -o bootstrap .
zip function.zip bootstrap collector.yaml

Create the function with the collector layer, the OPENTELEMETRY_COLLECTOR_CONFIG_URI environment variable, and a service name:

1aws lambda create-function --function-name <function-name> \
2 --runtime provided.al2023 --handler bootstrap --architectures x86_64 \
3 --zip-file fileb://function.zip --role <execution-role-arn> \
4 --layers arn:aws:lambda:<region>:901920570463:layer:aws-otel-collector-amd64-ver-0-156-0:4 \
5 --tracing-config Mode=Active \
6 --environment 'Variables={OPENTELEMETRY_COLLECTOR_CONFIG_URI=/var/task/collector.yaml,OTEL_SERVICE_NAME=<service-name>}' \
7 --region <region>

Set OTEL_SERVICE_NAME. Without it, the spans from the Go SDK have no service.name.

Collector layer ARNs

Lambda layers are Regional, so use the layer in the same Region as your function. Use amd64 for x86_64 functions and arm64 for arm64 functions.

Supported RegionsLambda layer ARN formatContents
ap-northeast-1
ap-northeast-2
ap-south-1
ap-southeast-1
ap-southeast-2
ca-central-1
eu-central-1
eu-north-1
eu-west-1
eu-west-2
eu-west-3
sa-east-1
us-east-1
us-east-2
us-west-1
us-west-2
arn:aws:lambda:\<region>:901920570463:layer:aws-otel-collector-\<architecture>-ver-0-156-0:4Contains ADOT Collector v0.49.0



4. View your traces

Invoke the function, and then use Transaction Search in the CloudWatch console to find its spans. Each invocation has a server span from otellambda and a client span for each outgoing request made through otelhttp, along with the segments that Lambda creates when active tracing is on. Spans are stored in the aws/spans log group.

To remove tracing, remove the layer, the OPENTELEMETRY_COLLECTOR_CONFIG_URI variable, and the instrumentation code, and turn off active tracing.