@odigos/aws-cdk 0.0.12 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.jsii CHANGED
@@ -3826,7 +3826,7 @@
3826
3826
  },
3827
3827
  "name": "@odigos/aws-cdk",
3828
3828
  "readme": {
3829
- "markdown": "# Odigos CDK constructs for AWS Lambda\n\nInstrument AWS Lambda functions with the Odigos OpenTelemetry layer, from your own CDK app.\n\n```bash\nnpm install @odigos/aws-cdk # TypeScript / JavaScript\npip install odigos-aws-cdk # Python\n```\n\n```ts\nimport { OdigosLambdaInstrumentation } from '@odigos/aws-cdk';\n\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [apiFn, workerFn],\n});\n```\n\n```python\nfrom odigos_aws_cdk import OdigosLambdaInstrumentation\n\nOdigosLambdaInstrumentation(self, \"Odigos\",\n destination={\"endpoint\": \"otlp.example.com:4317\"},\n functions=[api_fn, worker_fn],\n)\n```\n\nThat attaches the layer for each function's language and architecture, sets the exec wrapper that loads\nthe OpenTelemetry SDK, and hands the in-Lambda collector its whole configuration.\n\n## How the telemetry actually leaves the function\n\nYour function's SDK **does not** export to your destination. It exports to an OpenTelemetry collector\nrunning inside the same Lambda sandbox, on localhost. The collector forwards to your destination *after*\nthe handler has already returned its response.\n\nThat indirection is the whole point. A slow or unreachable destination costs billed duration, not caller\nlatency — and the collector's `decouple` processor is what holds the sandbox open until the export queue\ndrains, so a low-traffic function does not lose its telemetry to the freeze.\n\nConsequently `OTEL_EXPORTER_OTLP_ENDPOINT` is deliberately never set. If you set it yourself you put the\nexport back on the invocation's critical path.\n\n## Endpoint grammar\n\n`endpoint` is OTLP/**gRPC** as bare `host:port` (conventionally 4317). `httpEndpoint` is OTLP/**HTTP** as a\nscheme-qualified URL (conventionally 4318). Exactly one. They select different collector exporters with\ndifferent endpoint grammars, so a scheme in `endpoint` — or its absence in `httpEndpoint` — throws at synth\nrather than producing a collector that starts and silently delivers nothing. A gRPC endpoint on port 4318\n(or an HTTP one on 4317) is the likeliest version of that mistake, and is reported as a synth warning.\n\n## Choosing a layer source\n\n```ts\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [fn],\n layerSource: OdigosLayerSource.IN_ACCOUNT,\n});\n```\n\n| | `ODIGOS_PUBLIC` (default) | `IN_ACCOUNT` |\n|---|---|---|\n| What it synthesizes | a layer ARN | an `AWS::Serverless::Application` (nested stack) per language/arch |\n| Layer owner | the Odigos AWS account | **your** account, created by your stack |\n| Resolution | synth time, from a table baked into this package | deploy time, from the Serverless Application Repository |\n| Environment-agnostic stacks | not supported — needs a concrete region | works |\n| Deploy speed | unchanged | slower on first deploy |\n\nBoth install identical bytes. `IN_ACCOUNT` exists for organisations whose policy forbids attaching a\nLambda layer owned by another AWS account. It needs the deploying principal to be allowed\n`serverlessrepo:CreateCloudFormationTemplate` and `serverlessrepo:GetApplication`.\n\nIf you mirror the layer somewhere yourself, pass `layerVersion` and neither path is used.\n\n## Versioning\n\n**The package version is the layer version.** `@odigos/aws-cdk@0.2.0` resolves to the layer built and\npublished by Odigos release `v0.2.0`, and pins the SAR application to semantic version `0.2.0` — which is\nimmutable, so it means the same bytes forever.\n\nNothing resolves at deploy time in the default path, so upgrading the layer is `npm update` and a\n`cdk diff` that shows the change. An instrumentation layer moving on its own, under a deployment that\nchanged nothing, is not a property you want.\n\n## Handler mode vs. web-server mode\n\n`OdigosInstrumentationMode.HANDLER` (the default) is for a normal Lambda handler. It sets\n`AWS_LAMBDA_EXEC_WRAPPER`.\n\n`OdigosInstrumentationMode.WEB_SERVER` is for a function running a web server behind the\n[AWS Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter). The adapter owns the exec\nwrapper, so this mode does not touch it and loads instrumentation through the language's own loader\nvariable instead.\n\n```ts\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [webFn],\n mode: OdigosInstrumentationMode.WEB_SERVER,\n // NODE_OPTIONS the function already needs — ours is appended, not substituted.\n existingLoaderValue: '--max-old-space-size=2048',\n});\n```\n\nThere is no auto-detection, deliberately. Detecting the adapter means inspecting the function's other\nlayers, which at synth time are frequently unresolved tokens; a detector that was right most of the time\nwould silently break the functions it got wrong. **Applying `HANDLER` to a web-adapter function\noverwrites the adapter's wrapper and the function stops serving.**\n\n`existingLoaderValue` has to be passed explicitly because CDK's `lambda.Function` exposes no way to read\nback an environment variable set elsewhere in your app. Omit it and the loader variable is set to the\nOdigos value alone — for `NODE_OPTIONS` that can mean losing a flag your app needs to boot.\n\nRuby has no verified web-server loader and is rejected at synth in this mode.\n\n## Java handler interfaces\n\nThe Java layer ships four wrapper scripts, one per handler interface, and this is a correctness switch\nrather than a detail level:\n\n```ts\njavaHandlerDistro: OdigosJavaHandlerDistro.OTEL_STREAM_HANDLER\n```\n\n| Distro | For |\n|---|---|\n| `OTEL_HANDLER` (default) | `RequestHandler` |\n| `OTEL_PROXY_HANDLER` | API Gateway proxy events (enriched) |\n| `OTEL_SQS_HANDLER` | SQS events (enriched) |\n| `OTEL_STREAM_HANDLER` | `RequestStreamHandler` |\n\n`OTEL_HANDLER` installs a `RequestHandler` implementation. A `RequestStreamHandler` function has a\ndifferent signature entirely, so wrapping it with the default **breaks the invocation** — it does not\nmerely produce thinner spans.\n\n## Signals\n\n**Traces only, by default.** Metrics and logs are opt-in:\n\n```ts\ndestination: {\n endpoint: 'otlp.example.com:4317',\n metrics: true, // off unless you ask\n logs: true, // off unless you ask\n}\n```\n\nThey are opt-in because the cost of a signal the destination does not implement falls on the function:\nevery batch is refused and the in-Lambda collector retries it on an exponential backoff, inside billed\nduration. Traces are what nearly every destination accepts; the other two are a decision about your\ndestination, so they are made deliberately.\n\nA disabled signal gets no collector pipeline **and** the SDK is told not to produce it\n(`OTEL_METRICS_EXPORTER=none`). Both halves matter: a signal with no pipeline is refused at the receiver on\nevery batch, so suppressing it at the source is what stops the error loop. An enabled signal's variable\nstays unset, because `otlp` is already the SDK default.\n\n`traces: false` with neither of the others on throws at synth — a collector with no pipeline fails to\nstart, which would leave the function instrumented and silent.\n\n**If Odigos also manages this function in manual mode, the signals have to match.** The connector renders\nthe collector configuration from the destination configured in Odigos and compares the whole string, so a\ntraces-only function judged against an all-three destination is reported as drifted on the\ncollector-export component. Enable the same set on both sides.\n\n## Instrumenting a whole stack\n\n```ts\nAspects.of(stack).add(new OdigosInstrumentationAspect(stack, {\n destination: { endpoint: 'otlp.example.com:4317' },\n}));\n```\n\n`skipUnsupportedRuntimes` defaults to `true` for the aspect: it visits every function in the scope,\nincluding ones whose runtime has no OpenTelemetry Lambda layer (`dotnet*`, `provided.*` for Go and custom\nruntimes). Each skip is a synth warning rather than a silent no-op. The construct defaults it to `false`,\nbecause explicitly asking to instrument a Go function is a mistake worth failing on.\n\n## Credentials in `headers`\n\n`destination.headers` is rendered into `OPENTELEMETRY_COLLECTOR_CONFIG_URI`, which is a plain Lambda\nenvironment variable — readable by anyone with `lambda:GetFunctionConfiguration` and visible in the\nconsole. For a long-lived credential, prefer a destination that authenticates by network position, or\nterminate at a collector you control.\n\n## Making Odigos report the function as instrumented\n\nBy default these constructs do **not** write `ODIGOS_MANAGED`, and the consequence is easy to hit: Odigos\nreports the function as `Absent` — \"awaiting your deployment\" — even though the layer is attached, the\nwrapper is set and the collector is configured. The connector derives ownership from that one variable, and\nchecks for it *before* comparing anything else, so nothing about a correctly instrumented function\nsubstitutes for it.\n\nFor a function Odigos discovers in **manual (IaC) mode** — which is the mode a workload is in unless you\nhave explicitly handed instrumentation to the connector — turn it on:\n\n```ts\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [fn],\n recordOwnershipMarker: true,\n});\n```\n\nThe marker records the exact layer ARN the construct attached, which is also what the connector reads back\nto decide which layer version the function is *supposed* to carry — so a version you pinned is respected\ninstead of being reported as drift. It works in `IN_ACCOUNT` mode too, where the ARN is a deploy-time\nreference your own code has no way to obtain.\n\nIt also records a rollback snapshot (`prevEnv`) naming every variable the construct set. That matters: a\nmarker without one makes an uninstrument remove the **layer** while leaving `AWS_LAMBDA_EXEC_WRAPPER`\npointing into it, which breaks the function at its next cold start. In web-server mode the snapshot holds\nyour `existingLoaderValue`, so a rollback restores your own `NODE_OPTIONS` rather than deleting it.\n\nLeave it `false` for a function you have enabled as an **automatic-mode** connector source: there the\nconnector owns the marker, including a snapshot it wrote itself, and two writers of one ownership record is\nthe combination that genuinely misbehaves.\n\n## Service names\n\nLeft unset, `OTEL_SERVICE_NAME` is the function's physical name when your stack names it explicitly, and\nthe construct id otherwise. The fallback exists because a name CloudFormation generates is a `Ref` to the\nfunction, and a function referencing itself in its own environment is a dependency cycle CloudFormation\nrejects at deploy time.\n\nThe connector compares `OTEL_SERVICE_NAME` against the workload's name in Odigos, which is the real AWS\nfunction name — so for a function whose name is generated, pass `serviceName` explicitly or it is reported\nas drifted. `serviceName` applies to **every** function a construct instruments, so use one construct per\nfunction when you want per-function names.\n\n## Do not also instrument these functions with the Odigos connector\n\nThe Odigos AWS connector instruments **live** functions by mutating them, and reconciles them back to its\nown desired state on every pass. A function instrumented here *and* enabled as an automatic-mode connector\nsource ends up owned by both: each `cdk deploy` reasserts the CDK's environment, each reconcile reasserts\nthe connector's, and every round trip publishes a new function version.\n\nPick one per function. Discovery-only (manual) mode is the combination that works: Odigos watches and\nreports, your stack owns the configuration — that is what `recordOwnershipMarker` is for.\n\n## API\n\n| Export | |\n|---|---|\n| `OdigosLambdaInstrumentation` | the construct; `instrument(fn)`, `instrumentAll(fns)` |\n| `OdigosInstrumentationAspect` | applies it to every function in a scope |\n| `OdigosDestination` | where the collector exports; exactly one of `endpoint` / `httpEndpoint` |\n| `OdigosLayerSource` | `ODIGOS_PUBLIC` \\| `IN_ACCOUNT` |\n| `OdigosInstrumentationMode` | `HANDLER` \\| `WEB_SERVER` |\n| `OdigosJavaHandlerDistro` | the four Java wrappers |\n| `recordOwnershipMarker` | the option that makes Odigos recognise the function as instrumented |\n| `renderCollectorConfig` | the collector config renderer, if you want to inspect what gets set |\n| `LAYER_ARNS`, `ODIGOS_VERSION` | the baked layer table and the release it came from |\n\n## License\n\nApache-2.0.\n"
3829
+ "markdown": "# Odigos CDK constructs for AWS Lambda\n\nInstrument AWS Lambda functions with the Odigos OpenTelemetry layer, from your own CDK app.\n\n```bash\nnpm install @odigos/aws-cdk # TypeScript / JavaScript\npip install odigos-aws-cdk # Python\n```\n\n```ts\nimport { OdigosLambdaInstrumentation } from '@odigos/aws-cdk';\n\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [apiFn, workerFn],\n});\n```\n\n```python\nfrom odigos_aws_cdk import OdigosLambdaInstrumentation\n\nOdigosLambdaInstrumentation(self, \"Odigos\",\n destination={\"endpoint\": \"otlp.example.com:4317\"},\n functions=[api_fn, worker_fn],\n)\n```\n\nThat attaches the layer for each function's language and architecture, sets the exec wrapper that loads\nthe OpenTelemetry SDK, and hands the in-Lambda collector its whole configuration.\n\n## How the telemetry actually leaves the function\n\nYour function's SDK **does not** export to your destination. It exports to an OpenTelemetry collector\nrunning inside the same Lambda sandbox, on localhost. The collector forwards to your destination *after*\nthe handler has already returned its response.\n\nThat indirection is the whole point. A slow or unreachable destination costs billed duration, not caller\nlatency — and the collector's `decouple` processor is what holds the sandbox open until the export queue\ndrains, so a low-traffic function does not lose its telemetry to the freeze.\n\nConsequently `OTEL_EXPORTER_OTLP_ENDPOINT` is deliberately never set. If you set it yourself you put the\nexport back on the invocation's critical path.\n\n## Endpoint grammar\n\n`endpoint` is OTLP/**gRPC** as bare `host:port` (conventionally 4317). `httpEndpoint` is OTLP/**HTTP** as a\nscheme-qualified URL (conventionally 4318). Exactly one. They select different collector exporters with\ndifferent endpoint grammars, so a scheme in `endpoint` — or its absence in `httpEndpoint` — throws at synth\nrather than producing a collector that starts and silently delivers nothing. A gRPC endpoint on port 4318\n(or an HTTP one on 4317) is the likeliest version of that mistake, and is reported as a synth warning.\n\n## Choosing a layer source\n\n```ts\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [fn],\n layerSource: OdigosLayerSource.IN_ACCOUNT,\n});\n```\n\n| | `ODIGOS_PUBLIC` (default) | `IN_ACCOUNT` |\n|---|---|---|\n| What it synthesizes | a layer ARN | an `AWS::Serverless::Application` (nested stack) per language/arch |\n| Layer owner | the Odigos AWS account | **your** account, created by your stack |\n| Resolution | synth time, from a table baked into this package | deploy time, from the Serverless Application Repository |\n| Environment-agnostic stacks | not supported — needs a concrete region | works |\n| Deploy speed | unchanged | slower on first deploy |\n\nBoth install identical bytes. `IN_ACCOUNT` exists for organisations whose policy forbids attaching a\nLambda layer owned by another AWS account. It needs the deploying principal to be allowed\n`serverlessrepo:CreateCloudFormationTemplate` and `serverlessrepo:GetApplication`.\n\nIf you mirror the layer somewhere yourself, pass `layerVersion` and neither path is used.\n\n## Versioning\n\n**The package version is the layer version.** `@odigos/aws-cdk@0.2.0` resolves to the layer built and\npublished by Odigos release `v0.2.0`, and pins the SAR application to semantic version `0.2.0` — which is\nimmutable, so it means the same bytes forever.\n\nNothing resolves at deploy time in the default path, so upgrading the layer is `npm update` and a\n`cdk diff` that shows the change. An instrumentation layer moving on its own, under a deployment that\nchanged nothing, is not a property you want.\n\n## Handler mode vs. web-server mode\n\n`OdigosInstrumentationMode.HANDLER` (the default) is for a normal Lambda handler. It sets\n`AWS_LAMBDA_EXEC_WRAPPER`.\n\n`OdigosInstrumentationMode.WEB_SERVER` is for a function running a web server behind the\n[AWS Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter). The adapter owns the exec\nwrapper, so this mode does not touch it and loads instrumentation through the language's own loader\nvariable instead.\n\n```ts\nnew OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [webFn],\n mode: OdigosInstrumentationMode.WEB_SERVER,\n // NODE_OPTIONS the function already needs — ours is appended, not substituted.\n existingLoaderValue: '--max-old-space-size=2048',\n});\n```\n\nThere is no auto-detection, deliberately. Detecting the adapter means inspecting the function's other\nlayers, which at synth time are frequently unresolved tokens; a detector that was right most of the time\nwould silently break the functions it got wrong. **Applying `HANDLER` to a web-adapter function\noverwrites the adapter's wrapper and the function stops serving.**\n\n`existingLoaderValue` has to be passed explicitly because CDK's `lambda.Function` exposes no way to read\nback an environment variable set elsewhere in your app. Omit it and the loader variable is set to the\nOdigos value alone — for `NODE_OPTIONS` that can mean losing a flag your app needs to boot.\n\nRuby has no verified web-server loader and is rejected at synth in this mode.\n\n## Java handler interfaces\n\nThe Java layer ships four wrapper scripts, one per handler interface, and this is a correctness switch\nrather than a detail level:\n\n```ts\njavaHandlerDistro: OdigosJavaHandlerDistro.OTEL_STREAM_HANDLER\n```\n\n| Distro | For |\n|---|---|\n| `OTEL_HANDLER` (default) | `RequestHandler` |\n| `OTEL_PROXY_HANDLER` | API Gateway proxy events (enriched) |\n| `OTEL_SQS_HANDLER` | SQS events (enriched) |\n| `OTEL_STREAM_HANDLER` | `RequestStreamHandler` |\n\n`OTEL_HANDLER` installs a `RequestHandler` implementation. A `RequestStreamHandler` function has a\ndifferent signature entirely, so wrapping it with the default **breaks the invocation** — it does not\nmerely produce thinner spans.\n\n## Signals\n\n**Traces only, by default.** Metrics and logs are opt-in:\n\n```ts\ndestination: {\n endpoint: 'otlp.example.com:4317',\n metrics: true, // off unless you ask\n logs: true, // off unless you ask\n}\n```\n\nThey are opt-in because the cost of a signal the destination does not implement falls on the function:\nevery batch is refused and the in-Lambda collector retries it on an exponential backoff, inside billed\nduration. Traces are what nearly every destination accepts; the other two are a decision about your\ndestination, so they are made deliberately.\n\nA disabled signal gets no collector pipeline **and** the SDK is told not to produce it\n(`OTEL_METRICS_EXPORTER=none`). Both halves matter: a signal with no pipeline is refused at the receiver on\nevery batch, so suppressing it at the source is what stops the error loop. An enabled signal's variable\nstays unset, because `otlp` is already the SDK default.\n\n`traces: false` with neither of the others on throws at synth — a collector with no pipeline fails to\nstart, which would leave the function instrumented and silent.\n\n**If Odigos also manages this function in manual mode, the signals have to match.** The connector renders\nthe collector configuration from the destination configured in Odigos and compares the whole string, so a\ntraces-only function judged against an all-three destination is reported as drifted on the\ncollector-export component. Enable the same set on both sides.\n\n## Instrumenting a whole stack\n\n```ts\nAspects.of(stack).add(new OdigosInstrumentationAspect(stack, {\n destination: { endpoint: 'otlp.example.com:4317' },\n}));\n```\n\n`skipUnsupportedRuntimes` defaults to `true` for the aspect: it visits every function in the scope,\nincluding ones whose runtime has no OpenTelemetry Lambda layer (`dotnet*`, `provided.*` for Go and custom\nruntimes). Each skip is a synth warning rather than a silent no-op. The construct defaults it to `false`,\nbecause explicitly asking to instrument a Go function is a mistake worth failing on.\n\n## Credentials in `headers`\n\n`destination.headers` is rendered into `OPENTELEMETRY_COLLECTOR_CONFIG_URI`, which is a plain Lambda\nenvironment variable — readable by anyone with `lambda:GetFunctionConfiguration` and visible in the\nconsole. For a long-lived credential, prefer a destination that authenticates by network position, or\nterminate at a collector you control.\n\n## How Odigos recognises the function\n\nThese constructs write `ODIGOS_IAC` on every function they instrument, recording the layer ARN they attached\nand the package version that attached it. That variable is what Odigos reads to attribute the function to\nitself; without it a function reports as `Absent` — \"awaiting your deployment\" — however completely the layer,\nwrapper and collector configuration are applied. There is nothing to switch on.\n\nThe recorded layer ARN matters beyond attribution: it is what the connector checks the function against, so a\nversion you pinned is respected instead of being reported as drift the day Odigos publishes a newer one. It\nworks in `IN_ACCOUNT` mode too, where the ARN is a deploy-time reference your own code has no way to obtain.\n\nWhat these constructs never write is `ODIGOS_MANAGED`. That is the connector's own record of a mutation *it*\nperformed, including the `prevEnv` snapshot it restores from on rollback, and it is written only when you hand\na function to the connector by enabling it as an automatic-mode source. A CDK stack has no such snapshot to\noffer — nothing was mutated, your stack *is* the function's definition — so writing it would claim a rollback\nthat was never recorded. Do not add it by hand.\n\n## Service names\n\nLeft unset, `OTEL_SERVICE_NAME` is the function's physical name when your stack names it explicitly, and\nthe construct id otherwise. The fallback exists because a name CloudFormation generates is a `Ref` to the\nfunction, and a function referencing itself in its own environment is a dependency cycle CloudFormation\nrejects at deploy time.\n\nThe connector compares `OTEL_SERVICE_NAME` against the workload's name in Odigos, which is the real AWS\nfunction name — so for a function whose name is generated, pass `serviceName` explicitly or it is reported\nas drifted. `serviceName` applies to **every** function a construct instruments, so use one construct per\nfunction when you want per-function names.\n\n## Do not also instrument these functions with the Odigos connector\n\nThe Odigos AWS connector instruments **live** functions by mutating them, and reconciles them back to its\nown desired state on every pass. A function instrumented here *and* enabled as an automatic-mode connector\nsource ends up owned by both: each `cdk deploy` reasserts the CDK's environment, each reconcile reasserts\nthe connector's, and every round trip publishes a new function version.\n\nPick one per function. Discovery-only (manual) mode is the combination that works: Odigos watches and\nreports, your stack owns the configuration. That is what `ODIGOS_IAC` expresses — instrumented by Odigos,\nowned by you — and it is why these constructs never write the connector's ownership marker.\n\n## API\n\n| Export | |\n|---|---|\n| `OdigosLambdaInstrumentation` | the construct; `instrument(fn)`, `instrumentAll(fns)` |\n| `OdigosInstrumentationAspect` | applies it to every function in a scope |\n| `OdigosDestination` | where the collector exports; exactly one of `endpoint` / `httpEndpoint` |\n| `OdigosLayerSource` | `ODIGOS_PUBLIC` \\| `IN_ACCOUNT` |\n| `OdigosInstrumentationMode` | `HANDLER` \\| `WEB_SERVER` |\n| `OdigosJavaHandlerDistro` | the four Java wrappers |\n| `renderCollectorConfig` | the collector config renderer, if you want to inspect what gets set |\n| `LAYER_ARNS`, `ODIGOS_VERSION` | the baked layer table and the release it came from |\n\n## License\n\nApache-2.0.\n"
3830
3830
  },
3831
3831
  "repository": {
3832
3832
  "directory": "cdk",
@@ -3852,7 +3852,7 @@
3852
3852
  "assembly": "@odigos/aws-cdk",
3853
3853
  "datatype": true,
3854
3854
  "docs": {
3855
- "remarks": "Exactly one of `endpoint` (OTLP/gRPC) and `httpEndpoint` (OTLP/HTTP) must be set. They are different\ncollector components with different endpoint grammars — `host:port` versus a scheme-qualified URL — so\nthis is a genuine branch and not a formatting difference. Setting neither, or both, throws at synth.\n\nNOTE ON THE DATA PATH. The function's SDK does not export here. It exports to the collector running\ninside the same Lambda sandbox on localhost, and the collector forwards to this destination after the\nhandler has already returned its response. That indirection is the point: a slow or unreachable\ndestination costs billed duration, not caller latency.",
3855
+ "remarks": "Exactly one of `endpoint` (OTLP/gRPC) and `httpEndpoint` (OTLP/HTTP) must be set. They are different\ncollector components with different endpoint grammars — `host:port` versus a scheme-qualified URL — so\nthis is a genuine branch and not a formatting difference. Setting neither, or both, throws at synth.\n\nNOTE ON THE DATA PATH. The function's SDK does not export here. It exports to the collector running\ninside the same Lambda sandbox on localhost, and the collector forwards to this destination after the\nhandler has already returned its response. That indirection is the point: a slow or unreachable\ndestination costs billed duration, not caller latency.\n\nTHIS MUST DESCRIBE THE SAME DESTINATION ODIGOS HAS CONFIGURED, SIGNAL FOR SIGNAL. The connector renders\nthis same configuration from its own destination record and compares the whole rendered document against\nwhat the function carries, so any difference — the endpoint, the credential, or which of the three signals\nis enabled — is reported as instrumentation drift on the workload rather than being reconciled. The\nasymmetry to watch is the signals: `traces` is on here and `metrics`/`logs` are off, while a destination in\nOdigos commonly has more than one enabled. A stack that leaves the defaults against such a destination\nreports as drifted for a reason nothing in the stack makes visible, so read the enabled signals off the\ndestination in Odigos and state them here.",
3856
3856
  "stability": "stable",
3857
3857
  "summary": "Where the in-Lambda collector exports telemetry to."
3858
3858
  },
@@ -3860,7 +3860,7 @@
3860
3860
  "kind": "interface",
3861
3861
  "locationInModule": {
3862
3862
  "filename": "src/types.ts",
3863
- "line": 102
3863
+ "line": 111
3864
3864
  },
3865
3865
  "name": "OdigosDestination",
3866
3866
  "properties": [
@@ -3875,7 +3875,7 @@
3875
3875
  "immutable": true,
3876
3876
  "locationInModule": {
3877
3877
  "filename": "src/types.ts",
3878
- "line": 111
3878
+ "line": 120
3879
3879
  },
3880
3880
  "name": "endpoint",
3881
3881
  "optional": true,
@@ -3894,7 +3894,7 @@
3894
3894
  "immutable": true,
3895
3895
  "locationInModule": {
3896
3896
  "filename": "src/types.ts",
3897
- "line": 139
3897
+ "line": 148
3898
3898
  },
3899
3899
  "name": "headers",
3900
3900
  "optional": true,
@@ -3917,7 +3917,7 @@
3917
3917
  "immutable": true,
3918
3918
  "locationInModule": {
3919
3919
  "filename": "src/types.ts",
3920
- "line": 118
3920
+ "line": 127
3921
3921
  },
3922
3922
  "name": "httpEndpoint",
3923
3923
  "optional": true,
@@ -3936,7 +3936,7 @@
3936
3936
  "immutable": true,
3937
3937
  "locationInModule": {
3938
3938
  "filename": "src/types.ts",
3939
- "line": 127
3939
+ "line": 136
3940
3940
  },
3941
3941
  "name": "insecure",
3942
3942
  "optional": true,
@@ -3955,7 +3955,7 @@
3955
3955
  "immutable": true,
3956
3956
  "locationInModule": {
3957
3957
  "filename": "src/types.ts",
3958
- "line": 176
3958
+ "line": 185
3959
3959
  },
3960
3960
  "name": "logs",
3961
3961
  "optional": true,
@@ -3974,7 +3974,7 @@
3974
3974
  "immutable": true,
3975
3975
  "locationInModule": {
3976
3976
  "filename": "src/types.ts",
3977
- "line": 165
3977
+ "line": 174
3978
3978
  },
3979
3979
  "name": "metrics",
3980
3980
  "optional": true,
@@ -3993,7 +3993,7 @@
3993
3993
  "immutable": true,
3994
3994
  "locationInModule": {
3995
3995
  "filename": "src/types.ts",
3996
- "line": 153
3996
+ "line": 162
3997
3997
  },
3998
3998
  "name": "traces",
3999
3999
  "optional": true,
@@ -4018,7 +4018,7 @@
4018
4018
  },
4019
4019
  "locationInModule": {
4020
4020
  "filename": "src/instrumentation.ts",
4021
- "line": 448
4021
+ "line": 386
4022
4022
  },
4023
4023
  "parameters": [
4024
4024
  {
@@ -4045,7 +4045,7 @@
4045
4045
  "kind": "class",
4046
4046
  "locationInModule": {
4047
4047
  "filename": "src/instrumentation.ts",
4048
- "line": 440
4048
+ "line": 378
4049
4049
  },
4050
4050
  "methods": [
4051
4051
  {
@@ -4055,7 +4055,7 @@
4055
4055
  },
4056
4056
  "locationInModule": {
4057
4057
  "filename": "src/instrumentation.ts",
4058
- "line": 455
4058
+ "line": 393
4059
4059
  },
4060
4060
  "name": "visit",
4061
4061
  "overrides": "aws-cdk-lib.IAspect",
@@ -4086,7 +4086,7 @@
4086
4086
  "kind": "interface",
4087
4087
  "locationInModule": {
4088
4088
  "filename": "src/instrumentation.ts",
4089
- "line": 421
4089
+ "line": 359
4090
4090
  },
4091
4091
  "name": "OdigosInstrumentationAspectProps",
4092
4092
  "symbolId": "src/instrumentation:OdigosInstrumentationAspectProps"
@@ -4269,25 +4269,6 @@
4269
4269
  "fqn": "@odigos/aws-cdk.OdigosInstrumentationMode"
4270
4270
  }
4271
4271
  },
4272
- {
4273
- "abstract": true,
4274
- "docs": {
4275
- "default": "false",
4276
- "remarks": "WITHOUT IT THE FUNCTION IS REPORTED AS UNINSTRUMENTED. The connector derives ownership from this\nvariable alone: no marker means `Absent` — \"awaiting your deployment\" — even though the layer is\nattached, the wrapper is set and the collector is configured. Set this to `true` for a function that\nOdigos discovers in MANUAL (IaC) mode, which is the mode a workload is in unless you explicitly hand\ninstrumentation to the connector.\n\nLeave it `false` (the default) for a function you have enabled as an AUTOMATIC-mode connector source.\nThere, the connector instruments the function itself and owns this variable, including the `prevEnv`\nsnapshot it restores on rollback; two writers of one ownership record is the one combination that\ngenuinely misbehaves.\n\nThe marker records the exact layer ARN this construct attached, which is also what the connector reads\nback to decide which layer version the function is supposed to carry — so a version you pinned is\nrespected rather than reported as drift. It works in every layer mode, including `IN_ACCOUNT`, where the\nARN is a deploy-time reference your own code cannot obtain.",
4277
- "stability": "stable",
4278
- "summary": "Write `ODIGOS_MANAGED`, the marker that makes the Odigos connector recognise this function as instrumented."
4279
- },
4280
- "immutable": true,
4281
- "locationInModule": {
4282
- "filename": "src/instrumentation.ts",
4283
- "line": 187
4284
- },
4285
- "name": "recordOwnershipMarker",
4286
- "optional": true,
4287
- "type": {
4288
- "primitive": "boolean"
4289
- }
4290
- },
4291
4272
  {
4292
4273
  "abstract": true,
4293
4274
  "docs": {
@@ -4318,7 +4299,7 @@
4318
4299
  "immutable": true,
4319
4300
  "locationInModule": {
4320
4301
  "filename": "src/instrumentation.ts",
4321
- "line": 198
4302
+ "line": 174
4322
4303
  },
4323
4304
  "name": "skipUnsupportedRuntimes",
4324
4305
  "optional": true,
@@ -4380,7 +4361,7 @@
4380
4361
  "assembly": "@odigos/aws-cdk",
4381
4362
  "base": "constructs.Construct",
4382
4363
  "docs": {
4383
- "remarks": "```ts\nconst odigos = new OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [apiFn, workerFn],\n});\nodigos.instrument(anotherFn);\n```\n\nWhat it does to each function: attaches the layer for the function's language and architecture, sets\n`AWS_LAMBDA_EXEC_WRAPPER` so the layer loads the SDK, sets `OTEL_SERVICE_NAME`, and hands the in-Lambda\ncollector its entire configuration inline through `OPENTELEMETRY_COLLECTOR_CONFIG_URI`.\n\nThe function's SDK exports to the collector on localhost, not to your destination. The collector\nforwards after the handler has already returned, so a slow destination costs billed duration rather\nthan caller latency.\n\n## Do not also instrument these functions with the connector\n\nThe Odigos AWS connector instruments live functions by mutating them, and reconciles them back to its\nown desired state on every pass. A function instrumented here and also enabled as a connector source\nends up owned by both: each `cdk deploy` reasserts the CDK's environment, each reconcile reasserts the\nconnector's, and every round trip publishes a new function version.\n\nChoose one per function. This construct never sets the connector's `ODIGOS_MANAGED` ownership marker,\nso an IaC-instrumented function is not one the connector will roll back — but it will happily take it\nover if you enable it as a source.",
4364
+ "remarks": "```ts\nconst odigos = new OdigosLambdaInstrumentation(this, 'Odigos', {\n destination: { endpoint: 'otlp.example.com:4317' },\n functions: [apiFn, workerFn],\n});\nodigos.instrument(anotherFn);\n```\n\nWhat it does to each function: attaches the layer for the function's language and architecture, sets\n`AWS_LAMBDA_EXEC_WRAPPER` so the layer loads the SDK, sets `OTEL_SERVICE_NAME`, and hands the in-Lambda\ncollector its entire configuration inline through `OPENTELEMETRY_COLLECTOR_CONFIG_URI`.\n\nThe function's SDK exports to the collector on localhost, not to your destination. The collector\nforwards after the handler has already returned, so a slow destination costs billed duration rather\nthan caller latency.\n\n## Do not also instrument these functions with the connector\n\nThe Odigos AWS connector instruments live functions by mutating them, and reconciles them back to its\nown desired state on every pass. A function instrumented here and also enabled as a connector source\nends up owned by both: each `cdk deploy` reasserts the CDK's environment, each reconcile reasserts the\nconnector's, and every round trip publishes a new function version.\n\nChoose one per function. This construct writes `ODIGOS_IAC` and never the connector's `ODIGOS_MANAGED`\nownership marker, so an IaC-instrumented function reports as instrumented but is not one the connector\nwill roll back — though it will happily take it over if you enable it as a source.",
4384
4365
  "stability": "stable",
4385
4366
  "summary": "Instruments AWS Lambda functions with the Odigos OpenTelemetry layer."
4386
4367
  },
@@ -4391,7 +4372,7 @@
4391
4372
  },
4392
4373
  "locationInModule": {
4393
4374
  "filename": "src/instrumentation.ts",
4394
- "line": 249
4375
+ "line": 225
4395
4376
  },
4396
4377
  "parameters": [
4397
4378
  {
@@ -4417,7 +4398,7 @@
4417
4398
  "kind": "class",
4418
4399
  "locationInModule": {
4419
4400
  "filename": "src/instrumentation.ts",
4420
- "line": 243
4401
+ "line": 219
4421
4402
  },
4422
4403
  "methods": [
4423
4404
  {
@@ -4428,7 +4409,7 @@
4428
4409
  },
4429
4410
  "locationInModule": {
4430
4411
  "filename": "src/instrumentation.ts",
4431
- "line": 289
4412
+ "line": 265
4432
4413
  },
4433
4414
  "name": "instrument",
4434
4415
  "parameters": [
@@ -4447,7 +4428,7 @@
4447
4428
  },
4448
4429
  "locationInModule": {
4449
4430
  "filename": "src/instrumentation.ts",
4450
- "line": 322
4431
+ "line": 298
4451
4432
  },
4452
4433
  "name": "instrumentAll",
4453
4434
  "parameters": [
@@ -4482,7 +4463,7 @@
4482
4463
  "kind": "interface",
4483
4464
  "locationInModule": {
4484
4465
  "filename": "src/instrumentation.ts",
4485
- "line": 204
4466
+ "line": 180
4486
4467
  },
4487
4468
  "name": "OdigosLambdaInstrumentationProps",
4488
4469
  "properties": [
@@ -4497,7 +4478,7 @@
4497
4478
  "immutable": true,
4498
4479
  "locationInModule": {
4499
4480
  "filename": "src/instrumentation.ts",
4500
- "line": 210
4481
+ "line": 186
4501
4482
  },
4502
4483
  "name": "functions",
4503
4484
  "optional": true,
@@ -4547,6 +4528,6 @@
4547
4528
  "symbolId": "src/types:OdigosLayerSource"
4548
4529
  }
4549
4530
  },
4550
- "version": "0.0.12",
4551
- "fingerprint": "76adPuc8StHhgh9x1dH8rP9GBtLmzzNKY1d5Dvhv+hM="
4531
+ "version": "0.0.13",
4532
+ "fingerprint": "62LewgfsWUxqzy3tCKsO8Zo2MuyMvKF8j7uqckYFRoc="
4552
4533
  }
package/README.md CHANGED
@@ -184,38 +184,22 @@ environment variable — readable by anyone with `lambda:GetFunctionConfiguratio
184
184
  console. For a long-lived credential, prefer a destination that authenticates by network position, or
185
185
  terminate at a collector you control.
186
186
 
187
- ## Making Odigos report the function as instrumented
187
+ ## How Odigos recognises the function
188
188
 
189
- By default these constructs do **not** write `ODIGOS_MANAGED`, and the consequence is easy to hit: Odigos
190
- reports the function as `Absent` — "awaiting your deployment" — even though the layer is attached, the
191
- wrapper is set and the collector is configured. The connector derives ownership from that one variable, and
192
- checks for it *before* comparing anything else, so nothing about a correctly instrumented function
193
- substitutes for it.
189
+ These constructs write `ODIGOS_IAC` on every function they instrument, recording the layer ARN they attached
190
+ and the package version that attached it. That variable is what Odigos reads to attribute the function to
191
+ itself; without it a function reports as `Absent` — "awaiting your deployment" — however completely the layer,
192
+ wrapper and collector configuration are applied. There is nothing to switch on.
194
193
 
195
- For a function Odigos discovers in **manual (IaC) mode** — which is the mode a workload is in unless you
196
- have explicitly handed instrumentation to the connector — turn it on:
194
+ The recorded layer ARN matters beyond attribution: it is what the connector checks the function against, so a
195
+ version you pinned is respected instead of being reported as drift the day Odigos publishes a newer one. It
196
+ works in `IN_ACCOUNT` mode too, where the ARN is a deploy-time reference your own code has no way to obtain.
197
197
 
198
- ```ts
199
- new OdigosLambdaInstrumentation(this, 'Odigos', {
200
- destination: { endpoint: 'otlp.example.com:4317' },
201
- functions: [fn],
202
- recordOwnershipMarker: true,
203
- });
204
- ```
205
-
206
- The marker records the exact layer ARN the construct attached, which is also what the connector reads back
207
- to decide which layer version the function is *supposed* to carry — so a version you pinned is respected
208
- instead of being reported as drift. It works in `IN_ACCOUNT` mode too, where the ARN is a deploy-time
209
- reference your own code has no way to obtain.
210
-
211
- It also records a rollback snapshot (`prevEnv`) naming every variable the construct set. That matters: a
212
- marker without one makes an uninstrument remove the **layer** while leaving `AWS_LAMBDA_EXEC_WRAPPER`
213
- pointing into it, which breaks the function at its next cold start. In web-server mode the snapshot holds
214
- your `existingLoaderValue`, so a rollback restores your own `NODE_OPTIONS` rather than deleting it.
215
-
216
- Leave it `false` for a function you have enabled as an **automatic-mode** connector source: there the
217
- connector owns the marker, including a snapshot it wrote itself, and two writers of one ownership record is
218
- the combination that genuinely misbehaves.
198
+ What these constructs never write is `ODIGOS_MANAGED`. That is the connector's own record of a mutation *it*
199
+ performed, including the `prevEnv` snapshot it restores from on rollback, and it is written only when you hand
200
+ a function to the connector by enabling it as an automatic-mode source. A CDK stack has no such snapshot to
201
+ offer — nothing was mutated, your stack *is* the function's definition — so writing it would claim a rollback
202
+ that was never recorded. Do not add it by hand.
219
203
 
220
204
  ## Service names
221
205
 
@@ -237,7 +221,8 @@ source ends up owned by both: each `cdk deploy` reasserts the CDK's environment,
237
221
  the connector's, and every round trip publishes a new function version.
238
222
 
239
223
  Pick one per function. Discovery-only (manual) mode is the combination that works: Odigos watches and
240
- reports, your stack owns the configuration — that is what `recordOwnershipMarker` is for.
224
+ reports, your stack owns the configuration. That is what `ODIGOS_IAC` expresses — instrumented by Odigos,
225
+ owned by you — and it is why these constructs never write the connector's ownership marker.
241
226
 
242
227
  ## API
243
228
 
@@ -249,7 +234,6 @@ reports, your stack owns the configuration — that is what `recordOwnershipMark
249
234
  | `OdigosLayerSource` | `ODIGOS_PUBLIC` \| `IN_ACCOUNT` |
250
235
  | `OdigosInstrumentationMode` | `HANDLER` \| `WEB_SERVER` |
251
236
  | `OdigosJavaHandlerDistro` | the four Java wrappers |
252
- | `recordOwnershipMarker` | the option that makes Odigos recognise the function as instrumented |
253
237
  | `renderCollectorConfig` | the collector config renderer, if you want to inspect what gets set |
254
238
  | `LAYER_ARNS`, `ODIGOS_VERSION` | the baked layer table and the release it came from |
255
239
 
@@ -4,12 +4,12 @@
4
4
  * Produced by cdk/scripts/generate-layers.ts from artifacts.json and manifest/layers.json.
5
5
  * Run `npm run generate` (or `npm run build`) to refresh it.
6
6
  *
7
- * Odigos artifact version: v0.0.12
7
+ * Odigos artifact version: v0.0.13
8
8
  */
9
9
  /** Release this table was generated from. Empty before the first release. */
10
- export declare const ODIGOS_VERSION = "v0.0.12";
10
+ export declare const ODIGOS_VERSION = "v0.0.13";
11
11
  /** SAR semantic version matching ODIGOS_VERSION (no leading "v"). */
12
- export declare const SAR_SEMANTIC_VERSION = "0.0.12";
12
+ export declare const SAR_SEMANTIC_VERSION = "0.0.13";
13
13
  /** Public layer ARNs, keyed "<region>/<language>/<architecture>". */
14
14
  export declare const LAYER_ARNS: {
15
15
  [key: string]: string;