@odigos/aws-cdk 0.0.13 → 0.0.14

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.
@@ -0,0 +1,218 @@
1
+ import * as ecs from 'aws-cdk-lib/aws-ecs';
2
+ import { Construct } from 'constructs';
3
+ import { OdigosDestination, OdigosFargateLanguage } from './types';
4
+ /**
5
+ * Options shared by every container this construct instruments.
6
+ */
7
+ export interface OdigosFargateInstrumentationOptions {
8
+ /**
9
+ * Where the instrumented containers export telemetry to.
10
+ *
11
+ * Unlike Lambda, BOTH transports may be set and often should be: a Fargate task has no collector of its
12
+ * own, so each language's agent exports to this destination itself and takes the transport it prefers.
13
+ * php and ruby can only speak OTLP/HTTP at all.
14
+ */
15
+ readonly destination: OdigosDestination;
16
+ /**
17
+ * The agents bundle the staging container copies the language agents out of.
18
+ *
19
+ * Defaults to the multi-arch image this package's release published, at that release's immutable tag.
20
+ * Override it to mirror the image into a registry your tasks can reach — the image is pulled by YOUR
21
+ * task's execution role at every task start, so a task in a private subnet with no NAT and no
22
+ * interface endpoint cannot pull the default.
23
+ *
24
+ * A mirror must be the same bundle: the activation environment set below names exact paths inside it.
25
+ *
26
+ * @default - the released `registry.odigos.io/odigos-fargate-agents` image for this package version
27
+ */
28
+ readonly agentsImage?: string;
29
+ /**
30
+ * Raise agent verbosity (`OTEL_LOG_LEVEL=debug`) on every instrumented container.
31
+ *
32
+ * Useful while wiring up a destination, expensive to leave on — and it is compared: the connector
33
+ * expects the variable ABSENT unless debug telemetry is enabled for the connector too, so leaving this
34
+ * on can itself be reported as drift.
35
+ *
36
+ * @default false
37
+ */
38
+ readonly debug?: boolean;
39
+ }
40
+ /**
41
+ * One container to instrument.
42
+ */
43
+ export interface OdigosFargateTarget {
44
+ /**
45
+ * The application container. Its task definition is taken from it, so the staging container, the shared
46
+ * volume and the startup dependency are added to the right one automatically.
47
+ */
48
+ readonly container: ecs.ContainerDefinition;
49
+ /**
50
+ * The language whose agent to stage and activate.
51
+ *
52
+ * Stated rather than detected — a container declares an image, not a runtime, and resolving a language
53
+ * from an image means pulling it.
54
+ */
55
+ readonly language: OdigosFargateLanguage;
56
+ /**
57
+ * `OTEL_SERVICE_NAME` for this container.
58
+ *
59
+ * THIS MUST MATCH THE WORKLOAD'S NAME IN ODIGOS, which for a Fargate workload is the ECS SERVICE name —
60
+ * not the task definition family and not the container name. A different value is reported as
61
+ * instrumentation drift rather than treated as a naming preference.
62
+ *
63
+ * Pass `service` instead to read it off the service, or set this when the service is defined elsewhere
64
+ * (a different stack, Terraform, the console). One of the two is required.
65
+ *
66
+ * @default - taken from `service`
67
+ */
68
+ readonly serviceName?: string;
69
+ /**
70
+ * The ECS service that runs this task definition, used only to read its name.
71
+ *
72
+ * Its physical name has to be one your stack SET, not one CloudFormation generates: a generated name is
73
+ * a `Ref` to the service, and a service's own task definition referencing it is a dependency cycle
74
+ * CloudFormation rejects at deploy time. A generated name throws at synth pointing at `serviceName`.
75
+ *
76
+ * @default - `serviceName` must be given instead
77
+ */
78
+ readonly service?: ecs.BaseService;
79
+ /**
80
+ * The application's runtime version as `major.minor` — for example `"8.3"`.
81
+ *
82
+ * Required for php and ruby, whose agents are laid down per runtime version in the bundle, and the
83
+ * version selects the path their activation variables point at. Ignored by every other language.
84
+ *
85
+ * @default - none; required for php and ruby
86
+ */
87
+ readonly runtimeVersion?: string;
88
+ /**
89
+ * The value this container already needs in its loader variable (`JAVA_TOOL_OPTIONS`, `NODE_OPTIONS` or
90
+ * `PYTHONPATH`), which the Odigos fragment is joined to rather than replacing.
91
+ *
92
+ * Only needed as an OVERRIDE. The construct reads the value the container was created with and appends
93
+ * to it, so a container that sets its own `JAVA_TOOL_OPTIONS` in `addContainer` keeps it. Pass this when
94
+ * the value is not visible at synth — set by an `environmentFiles` entry, injected by the image's own
95
+ * `ENV`, or supplied through `secrets`.
96
+ *
97
+ * @default - read from the container's own environment
98
+ */
99
+ readonly existingLoaderValue?: string;
100
+ }
101
+ /**
102
+ * Props for {@link OdigosFargateInstrumentation}.
103
+ */
104
+ export interface OdigosFargateInstrumentationProps extends OdigosFargateInstrumentationOptions {
105
+ /**
106
+ * Containers to instrument on construction. More can be added with `instrument()`.
107
+ *
108
+ * @default - none
109
+ */
110
+ readonly targets?: OdigosFargateTarget[];
111
+ }
112
+ /**
113
+ * Instruments ECS Fargate containers with the Odigos OpenTelemetry agents.
114
+ *
115
+ * ```ts
116
+ * const odigos = new OdigosFargateInstrumentation(this, 'Odigos', {
117
+ * destination: { httpEndpoint: 'https://otlp.example.com:4318' },
118
+ * });
119
+ * odigos.instrument({
120
+ * container: apiContainer,
121
+ * language: OdigosFargateLanguage.JAVA,
122
+ * service: apiService,
123
+ * });
124
+ * ```
125
+ *
126
+ * ## What it does to the task definition
127
+ *
128
+ * Four moves, which are one mechanism and only work together — the ECS adaptation of the Odikos
129
+ * init-container mount method:
130
+ *
131
+ * 1. a bare-name task volume (`odigos-agent`), which on Fargate is an ephemeral-storage bind mount
132
+ * scoped to the task;
133
+ * 2. a NON-ESSENTIAL `odigos-agent` container that copies the language agents out of the agents bundle
134
+ * into that volume and exits 0;
135
+ * 3. the volume mounted read-only at `/var/odigos` in each instrumented container, which depends on the
136
+ * staging container with condition `SUCCESS` — only valid against a non-essential container, which is
137
+ * why (2) is non-essential;
138
+ * 4. the language's activation environment, the OTLP export environment, and the `ODIGOS_IAC` marker on
139
+ * each instrumented container.
140
+ *
141
+ * There is ONE staging container per task definition however many languages the task holds; its command
142
+ * is the union of every instrumented container's agent directories, and it is built lazily so containers
143
+ * instrumented later are included.
144
+ *
145
+ * ## Where the telemetry goes
146
+ *
147
+ * Straight to your destination, from inside the application process. This is the substantive difference
148
+ * from Lambda: there is no collector in the task to hand a batch to, so a slow or unreachable destination
149
+ * is felt by the application's own exporter rather than absorbed after a response has been returned.
150
+ *
151
+ * ## What it deliberately does NOT do
152
+ *
153
+ * There is no aspect that sweeps a scope, as there is for Lambda. An aspect there works because a
154
+ * function DECLARES its runtime; a container declares an image, and a language guessed from an image name
155
+ * would silently mis-instrument the ones it got wrong — staging a Java agent into a Python container
156
+ * leaves it uninstrumented, and a `JAVA_TOOL_OPTIONS` on a JVM-less image is simply ignored, so nothing
157
+ * fails loudly enough to notice.
158
+ *
159
+ * ## Do not also instrument these services with the connector
160
+ *
161
+ * The connector instruments live services by registering a new task-definition revision and updating the
162
+ * service to it, reconciling to its own desired state on every pass. A service instrumented here and also
163
+ * enabled as a connector source ends up owned by both: each `cdk deploy` reasserts the stack's
164
+ * definition, each reconcile reasserts the connector's, and every round trip registers a revision and
165
+ * rolls the service. Choose one per service.
166
+ */
167
+ export declare class OdigosFargateInstrumentation extends Construct {
168
+ private readonly options;
169
+ private readonly agentsImage;
170
+ private readonly taskDefinitions;
171
+ private readonly instrumented;
172
+ constructor(scope: Construct, id: string, props: OdigosFargateInstrumentationProps);
173
+ /**
174
+ * Instruments one container. Idempotent — instrumenting the same container twice is a no-op rather than
175
+ * a doubled loader value.
176
+ */
177
+ instrument(target: OdigosFargateTarget): void;
178
+ /** Instruments every target in the list. */
179
+ instrumentAll(targets: OdigosFargateTarget[]): void;
180
+ /**
181
+ * The task definition's staging container and volume, created once and shared by every container in it.
182
+ *
183
+ * The command is a lazy list rather than a literal because the union it renders is not known until
184
+ * synthesis: a task definition holding a Java and a Python application is instrumented by two
185
+ * `instrument()` calls, and the single staging container has to stage both. The connector compares this
186
+ * command against exactly that union, so a stale one is reported as drift on the whole task definition
187
+ * and leaves one of the containers with no agent on disk.
188
+ */
189
+ private taskDefinitionState;
190
+ /**
191
+ * `OTEL_SERVICE_NAME` for a target, and the one value a caller cannot be allowed to leave to a default.
192
+ *
193
+ * The connector compares it against the workload's name in Odigos, which is the ECS SERVICE name, so
194
+ * guessing — the task definition family, the container name, the construct id — would produce a stack
195
+ * that deploys cleanly and then reports as drifted on a component nothing in the stack makes visible.
196
+ *
197
+ * Read from the L1, not from `service.serviceName`: the L2 property is a token that resolves to a `Ref`
198
+ * to the service even when the stack set the name explicitly, and a `Ref` here is worse than useless —
199
+ * the task definition would reference the service that references it, which CloudFormation rejects as a
200
+ * dependency cycle at deploy time.
201
+ */
202
+ private resolveServiceName;
203
+ /**
204
+ * Checks the task definition can carry the staged-agent method at all, and warns about the things that
205
+ * are legal but almost certainly a mistake.
206
+ */
207
+ private checkTaskDefinition;
208
+ /**
209
+ * The environment applied to one instrumented container.
210
+ *
211
+ * Mirrors `instrumentContainer` in the connector, including the ORDER of decisions: the agent's own
212
+ * activation variables first, then identity, then export, then the marker. Every variable here has a
213
+ * counterpart in the connector's `containerDiff`, which is what a customer's conformance report is
214
+ * built from — so one that is absent, or spelled differently, is reported as a named broken component
215
+ * rather than passing quietly.
216
+ */
217
+ private environmentFor;
218
+ }