Terraform and a plain
aws lambda update-function-configuration CLI command are
also available for every language shown here — the Custom access-level policy
preview in the Central UI surfaces all four formats for a discovered function.
This page covers the two most common: CDK and CloudFormation.What actually gets added to your function
However you apply it, self-managed Lambda instrumentation is the same four things:- The OpenTelemetry layer — a prebuilt Lambda layer for your function’s language and architecture.
- An exec wrapper (
AWS_LAMBDA_EXEC_WRAPPER) — tells Lambda to run your handler through the layer’s instrumentation code first. The exact path is different per language. - The bundled collector’s configuration (
OPENTELEMETRY_COLLECTOR_CONFIG_URI) — tells the small OpenTelemetry collector that ships inside the layer where to send your telemetry. It runs in the same Lambda sandbox and forwards data after your handler already returned, so a slow destination costs extra billed time, not extra response latency. - The
ODIGOS_IACmarker — a small JSON value that tells Odigos “this function is instrumented, and here’s the layer version it’s running.” Without it, Odigos has no way to tell the difference between an instrumented function and one you haven’t touched yet — it will keep reporting the function as Not Instrumented / Waiting for you, even if everything else above is already in place.
Using AWS CDK
The easiest option if your functions are already defined in a CDK app. One package covers every supported language — the construct looks at each function’s runtime and figures out the right layer and wrapper on its own.TypeScript and JavaScript only, for now — a Python distribution is built but not
yet published. Python CDK apps should use the
CloudFormation instructions below.
ODIGOS_IAC for every
function you list.
Full CDK reference
Every option in depth — layer sources, instrumenting a whole stack at once, the AWS Lambda Web Adapter,
Java handler interfaces, and the complete API.
Using CloudFormation directly
If you’re not using CDK, merge these properties into your function’sAWS::Lambda::Function resource by
hand. The shape is identical across languages — a layer, a wrapper, a service name, and the collector
configuration — but the wrapper path (and, for the Web Adapter case, the loader variable) is different for
each one. Pick your language below:
- Java
- Python
- Node.js
- Ruby
Java ships three more wrappers for handler interfaces other than the default
RequestHandler: /opt/otel-proxy-handler (API Gateway proxy events),
/opt/otel-sqs-handler (SQS), and /opt/otel-stream-handler
(RequestStreamHandler). Using the default wrapper on a RequestStreamHandler
function breaks the invocation — it’s the wrong interface, not just a
less-detailed trace.AWS_LAMBDA_EXEC_WRAPPER — the adapter already
owns it — and instead append the agent to JAVA_TOOL_OPTIONS. CloudFormation can’t read an existing
environment variable back, so add your current value in by hand:Things to watch out for
Every space in the collector config matters
Every space in the collector config matters
OPENTELEMETRY_COLLECTOR_CONFIG_URI is written in a compact YAML style where a colon must always be
followed by a space. Miss one and the collector doesn’t fail with a helpful parse error — it accepts
the variable, logs the URI it read, and then fails to start with an unrelated-looking
otelcol state is Closed.A few variables must never be set
A few variables must never be set
OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, ODIGOS_OTLP_ENDPOINT, and
ODIGOS_OTLP_INSECURE are all compared against unset — adding any of them is reported as drift,
even if the value looks harmless. OTEL_LOG_LEVEL is the one exception: leave it unset unless debug
telemetry is turned on for this connector, in which case it must be exactly debug.ODIGOS_IAC is not optional
ODIGOS_IAC is not optional
It’s the only signal Odigos has that this function is instrumented at all, and the layer ARN recorded
inside it is what future checks compare against — so a version you deliberately pinned is respected
instead of being flagged as an available upgrade.
Never set ODIGOS_MANAGED by hand
Never set ODIGOS_MANAGED by hand
That variable belongs to the connector alone — it’s how the connector remembers what to roll back to
after it makes a change itself. Setting it yourself claims a rollback that was never actually recorded.
Turning off a signal
Turning off a signal
If your destination doesn’t accept metrics or logs, set
OTEL_METRICS_EXPORTER / OTEL_LOGS_EXPORTER
to "none" and remove that signal’s pipeline from the collector configuration. Leave both untouched
(unset) for a signal your destination does accept.Once
ODIGOS_IAC is set and the layer, wrapper, and collector configuration all
match, Odigos flips the function to Instrumented on its own — usually within
a few minutes, at the next discovery cycle. No action needed on the Odigos side.Next steps
Full CDK reference
Every construct option, in depth.
Preload the layer
Get the layer into your own account first, if your policy requires it.