Monitor Lambdas using OTEL Layers
This guide explains how to instrument your AWS Lambda functions using OpenTelemetry and ship traces, metrics, and logs to groundcover.
Overview
AWS Lambda's serverless architecture presents unique observability challenges:
Ephemeral execution: Functions may exist only for a single request, requiring telemetry to be exported quickly
Cold starts: Each new execution environment introduces latency that should be tracked
Distributed nature: Serverless architectures span multiple services, making trace correlation essential
The OpenTelemetry Lambda project provides Lambda layers that solve these challenges with automatic instrumentation and an embedded collector.
How It Works
The setup uses two Lambda layers working together:
Instrumentation Layer (language-specific) - Automatically instruments your code, captures context from upstream callers, creates spans, and instruments the AWS SDK
Collector Layer - Embeds a stripped-down OpenTelemetry Collector as a Lambda extension that processes and exports telemetry data
The collector runs as an AWS Lambda Extension, receiving telemetry from your instrumented function and forwarding it to groundcover. It also captures your function's stdout and stderr as logs.
OpenTelemetry Lambda supports automatic instrumentation for Python, Node.js, Java, and Ruby. For .NET and Go, manual instrumentation is required.
Prerequisites
Before you begin, ensure you have:
An AWS account with permissions to create/modify Lambda functions and layers
A groundcover account with a BYOC endpoint
A groundcover Ingestion Key
Knowledge of your Lambda function's runtime and architecture (x86_64 or arm64)
Step 1: Create the Collector Configuration
The OpenTelemetry Collector requires a configuration file that defines how telemetry is received and exported.
Configuration File
Create a file named otel-collector-config.yaml:
The telemetryapi receiver captures Lambda platform telemetry including:
Cold start spans - Records function initialization time (
platform.initRuntimeDone)Function logs - Captures
stdoutandstderrfrom your Lambda function
Replace the following placeholders:
{BYOC_ENDPOINT}- Your groundcover BYOC endpoint{INGESTION_KEY}- Your ingestion key{SERVICE_NAME}- Your Lambda function or service name{ENVIRONMENT}- Your environment (e.g.,production,staging)
Find your endpoint and ingestion key in Settings > Ingestion Keys.
Creating a Configuration Layer
Package the collector configuration as a Lambda layer for easy reuse:
Create a zip file with
otel-collector-config.yamlat the root (not inside a directory)Open the Lambda Layers console
Click Create layer
Enter a name (e.g.,
otel-collector-config)Upload your zip file
Select the compatible architectures and runtimes
Click Create
Alternatively, you can include the config file directly in your function bundle at the root level, or store it in S3 and reference via URI (ensure your Lambda's IAM role has s3:GetObject permission).
Step 2: Add the Lambda Layers
Your Lambda function needs three layers:
OpenTelemetry Instrumentation Layer - Auto-instruments your code (language-specific)
OpenTelemetry Collector Layer - Processes and exports telemetry
Configuration Layer - Contains your collector config (from Step 1)
Layer ARNs
Replace <region> with your AWS region and <version> with the latest version from the OpenTelemetry Lambda releases.
Layer versions are updated frequently. Always check the releases page for the latest versions before deploying.
Instrumentation Layers
Node.js
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-nodejs-<version>:1
/opt/otel-handler
Python
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-python-<version>:1
/opt/otel-instrument
Java Agent
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-javaagent-<version>:1
/opt/otel-handler
Java Wrapper
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-javawrapper-<version>:1
/opt/otel-handler
Ruby
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-ruby-<version>:1
/opt/otel-handler
Collector Layer
x86_64 (amd64)
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-collector-amd64-<version>:1
arm64
arn:aws:lambda:<region>:184161586896:layer:opentelemetry-collector-arm64-<version>:1
Make sure the collector layer architecture matches your Lambda function's architecture.
Adding Layers via AWS Console
Open the Lambda Console
Select your function
In the Layers section, click Add a layer
Select Specify an ARN
Paste the appropriate ARN
Click Verify, then Add
Repeat for all three layers (instrumentation, collector, configuration)
Adding Layers via Terraform
Adding Layers via AWS CDK
Step 3: Configure Environment Variables
Set the following environment variables on your Lambda function:
AWS_LAMBDA_EXEC_WRAPPER
See wrapper path in the table above
Enables automatic instrumentation
OPENTELEMETRY_COLLECTOR_CONFIG_URI
/opt/otel-collector-config.yaml
Path to collector config
The collector config can also be loaded from your function bundle (/var/task/otel-collector-config.yaml) or from S3 (s3://<bucket>.s3.<region>.amazonaws.com/config.yaml).
Step 4: Deploy and Test
Deploy your Lambda function with the layers and configuration
Invoke the function (via AWS Console, CLI, or trigger)
Check groundcover for incoming telemetry data
Allow 1-2 minutes for data to appear in groundcover after the first invocation.
Complete Example
Collector Config (otel-collector-config.yaml)
otel-collector-config.yaml)Terraform Configuration
Enriching Telemetry Data
groundcover supports enriching ingested data with additional context using HTTP headers in the collector configuration.
Add enrichment headers in the exporter configuration:
Available Enrichment Headers
x-groundcover-service-name
Service/workload name
payment-processor
x-groundcover-env-name
Environment name
production, staging
x-groundcover-env-type
Environment type
lambda, vm
x-groundcover-source
Data source identifier
otel-lambda
For more details, see Enriching 3rd Party Data.
Sampling Configuration
Always Sample (Development)
Ratio-Based Sampling (Production)
Sample 10% of traces to reduce costs:
For high-traffic Lambda functions, ratio-based sampling reduces costs while maintaining visibility.
Collecting Logs
The telemetryapi receiver automatically captures your Lambda function's stdout and stderr output via the Lambda Telemetry API and forwards them as logs to groundcover.
To correlate logs with traces, use a logger that outputs trace context. For Python:
Lambda Platform Metrics
The OpenTelemetry layers capture application-level metrics. For Lambda platform metrics (invocation count, duration, throttles, etc.), use the CloudWatch Metrics integration to ingest the AWS/Lambda namespace.
Troubleshooting
Data Not Appearing in groundcover
Check config path: Verify
OPENTELEMETRY_COLLECTOR_CONFIG_URIpoints to the correct locationVerify credentials: Confirm your ingestion key is valid
Check Lambda logs: Look for collector errors in CloudWatch Logs
Enable debug logging: Set
OPENTELEMETRY_EXTENSION_LOG_LEVEL=debugNetwork connectivity: Ensure Lambda can reach the groundcover endpoint (port 443)
403 Forbidden Errors
Verify your ingestion key is valid and not revoked
Ensure you're using a Third Party type ingestion key
Check the
apikeyheader format in your collector config
Architecture Mismatch
If you see errors about missing libraries:
Ensure the collector layer architecture (
amd64vsarm64) matches your function's architecture
Additional Resources
Ingest CloudWatch Metrics - For Lambda platform metrics
Last updated
