Skip to content

Commit 1f44340

Browse files
authored
latest @opentelemetry packages and correlate external traces (#2334)
1 parent 7bb8845 commit 1f44340

File tree

47 files changed

+1262
-691
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1262
-691
lines changed

.changeset/five-nails-whisper.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
---
4+
5+
External Trace Correlation & OpenTelemetry Package Updates.
6+
7+
| Package | Previous Version | New Version | Change Type |
8+
|---------|------------------|-------------|-------------|
9+
| `@opentelemetry/api` | 1.9.0 | 1.9.0 | No change (stable API) |
10+
| `@opentelemetry/api-logs` | 0.52.1 | 0.203.0 | Major update |
11+
| `@opentelemetry/core` | - | 2.0.1 | New dependency |
12+
| `@opentelemetry/exporter-logs-otlp-http` | 0.52.1 | 0.203.0 | Major update |
13+
| `@opentelemetry/exporter-trace-otlp-http` | 0.52.1 | 0.203.0 | Major update |
14+
| `@opentelemetry/instrumentation` | 0.52.1 | 0.203.0 | Major update |
15+
| `@opentelemetry/instrumentation-fetch` | 0.52.1 | 0.203.0 | Major update |
16+
| `@opentelemetry/resources` | 1.25.1 | 2.0.1 | Major update |
17+
| `@opentelemetry/sdk-logs` | 0.52.1 | 0.203.0 | Major update |
18+
| `@opentelemetry/sdk-node` | 0.52.1 | - | Removed (functionality consolidated) |
19+
| `@opentelemetry/sdk-trace-base` | 1.25.1 | 2.0.1 | Major update |
20+
| `@opentelemetry/sdk-trace-node` | 1.25.1 | 2.0.1 | Major update |
21+
| `@opentelemetry/semantic-conventions` | 1.25.1 | 1.36.0 | Minor update |
22+
23+
### External trace correlation and propagation
24+
25+
We will now correlate your external traces with trigger.dev traces and logs when using our external exporters:
26+
27+
```ts
28+
import { defineConfig } from "@trigger.dev/sdk";
29+
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
30+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
31+
32+
export default defineConfig({
33+
project: process.env.TRIGGER_PROJECT_REF,
34+
dirs: ["./src/trigger"],
35+
telemetry: {
36+
logExporters: [
37+
new OTLPLogExporter({
38+
url: "https://api.axiom.co/v1/logs",
39+
headers: {
40+
Authorization: `Bearer ${process.env.AXIOM_TOKEN}`,
41+
"X-Axiom-Dataset": "test",
42+
},
43+
}),
44+
],
45+
exporters: [
46+
new OTLPTraceExporter({
47+
url: "https://api.axiom.co/v1/traces",
48+
headers: {
49+
Authorization: `Bearer ${process.env.AXIOM_TOKEN}`,
50+
"X-Axiom-Dataset": "test",
51+
},
52+
}),
53+
],
54+
},
55+
maxDuration: 3600,
56+
});
57+
```
58+
59+
You can also now propagate your external trace context when calling back into your own backend infra from inside a trigger.dev task:
60+
61+
```ts
62+
import { otel, task } from "@trigger.dev/sdk";
63+
import { context, propagation } from "@opentelemetry/api";
64+
65+
async function callNextjsApp() {
66+
return await otel.withExternalTrace(async () => {
67+
const headersObject = {};
68+
69+
// Now context.active() refers to your external trace context
70+
propagation.inject(context.active(), headersObject);
71+
72+
const result = await fetch("http://localhost:3000/api/demo-call-from-trigger", {
73+
headers: new Headers(headersObject),
74+
method: "POST",
75+
body: JSON.stringify({
76+
message: "Hello from Trigger.dev",
77+
}),
78+
});
79+
80+
return result.json();
81+
});
82+
}
83+
84+
export const myTask = task({
85+
id: "my-task",
86+
run: async (payload: any) => {
87+
await callNextjsApp()
88+
}
89+
})
90+
```
91+
92+

apps/webapp/app/presenters/v3/SpanPresenter.server.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import {
44
SemanticInternalAttributes,
55
TaskRunContext,
66
TaskRunError,
7+
TriggerTraceContext,
78
V3TaskRunContext,
89
} from "@trigger.dev/core/v3";
9-
import { AttemptId, getMaxDuration } from "@trigger.dev/core/v3/isomorphic";
10+
import { AttemptId, getMaxDuration, parseTraceparent } from "@trigger.dev/core/v3/isomorphic";
1011
import { RUNNING_STATUSES } from "~/components/runs/v3/TaskRunStatus";
1112
import { logger } from "~/services/logger.server";
1213
import { eventRepository, rehydrateAttribute } from "~/v3/eventRepository.server";
@@ -173,6 +174,8 @@ export class SpanPresenter extends BasePresenter {
173174

174175
const context = await this.#getTaskRunContext({ run, machine: machine ?? undefined });
175176

177+
const externalTraceId = this.#getExternalTraceId(run.traceContext);
178+
176179
return {
177180
id: run.id,
178181
friendlyId: run.friendlyId,
@@ -234,6 +237,7 @@ export class SpanPresenter extends BasePresenter {
234237
spanId: run.spanId,
235238
isCached: !!span.originalRun,
236239
machinePreset: machine?.name,
240+
externalTraceId,
237241
};
238242
}
239243

@@ -272,6 +276,7 @@ export class SpanPresenter extends BasePresenter {
272276
id: true,
273277
spanId: true,
274278
traceId: true,
279+
traceContext: true,
275280
//metadata
276281
number: true,
277282
taskIdentifier: true,
@@ -574,4 +579,26 @@ export class SpanPresenter extends BasePresenter {
574579
async #getV4TaskRunContext({ run }: { run: FindRunResult }): Promise<TaskRunContext> {
575580
return engine.resolveTaskRunContext(run.id);
576581
}
582+
583+
#getExternalTraceId(traceContext: unknown) {
584+
if (!traceContext) {
585+
return;
586+
}
587+
588+
const parsedTraceContext = TriggerTraceContext.safeParse(traceContext);
589+
590+
if (!parsedTraceContext.success) {
591+
return;
592+
}
593+
594+
const externalTraceparent = parsedTraceContext.data.external?.traceparent;
595+
596+
if (!externalTraceparent) {
597+
return;
598+
}
599+
600+
const parsedTraceparent = parseTraceparent(externalTraceparent);
601+
602+
return parsedTraceparent?.traceId;
603+
}
577604
}

apps/webapp/app/routes/api.v1.tasks.$taskId.trigger.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,9 @@ const { action, loader } = createActionApiRoute(
9393
const service = new TriggerTaskService();
9494

9595
try {
96-
const traceContext =
97-
traceparent && isFromWorker /// If the request is from a worker, we should pass the trace context
98-
? { traceparent, tracestate }
99-
: undefined;
96+
const traceContext = isFromWorker
97+
? { traceparent, tracestate }
98+
: { external: { traceparent, tracestate } };
10099

101100
const oneTimeUseToken = await getOneTimeUseToken(authentication);
102101

@@ -111,6 +110,14 @@ const { action, loader } = createActionApiRoute(
111110
traceContext,
112111
});
113112

113+
logger.debug("[otelContext]", {
114+
taskId: params.taskId,
115+
headers,
116+
options: body.options,
117+
isFromWorker,
118+
traceContext,
119+
});
120+
114121
const idempotencyKeyExpiresAt = resolveIdempotencyKeyTTL(idempotencyKeyTTL);
115122

116123
const result = await service.call(

apps/webapp/app/routes/api.v2.tasks.batch.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ const { action, loader } = createActionApiRoute(
103103
return cachedResponse;
104104
}
105105

106-
const traceContext =
107-
traceparent && isFromWorker // If the request is from a worker, we should pass the trace context
108-
? { traceparent, tracestate }
109-
: undefined;
106+
const traceContext = isFromWorker
107+
? { traceparent, tracestate }
108+
: { external: { traceparent, tracestate } };
110109

111110
const service = new RunEngineBatchTriggerService(batchProcessingStrategy ?? undefined);
112111

apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,6 +743,12 @@ function RunBody({
743743
<Property.Label>Run Engine</Property.Label>
744744
<Property.Value>{run.engine}</Property.Value>
745745
</Property.Item>
746+
{run.externalTraceId && (
747+
<Property.Item>
748+
<Property.Label>External Trace ID</Property.Label>
749+
<Property.Value>{run.externalTraceId}</Property.Value>
750+
</Property.Item>
751+
)}
746752
{isAdmin && (
747753
<div className="border-t border-yellow-500/50 pt-2">
748754
<Paragraph spacing variant="small" className="text-yellow-500">

apps/webapp/app/runEngine/services/batchTrigger.server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export type BatchProcessingOptions = z.infer<typeof BatchProcessingOptions>;
4242

4343
export type BatchTriggerTaskServiceOptions = {
4444
triggerVersion?: string;
45-
traceContext?: Record<string, string | undefined>;
45+
traceContext?: Record<string, string | undefined | Record<string, string | undefined>>;
4646
spanParentAsLink?: boolean;
4747
oneTimeUseToken?: string;
4848
};

apps/webapp/app/runEngine/services/triggerTask.server.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@ import {
1010
taskRunErrorEnhancer,
1111
taskRunErrorToString,
1212
TriggerTaskRequestBody,
13+
TriggerTraceContext,
1314
} from "@trigger.dev/core/v3";
14-
import { RunId, stringifyDuration } from "@trigger.dev/core/v3/isomorphic";
15+
import {
16+
parseTraceparent,
17+
RunId,
18+
serializeTraceparent,
19+
stringifyDuration,
20+
} from "@trigger.dev/core/v3/isomorphic";
1521
import type { PrismaClientOrTransaction } from "@trigger.dev/database";
1622
import { createTags } from "~/models/taskRunTag.server";
1723
import type { AuthenticatedEnvironment } from "~/services/apiAuth.server";
@@ -253,7 +259,11 @@ export class RunEngineTriggerTaskService {
253259
payload: payloadPacket.data ?? "",
254260
payloadType: payloadPacket.dataType,
255261
context: body.context,
256-
traceContext: event.traceContext,
262+
traceContext: this.#propagateExternalTraceContext(
263+
event.traceContext,
264+
parentRun?.traceContext,
265+
event.traceparent?.spanId
266+
),
257267
traceId: event.traceId,
258268
spanId: event.spanId,
259269
parentSpanId:
@@ -341,4 +351,49 @@ export class RunEngineTriggerTaskService {
341351
}
342352
});
343353
}
354+
355+
#propagateExternalTraceContext(
356+
traceContext: Record<string, unknown>,
357+
parentRunTraceContext: unknown,
358+
parentSpanId: string | undefined
359+
): TriggerTraceContext {
360+
if (!parentRunTraceContext) {
361+
return traceContext;
362+
}
363+
364+
const parsedParentRunTraceContext = TriggerTraceContext.safeParse(parentRunTraceContext);
365+
366+
if (!parsedParentRunTraceContext.success) {
367+
return traceContext;
368+
}
369+
370+
const { external } = parsedParentRunTraceContext.data;
371+
372+
if (!external) {
373+
return traceContext;
374+
}
375+
376+
if (!external.traceparent) {
377+
return traceContext;
378+
}
379+
380+
const parsedTraceparent = parseTraceparent(external.traceparent);
381+
382+
if (!parsedTraceparent) {
383+
return traceContext;
384+
}
385+
386+
const newExternalTraceparent = serializeTraceparent(
387+
parsedTraceparent.traceId,
388+
parentSpanId ?? parsedTraceparent.spanId
389+
);
390+
391+
return {
392+
...traceContext,
393+
external: {
394+
...external,
395+
traceparent: newExternalTraceparent,
396+
},
397+
};
398+
}
344399
}

apps/webapp/app/runEngine/types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export type TriggerTaskServiceOptions = {
1212
idempotencyKey?: string;
1313
idempotencyKeyExpiresAt?: Date;
1414
triggerVersion?: string;
15-
traceContext?: Record<string, string | undefined>;
15+
traceContext?: Record<string, unknown>;
1616
spanParentAsLink?: boolean;
1717
parentAsLinkType?: "replay" | "trigger";
1818
batchId?: string;
@@ -119,7 +119,7 @@ export interface TriggerTaskValidator {
119119
export type TracedEventSpan = {
120120
traceId: string;
121121
spanId: string;
122-
traceContext: Record<string, string | undefined>;
122+
traceContext: Record<string, unknown>;
123123
traceparent?: {
124124
traceId: string;
125125
spanId: string;

apps/webapp/app/v3/environmentVariableRules.server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ type VariableRule =
88
const blacklistedVariables: VariableRule[] = [
99
{ type: "exact", key: "TRIGGER_SECRET_KEY" },
1010
{ type: "exact", key: "TRIGGER_API_URL" },
11-
{ type: "prefix", prefix: "OTEL_" },
12-
{ type: "whitelist", key: "OTEL_LOG_LEVEL" },
1311
];
1412

1513
export function removeBlacklistedVariables(

0 commit comments

Comments
 (0)