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 Lambdaarrow-up-right 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:

  1. Instrumentation Layer (language-specific) - Automatically instruments your code, captures context from upstream callers, creates spans, and instruments the AWS SDK

  2. 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 Extensionarrow-up-right, receiving telemetry from your instrumented function and forwarding it to groundcover. It also captures your function's stdout and stderr as logs.

circle-info

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 stdout and stderr from your Lambda function

circle-exclamation

Creating a Configuration Layer

Package the collector configuration as a Lambda layer for easy reuse:

  1. Create a zip file with otel-collector-config.yaml at the root (not inside a directory)

  2. Click Create layer

  3. Enter a name (e.g., otel-collector-config)

  4. Upload your zip file

  5. Select the compatible architectures and runtimes

  6. Click Create

circle-info

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:

  1. OpenTelemetry Instrumentation Layer - Auto-instruments your code (language-specific)

  2. OpenTelemetry Collector Layer - Processes and exports telemetry

  3. 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 releasesarrow-up-right.

circle-exclamation

Instrumentation Layers

Runtime
Layer ARN
Wrapper Path

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

Architecture
Layer ARN

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

circle-exclamation

Adding Layers via AWS Console

  1. Select your function

  2. In the Layers section, click Add a layer

  3. Select Specify an ARN

  4. Paste the appropriate ARN

  5. Click Verify, then Add

  6. 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:

Variable
Value
Description

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

circle-info

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

  1. Deploy your Lambda function with the layers and configuration

  2. Invoke the function (via AWS Console, CLI, or trigger)

  3. Check groundcover for incoming telemetry data

circle-info

Allow 1-2 minutes for data to appear in groundcover after the first invocation.

Complete Example

Collector Config (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

Header
Description
Example

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:

circle-info

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 APIarrow-up-right 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

  1. Check config path: Verify OPENTELEMETRY_COLLECTOR_CONFIG_URI points to the correct location

  2. Verify credentials: Confirm your ingestion key is valid

  3. Check Lambda logs: Look for collector errors in CloudWatch Logs

  4. Enable debug logging: Set OPENTELEMETRY_EXTENSION_LOG_LEVEL=debug

  5. Network 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 apikey header format in your collector config

Architecture Mismatch

If you see errors about missing libraries:

  • Ensure the collector layer architecture (amd64 vs arm64) matches your function's architecture

Additional Resources

Last updated