Skip to main content
OdigosLambdaInstrumentation instruments AWS Lambda functions defined in your CDK app.
Read Odigos AWS CDK first — it covers installing the package and how Odigos recognizes an instrumented workload — then Destinations for the shared destination options. This page covers only what’s specific to Lambda.

Basic usage

Typically you define one OdigosLambdaInstrumentation per CDK stack and pass it every function you want instrumented. One construct does everything for every function you list: attaches the right OpenTelemetry layer for that function’s language and CPU architecture, sets the variable that loads it, configures where telemetry goes, and writes the ODIGOS_IAC marker. serviceName (and other construct-level options) apply to every function on that construct. If each function needs its own serviceName, define one construct per function instead of listing them together. The same applies whenever any other setting must differ. To instrument every function in the stack without listing them, use the Aspect instead. Languages supported: Python, Node.js, Java, Ruby. Other runtimes — Go, .NET, and custom runtimes — have no OpenTelemetry Lambda layer, so they can’t be instrumented this way.
You can also call instrument(fn) or instrumentAll([fn1, fn2]) on the construct after creating it, instead of passing functions up front.

How telemetry leaves the function

This is worth understanding because it explains several of the options below. Your function’s OpenTelemetry SDK does not send data to your destination directly. It sends it to a small collector that ships inside the Odigos layer and runs in the same Lambda sandbox, reachable on localhost. That collector then forwards the data to your real destination — after your handler has already returned its response to the caller. That extra hop is the entire point: if your destination is slow or briefly unreachable, the delay lands on billed duration rather than on the response your user is waiting for. (A decouple processor inside the collector keeps the sandbox alive just long enough to finish sending before Lambda freezes it, so a low-traffic function doesn’t lose its telemetry.)
This is why the construct never sets OTEL_EXPORTER_OTLP_ENDPOINT. If you set it yourself, you point the SDK straight at your destination and put the network call back on the critical path of every single invocation — undoing the whole design.

Where the layer comes from

OdigosLayerSource
default:"ODIGOS_PUBLIC"
Which copy of the OpenTelemetry layer your functions attach.
Both options install byte-for-byte identical instrumentation. IN_ACCOUNT is the SAR preload path for CDK: the construct nests an AWS Serverless Application Repository application into your stack, which publishes an AWS::Lambda::LayerVersion owned by your account and wires its ARN onto the function. You do not deploy SAR by hand when using this option. Use IN_ACCOUNT if your organization’s policy forbids attaching a Lambda layer owned by an outside AWS account. It needs the principal running cdk deploy to hold serverlessrepo:CreateCloudFormationTemplate and serverlessrepo:GetApplication. For the same preload outside CDK (Console, CloudFormation/SAM) — or to see the Application IDs and SemanticVersion the construct pins — see Preload the Lambda layer.
lambda.ILayerVersion
Escape hatch: attach a specific layer you already own, and skip layerSource entirely — neither ODIGOS_PUBLIC nor IN_ACCOUNT is consulted when this is set.Pass any CDK ILayerVersion — typically LayerVersion.fromLayerVersionArn(...) pointing at a layer you mirrored into your account, or a LayerVersion construct you already defined. There is no separate allow-list: the construct attaches whatever you pass.The layer must be the Odigos OpenTelemetry layer (same bytes / script layout as the public or SAR layer). Environment variables assume paths inside that layout; a different layer will attach but fail to instrument at runtime.
One layerVersion is used for every function on this construct, so those functions must share a language and architecture that match that layer. Prefer layerSource when you need the construct to pick the right layer per function.

Normal functions vs. web-server functions

OdigosInstrumentationMode
default:"HANDLER"
HANDLER is for an ordinary Lambda function — one that exports a handler and gets invoked per event.WEB_SERVER is for a function that runs an actual web server behind the AWS Lambda Web Adapter.
The difference matters because both Odigos and the Web Adapter want to use the same Lambda setting (AWS_LAMBDA_EXEC_WRAPPER) to hook into startup. In WEB_SERVER mode, Odigos leaves that setting to the adapter and loads instrumentation a different way instead.
Using HANDLER on a web-adapter function overwrites the adapter’s setting and the function stops serving traffic. There’s deliberately no auto-detection: spotting the adapter would mean inspecting the function’s other layers, which CDK often can’t resolve until deploy time — and a detector that was right most of the time would silently break exactly the functions it got wrong. So you state it.
string
In WEB_SERVER mode, Odigos loads instrumentation through your language’s own startup variable — NODE_OPTIONS, JAVA_TOOL_OPTIONS, or PYTHONPATH. If your function already needs a value in that variable, pass it here and Odigos adds to it instead of replacing it.
CDK can’t read back an environment variable your app set elsewhere, so this can’t be detected automatically. Omit it and the variable is set to only the Odigos value — for NODE_OPTIONS, that can silently drop a flag your application needs to start.
Ruby functions are not supported in WEB_SERVER mode because a verified web-server loader is currently unavailable.

Java functions: pick the matching handler type

The Java layer ships four different wrapper scripts, one per Lambda handler interface. This is a correctness setting, not a level-of-detail setting.
OdigosJavaHandlerDistro
default:"OTEL_HANDLER"
The default installs a RequestHandler implementation. A function that actually implements RequestStreamHandler has a completely different method signature, so the default breaks the invocation — it doesn’t merely produce thinner traces.

Instrumenting every function in a stack

This visits every Lambda function in the stack.
boolean
default:"false (true on the aspect)"
What to do when a function’s runtime has no OpenTelemetry layer (Go, .NET, custom runtimes).The aspect defaults to true: skip it with a build warning rather than failing. The single-function construct defaults to false, because naming one specific Go function and asking for it to be instrumented is a mistake worth stopping the build over.

Naming your service

OTEL_SERVICE_NAME is what your function shows up as in your observability tool.
string
Left unset, this becomes the function’s real name when your stack sets one explicitly, and the CDK construct ID otherwise.
That fallback exists for a structural reason: a function name that CloudFormation generates for you is a reference to the function itself, and a function referring to its own generated name inside its own configuration is a circular dependency that CloudFormation refuses to deploy.
Odigos compares this against the function’s real AWS name. If your function’s name is auto-generated, set serviceName explicitly — otherwise Odigos reports it as drifted. Note that serviceName applies to every function in a single construct, so use one construct per function when you need different names.

Other things worth knowing

A container-image function (DockerImageFunction) can’t carry Lambda layers at all. The construct also needs a function your own stack owns — one imported with Function.fromFunctionArn can’t be modified by CDK.
AWS allows a maximum of 5 layers per function. Also don’t attach the Odigos layer through more than one route at once — two versions of the same layer is reported as a conflict.

API reference

CDK overview

Install, constructs, and how Odigos recognizes instrumented workloads.

Destinations

Endpoint formats, credentials, and which signals to enable.

Preload the layer

Put the layer in your own account for IN_ACCOUNT.