Instrumenting AWS Lambda

Status: Experimental

This document defines how to apply semantic conventions when instrumenting an AWS Lambda request handler. AWS Lambda largely follows the conventions for FaaS while HTTP conventions are also applicable when handlers are for HTTP requests.

There are a variety of triggers for Lambda functions, and this document will grow over time to cover all the use cases.

All triggers

For all events, a span with kind SERVER MUST be created corresponding to the function invocation unless stated otherwise below. Unless stated otherwise below, the name of the span MUST be set to the function name from the Lambda Context.

The following attributes SHOULD be set:

  • faas.execution - The value of the AWS Request ID, which is always available through an accessor on the Lambda Context.

  • faas.id - The value of the invocation ARN for the function, which is always available through an accessor on the Lambda Context, modified as follows: Discard all parts beyond the seventh (when split on :; the seventh part is the function name) and append the faas.version, separated by a colon.

    Note that this is set as span attribute instead of resource attribute due to technical limitations (account ID is not available at startup).

  • cloud.account.id - In some languages, this is available as an accessor on the Lambda Context. Otherwise, it can be parsed from the value of faas.id as the fifth item when splitting on :

Also consider setting other attributes of the faas resource and trace conventions and the cloud resource conventions. The following AWS Lambda-specific attribute MAY also be set:

AttributeTypeDescriptionExamplesRequirement Level
aws.lambda.invoked_arnstringThe full invoked ARN as provided on the Context passed to the function (Lambda-Runtime-Invoked-Function-Arn header on the /runtime/invocation/next applicable). [1]arn:aws:lambda:us-east-1:123456:function:myfunction:myaliasRecommended

[1]: This may be different from faas.id if an alias is involved.

Determining the parent of a span

The parent of the span MUST be determined by considering both the environment and any headers or attributes available from the event.

If the _X_AMZN_TRACE_ID environment variable is set, instrumentations SHOULD first try to parse an OpenTelemetry Context out of it using the AWS X-Ray Propagator. If the resulting Context is valid and sampled, then this Context is the parent of the function span. We check if it is valid because sometimes the _X_AMZN_TRACE_ID environment variable contains an incomplete trace context which indicates X-Ray isn’t enabled. The environment variable will be set and the Context will be valid and sampled only if AWS X-Ray has been enabled for the Lambda function. A user can disable AWS X-Ray for the function if X-Ray propagation is not desired.

Otherwise, when X-Ray propagation fails, the user’s configured propagators SHOULD be applied to the HTTP headers of the request to extract a Context. For example, API Gateway proxy requests can be configured to send HTTP headers to a Lambda function using a body mapping template.

API Gateway

API Gateway allows a user to trigger a Lambda function in response to HTTP requests. It can be configured to be a pure proxy, where the information about the original HTTP request is passed to the Lambda function, or as a configuration for a REST API, in which case only a deserialized body payload is available. In the case the API gateway is configured to proxy to the Lambda function, the instrumented request handler will have access to all the information about the HTTP request in the form of an API Gateway Proxy Request Event.

The Lambda span name and the http.route span attribute SHOULD be set to the resource property from the proxy request event, which corresponds to the user configured HTTP route instead of the function name.

faas.trigger MUST be set to http. HTTP attributes SHOULD be set based on the available information in the Lambda event initiated by the proxy request. http.scheme is available as the x-forwarded-proto header in the Lambda event. Refer to the input event format for more details.

SQS

Amazon Simple Queue Service (SQS) is a message queue that triggers a Lambda function with a batch of messages. So we consider processing both of a batch and of each individual message. The function invocation span MUST correspond to the SQS event, which is the batch of messages. For each message, an additional span SHOULD be created to correspond with the handling of the SQS message. Because handling of a message will be inside user business logic, not the Lambda framework, automatic instrumentation mechanisms without code change will often not be able to instrument the processing of the individual messages. Instrumentation SHOULD provide utilities for creating message processing spans within user code.

The span kind for both types of SQS spans MUST be CONSUMER.

SQS Event

For the SQS event span, if all the messages in the event have the same event source, the name of the span MUST be <event source> process. If there are multiple sources in the batch, the name MUST be multiple_sources process. The parent MUST be the SERVER span corresponding to the function invocation.

For every message in the event, the message system attributes (not message attributes, which are provided by the user) SHOULD be checked for the key AWSTraceHeader. If it is present, an OpenTelemetry Context SHOULD be parsed from the value of the attribute using the AWS X-Ray Propagator and added as a link to the span. This means the span may have as many links as messages in the batch.

SQS Message

For the SQS message span, the name MUST be <event source> process. The parent MUST be the CONSUMER span corresponding to the SQS event. The message system attributes (not message attributes, which are provided by the user) SHOULD be checked for the key AWSTraceHeader. If it is present, an OpenTelemetry Context SHOULD be parsed from the value of the attribute using the AWS X-Ray Propagator and added as a link to the span.

Other Messaging attributes SHOULD be set based on the available information in the SQS message event.

Note that AWSTraceHeader is the only supported mechanism for propagating Context in instrumentation for SQS to prevent conflicts with other sources. Notably, message attributes (user-provided, not system) are not supported - the linked contexts are always expected to have been sent as HTTP headers of the SQS.SendMessage request that the message originated from. This is a function of AWS SDK instrumentation, not Lambda instrumentation.

Using the AWSTraceHeader ensures that propagation will work across AWS services that may be integrated to Lambda via SQS, for example a flow that goes through S3 -> SNS -> SQS -> Lambda. AWSTraceHeader is only a means of propagating context and not tied to any particular observability backend. Notably, using it does not imply using AWS X-Ray - any observability backend will fully function using this propagation mechanism.

Examples

API Gateway Request Proxy (Lambda tracing passive)

Given a process C that sends an HTTP request to an API Gateway endpoint with path /pets/{petId} configured for a Lambda function F:

Process C: | Span Client        |
--
Function F:    | Span Function |
Field or AttributeSpan ClientSpan Function
Span nameHTTP GET/pets/{petId}
ParentSpan Client
SpanKindCLIENTSERVER
StatusOkOk
faas.execution79104EXAMPLEB723
faas.idarn:aws:lambda:us-west-2:123456789012:function:my-function
faas.triggerhttp
cloud.account.id12345678912
net.peer.namefoo.execute-api.us-east-1.amazonaws.com
net.peer.port413
http.methodGETGET
http.user_agentokhttp 3.0okhttp 3.0
http.urlhttps://foo.execute-api.us-east-1.amazonaws.com/pets/10
http.schemehttps
http.hostfoo.execute-api.us-east-1.amazonaws.com
http.target/pets/10
http.route/pets/{petId}
http.status_code200200

API Gateway Request Proxy (Lambda tracing active)

Active tracing in Lambda means an API Gateway span Span APIGW and a Lambda runtime invocation span Span Lambda will be exported to AWS X-Ray by the infrastructure (not instrumentation). All attributes above are the same except that in this case, the parent of APIGW is Span Client and the parent of Span Function is Span Lambda. This means the hierarchy looks like:

Span Client --> Span APIGW --> Span Lambda --> Span Function

SQS (Lambda tracing passive)

Given a process P, that sends two messages to a queue Q on SQS, and a Lambda function F, which processes both of them in one batch (Span ProcBatch) and generates a processing span for each message separately (Spans Proc1 and Proc2).

Process P: | Span Prod1 | Span Prod2 |
--
Function F:                      | Span ProcBatch |
                                        | Span Proc1 |
                                               | Span Proc2 |
Field or AttributeSpan Prod1Span Prod2Span ProcBatchSpan Proc1Span Proc2
Span nameQ sendQ sendQ processQ processQ process
ParentSpan ProcBatchSpan ProcBatch
LinksSpan Prod1Span Prod2
SpanKindPRODUCERPRODUCERCONSUMERCONSUMERCONSUMER
StatusOkOkOkOkOk
messaging.systemAmazonSQSAmazonSQSAmazonSQSAmazonSQSAmazonSQS
messaging.destinationQQQQQ
messaging.destination_kindqueuequeuequeuequeuequeue
messaging.operationprocessprocessprocess
messaging.message_id"a1""a2"

Note that if Span Prod1 and Span Prod2 were sent to different queues, Span ProcBatch would not have messaging.destination set as it would correspond to multiple destinations.

The above requires user code change to create Span Proc1 and Span Proc2. In Java, the user would inherit from TracingSqsMessageHandler instead of Lambda’s standard RequestHandler to enable them. Otherwise these two spans would not exist.

SQS (Lambda tracing active)

Active tracing in Lambda means a Lambda runtime invocation span Span Lambda will be exported to X-Ray by the infrastructure (not instrumentation). In this case, all of the above is the same except Span ProcBatch will have a parent of Span Lambda. This means the hierarchy looks like:

Span Lambda --> Span ProcBatch --> Span Proc1 (links to Span Prod1 and Span Prod2)
                               \-> Span Proc2 (links to Span Prod1 and Span Prod2)

Resource Detector

AWS Lambda resource information is available as environment variables provided by the runtime.

  • cloud.provider MUST be set to aws
  • cloud.region MUST be set to the value of the AWS_REGION environment variable
  • faas.name MUST be set to the value of the AWS_LAMBDA_FUNCTION_NAME environment variable
  • faas.version MUST be set to the value of the AWS_LAMBDA_FUNCTION_VERSION environment variable

Note that faas.id currently cannot be populated to resource because it is not available until function invocation.