autotel-cloudflare 3.1.0 → 4.0.0
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/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +7 -0
- package/dist/agents.js.map +1 -1
- package/package.json +8 -4
- package/src/actors/alarms.ts +0 -225
- package/src/actors/index.ts +0 -36
- package/src/actors/instrument-actor.test.ts +0 -179
- package/src/actors/instrument-actor.ts +0 -574
- package/src/actors/sockets.ts +0 -217
- package/src/actors/storage.ts +0 -263
- package/src/actors/traced-handler.ts +0 -300
- package/src/actors/types.ts +0 -98
- package/src/actors.ts +0 -50
- package/src/agents/agent.ts +0 -327
- package/src/agents/base.ts +0 -26
- package/src/agents/index.ts +0 -46
- package/src/agents/mcp.ts +0 -38
- package/src/agents/observability.ts +0 -145
- package/src/agents/otel-observability.test.ts +0 -269
- package/src/agents/otel-observability.ts +0 -557
- package/src/agents/types.ts +0 -61
- package/src/agents.ts +0 -87
- package/src/bindings/ai.test.ts +0 -170
- package/src/bindings/ai.ts +0 -73
- package/src/bindings/analytics-engine.test.ts +0 -175
- package/src/bindings/analytics-engine.ts +0 -78
- package/src/bindings/bindings-cache.test.ts +0 -80
- package/src/bindings/bindings-detection.test.ts +0 -235
- package/src/bindings/bindings-this-binding.test.ts +0 -294
- package/src/bindings/bindings.ts +0 -720
- package/src/bindings/browser-rendering.test.ts +0 -160
- package/src/bindings/browser-rendering.ts +0 -70
- package/src/bindings/common.ts +0 -84
- package/src/bindings/hyperdrive.test.ts +0 -176
- package/src/bindings/hyperdrive.ts +0 -74
- package/src/bindings/images.test.ts +0 -262
- package/src/bindings/images.ts +0 -182
- package/src/bindings/index.ts +0 -20
- package/src/bindings/queue-producer.test.ts +0 -224
- package/src/bindings/queue-producer.ts +0 -105
- package/src/bindings/rate-limiter.test.ts +0 -140
- package/src/bindings/rate-limiter.ts +0 -69
- package/src/bindings/vectorize.test.ts +0 -362
- package/src/bindings/vectorize.ts +0 -86
- package/src/bindings.ts +0 -6
- package/src/events.ts +0 -6
- package/src/execution-logger.test.ts +0 -127
- package/src/execution-logger.ts +0 -112
- package/src/global/cache.test.ts +0 -292
- package/src/global/cache.ts +0 -164
- package/src/global/fetch.test.ts +0 -399
- package/src/global/fetch.ts +0 -136
- package/src/global/index.ts +0 -7
- package/src/handlers/durable-objects.test.ts +0 -524
- package/src/handlers/durable-objects.ts +0 -250
- package/src/handlers/index.ts +0 -6
- package/src/handlers/workflows.test.ts +0 -411
- package/src/handlers/workflows.ts +0 -345
- package/src/handlers.ts +0 -6
- package/src/index.ts +0 -91
- package/src/logger.ts +0 -15
- package/src/native/native-tracing.test.ts +0 -54
- package/src/native/native-tracing.ts +0 -83
- package/src/native.ts +0 -12
- package/src/parse-error.ts +0 -1
- package/src/sampling.ts +0 -6
- package/src/testing.ts +0 -6
- package/src/wrappers/cf-attributes.test.ts +0 -334
- package/src/wrappers/define-worker-fetch.test.ts +0 -102
- package/src/wrappers/define-worker-fetch.ts +0 -71
- package/src/wrappers/index.ts +0 -13
- package/src/wrappers/instrument.integration.test.ts +0 -578
- package/src/wrappers/instrument.ts +0 -806
- package/src/wrappers/native-instrument.test.ts +0 -153
- package/src/wrappers/wrap-do.ts +0 -34
- package/src/wrappers/wrap-module.ts +0 -37
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cloudflare Workflows instrumentation for autotel-edge
|
|
3
|
-
*
|
|
4
|
-
* Instruments WorkflowEntrypoint classes to automatically trace workflow execution,
|
|
5
|
-
* step operations, retries, and sleeps.
|
|
6
|
-
*
|
|
7
|
-
* Based on Cloudflare Workflows API:
|
|
8
|
-
* https://developers.cloudflare.com/workflows/
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
trace,
|
|
13
|
-
context as api_context,
|
|
14
|
-
SpanStatusCode,
|
|
15
|
-
SpanKind,
|
|
16
|
-
} from '@opentelemetry/api';
|
|
17
|
-
import type { WorkflowEvent, WorkflowStep } from 'cloudflare:workers';
|
|
18
|
-
import type { ConfigurationOption, WorkflowTrigger } from 'autotel-edge';
|
|
19
|
-
import { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';
|
|
20
|
-
import { wrap } from '../bindings/common';
|
|
21
|
-
|
|
22
|
-
type WorkflowRunFn = (
|
|
23
|
-
event: Readonly<WorkflowEvent<unknown>>,
|
|
24
|
-
step: WorkflowStep,
|
|
25
|
-
) => Promise<unknown> | void;
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Track cold starts per Workflow class
|
|
29
|
-
*/
|
|
30
|
-
const coldStarts = new WeakMap<object, boolean>();
|
|
31
|
-
|
|
32
|
-
function isColdStart(workflowClass: object): boolean {
|
|
33
|
-
if (!coldStarts.has(workflowClass)) {
|
|
34
|
-
coldStarts.set(workflowClass, true);
|
|
35
|
-
return true;
|
|
36
|
-
}
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Proxy the step object to instrument step.do(), step.sleep(), and step.sleepUntil() calls
|
|
42
|
-
*/
|
|
43
|
-
function instrumentWorkflowStep(
|
|
44
|
-
step: WorkflowStep,
|
|
45
|
-
workflowName: string,
|
|
46
|
-
): WorkflowStep {
|
|
47
|
-
const stepHandler: ProxyHandler<WorkflowStep> = {
|
|
48
|
-
get(target, prop) {
|
|
49
|
-
const value = Reflect.get(target, prop);
|
|
50
|
-
|
|
51
|
-
// Instrument step.do() to create spans for each workflow step
|
|
52
|
-
if (prop === 'do' && typeof value === 'function') {
|
|
53
|
-
return new Proxy(value, {
|
|
54
|
-
apply: (fnTarget, thisArg, args) => {
|
|
55
|
-
const [stepName] = args as [string, ...unknown[]];
|
|
56
|
-
|
|
57
|
-
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
|
|
58
|
-
|
|
59
|
-
return tracer.startActiveSpan(
|
|
60
|
-
`Workflow ${workflowName}: ${stepName}`,
|
|
61
|
-
{
|
|
62
|
-
kind: SpanKind.INTERNAL,
|
|
63
|
-
attributes: {
|
|
64
|
-
'workflow.step.name': stepName,
|
|
65
|
-
'workflow.name': workflowName,
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
async (span) => {
|
|
69
|
-
try {
|
|
70
|
-
const result = await Reflect.apply(fnTarget, thisArg, args);
|
|
71
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
72
|
-
return result;
|
|
73
|
-
} catch (error) {
|
|
74
|
-
span.recordException(error as Error);
|
|
75
|
-
span.setStatus({
|
|
76
|
-
code: SpanStatusCode.ERROR,
|
|
77
|
-
message:
|
|
78
|
-
error instanceof Error ? error.message : String(error),
|
|
79
|
-
});
|
|
80
|
-
throw error;
|
|
81
|
-
} finally {
|
|
82
|
-
span.end();
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
);
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Instrument step.sleep() to track workflow delays
|
|
91
|
-
if (prop === 'sleep' && typeof value === 'function') {
|
|
92
|
-
return new Proxy(value, {
|
|
93
|
-
apply: (fnTarget, thisArg, args) => {
|
|
94
|
-
const [sleepName, duration] = args as [string, string | number];
|
|
95
|
-
|
|
96
|
-
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
|
|
97
|
-
|
|
98
|
-
return tracer.startActiveSpan(
|
|
99
|
-
`Workflow ${workflowName}: sleep ${sleepName}`,
|
|
100
|
-
{
|
|
101
|
-
kind: SpanKind.INTERNAL,
|
|
102
|
-
attributes: {
|
|
103
|
-
'workflow.sleep.name': sleepName,
|
|
104
|
-
'workflow.sleep.duration': String(duration),
|
|
105
|
-
'workflow.name': workflowName,
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
async (span) => {
|
|
109
|
-
try {
|
|
110
|
-
const result = await Reflect.apply(fnTarget, thisArg, args);
|
|
111
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
112
|
-
return result;
|
|
113
|
-
} catch (error) {
|
|
114
|
-
span.recordException(error as Error);
|
|
115
|
-
span.setStatus({
|
|
116
|
-
code: SpanStatusCode.ERROR,
|
|
117
|
-
message:
|
|
118
|
-
error instanceof Error ? error.message : String(error),
|
|
119
|
-
});
|
|
120
|
-
throw error;
|
|
121
|
-
} finally {
|
|
122
|
-
span.end();
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
);
|
|
126
|
-
},
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (prop === 'sleepUntil' && typeof value === 'function') {
|
|
131
|
-
return new Proxy(value, {
|
|
132
|
-
apply: (fnTarget, thisArg, args) => {
|
|
133
|
-
const [sleepName, timestamp] = args as [string, Date | number];
|
|
134
|
-
|
|
135
|
-
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
|
|
136
|
-
const wakeAt =
|
|
137
|
-
timestamp instanceof Date
|
|
138
|
-
? timestamp.toISOString()
|
|
139
|
-
: new Date(timestamp).toISOString();
|
|
140
|
-
|
|
141
|
-
return tracer.startActiveSpan(
|
|
142
|
-
`Workflow ${workflowName}: sleepUntil ${sleepName}`,
|
|
143
|
-
{
|
|
144
|
-
kind: SpanKind.INTERNAL,
|
|
145
|
-
attributes: {
|
|
146
|
-
'workflow.sleep.name': sleepName,
|
|
147
|
-
'workflow.sleep.until': wakeAt,
|
|
148
|
-
'workflow.name': workflowName,
|
|
149
|
-
},
|
|
150
|
-
},
|
|
151
|
-
async (span) => {
|
|
152
|
-
try {
|
|
153
|
-
const result = await Reflect.apply(fnTarget, thisArg, args);
|
|
154
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
155
|
-
return result;
|
|
156
|
-
} catch (error) {
|
|
157
|
-
span.recordException(error as Error);
|
|
158
|
-
span.setStatus({
|
|
159
|
-
code: SpanStatusCode.ERROR,
|
|
160
|
-
message:
|
|
161
|
-
error instanceof Error ? error.message : String(error),
|
|
162
|
-
});
|
|
163
|
-
throw error;
|
|
164
|
-
} finally {
|
|
165
|
-
span.end();
|
|
166
|
-
}
|
|
167
|
-
},
|
|
168
|
-
);
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Pass through other step methods
|
|
174
|
-
if (typeof value === 'function') {
|
|
175
|
-
return value.bind(target);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return value;
|
|
179
|
-
},
|
|
180
|
-
};
|
|
181
|
-
|
|
182
|
-
return wrap(step, stepHandler);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Instrument a Workflow run method
|
|
187
|
-
*/
|
|
188
|
-
function instrumentWorkflowRun(
|
|
189
|
-
runFn: WorkflowRunFn,
|
|
190
|
-
workflowName: string,
|
|
191
|
-
workflowClass: object,
|
|
192
|
-
): WorkflowRunFn {
|
|
193
|
-
return async function instrumentedRun(
|
|
194
|
-
this: unknown,
|
|
195
|
-
event: Readonly<WorkflowEvent<unknown>>,
|
|
196
|
-
step: WorkflowStep,
|
|
197
|
-
): Promise<unknown> {
|
|
198
|
-
const tracer = trace.getTracer('autotel-edge') as WorkerTracer;
|
|
199
|
-
|
|
200
|
-
// Instrument the step object to track individual operations
|
|
201
|
-
const instrumentedStep = instrumentWorkflowStep(step, workflowName);
|
|
202
|
-
|
|
203
|
-
const spanName = `Workflow ${workflowName}: run`;
|
|
204
|
-
|
|
205
|
-
return tracer.startActiveSpan(
|
|
206
|
-
spanName,
|
|
207
|
-
{
|
|
208
|
-
kind: SpanKind.INTERNAL,
|
|
209
|
-
attributes: {
|
|
210
|
-
'workflow.name': workflowName,
|
|
211
|
-
'workflow.instance_id': event.instanceId,
|
|
212
|
-
'faas.trigger': 'workflow',
|
|
213
|
-
'faas.coldstart': isColdStart(workflowClass),
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
async (span) => {
|
|
217
|
-
try {
|
|
218
|
-
const result = await runFn.call(this, event, instrumentedStep);
|
|
219
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
220
|
-
return result;
|
|
221
|
-
} catch (error) {
|
|
222
|
-
span.recordException(error as Error);
|
|
223
|
-
span.setStatus({
|
|
224
|
-
code: SpanStatusCode.ERROR,
|
|
225
|
-
message: error instanceof Error ? error.message : String(error),
|
|
226
|
-
});
|
|
227
|
-
throw error;
|
|
228
|
-
} finally {
|
|
229
|
-
span.end();
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
);
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Instrument a Workflow instance
|
|
238
|
-
*/
|
|
239
|
-
function instrumentWorkflowInstance(
|
|
240
|
-
workflowInstance: Record<string, unknown>,
|
|
241
|
-
workflowName: string,
|
|
242
|
-
workflowClass: object,
|
|
243
|
-
): Record<string, unknown> {
|
|
244
|
-
const instanceHandler: ProxyHandler<Record<string, unknown>> = {
|
|
245
|
-
get(target, prop) {
|
|
246
|
-
const value = Reflect.get(target, prop);
|
|
247
|
-
|
|
248
|
-
if (prop === 'run' && typeof value === 'function') {
|
|
249
|
-
return instrumentWorkflowRun(
|
|
250
|
-
value.bind(target) as WorkflowRunFn,
|
|
251
|
-
workflowName,
|
|
252
|
-
workflowClass,
|
|
253
|
-
);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Bind other methods to the target
|
|
257
|
-
if (typeof value === 'function') {
|
|
258
|
-
return value.bind(target);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return value;
|
|
262
|
-
},
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
return wrap(workflowInstance, instanceHandler);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Instrument a Cloudflare Workflow class
|
|
270
|
-
*
|
|
271
|
-
* This wraps the WorkflowEntrypoint class to automatically trace workflow execution,
|
|
272
|
-
* step operations, retries, and sleeps.
|
|
273
|
-
*
|
|
274
|
-
* **Usage:**
|
|
275
|
-
* ```typescript
|
|
276
|
-
* import { WorkflowEntrypoint } from 'cloudflare:workers'
|
|
277
|
-
* import { instrumentWorkflow } from 'autotel-cloudflare/handlers'
|
|
278
|
-
*
|
|
279
|
-
* class MyWorkflow extends WorkflowEntrypoint {
|
|
280
|
-
* async run(event, step) {
|
|
281
|
-
* await step.do('submit payment', async () => {
|
|
282
|
-
* return await submitToPaymentProcessor(event.payload.payment)
|
|
283
|
-
* })
|
|
284
|
-
*
|
|
285
|
-
* await step.sleep('wait for feedback', '2 days')
|
|
286
|
-
*
|
|
287
|
-
* await step.do('send feedback email', sendFeedbackEmail)
|
|
288
|
-
* }
|
|
289
|
-
* }
|
|
290
|
-
*
|
|
291
|
-
* export const CheckoutWorkflow = instrumentWorkflow(
|
|
292
|
-
* MyWorkflow,
|
|
293
|
-
* 'checkout-workflow',
|
|
294
|
-
* (env: Env) => ({
|
|
295
|
-
* exporter: {
|
|
296
|
-
* url: env.OTLP_ENDPOINT,
|
|
297
|
-
* headers: { 'x-api-key': env.API_KEY }
|
|
298
|
-
* },
|
|
299
|
-
* service: {
|
|
300
|
-
* name: 'checkout-workflow',
|
|
301
|
-
* version: '1.0.0'
|
|
302
|
-
* }
|
|
303
|
-
* })
|
|
304
|
-
* )
|
|
305
|
-
* ```
|
|
306
|
-
*
|
|
307
|
-
* @param workflowClass - The WorkflowEntrypoint class to instrument
|
|
308
|
-
* @param workflowName - The name of the workflow (used in span names)
|
|
309
|
-
* @param config - Configuration or configuration function
|
|
310
|
-
* @returns Instrumented Workflow class
|
|
311
|
-
*/
|
|
312
|
-
export function instrumentWorkflow<
|
|
313
|
-
C extends new (...args: any[]) => any,
|
|
314
|
-
>(
|
|
315
|
-
workflowClass: C,
|
|
316
|
-
workflowName: string,
|
|
317
|
-
config: ConfigurationOption,
|
|
318
|
-
): C {
|
|
319
|
-
const initialiser = createInitialiser(config);
|
|
320
|
-
|
|
321
|
-
const classHandler: ProxyHandler<C> = {
|
|
322
|
-
construct(target, args: any[]) {
|
|
323
|
-
// Extract env from constructor args (typically last arg)
|
|
324
|
-
const env = args[args.length - 1] || {};
|
|
325
|
-
|
|
326
|
-
const trigger: WorkflowTrigger = { type: 'workflow', name: workflowName };
|
|
327
|
-
const workflowConfig = initialiser(env, trigger);
|
|
328
|
-
const context = setConfig(workflowConfig);
|
|
329
|
-
|
|
330
|
-
// Create the workflow instance within the config context
|
|
331
|
-
const workflowInstance = api_context.with(context, () => {
|
|
332
|
-
return new target(...args);
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
// Instrument the instance
|
|
336
|
-
return instrumentWorkflowInstance(
|
|
337
|
-
workflowInstance,
|
|
338
|
-
workflowName,
|
|
339
|
-
workflowClass,
|
|
340
|
-
);
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
return wrap(workflowClass, classHandler);
|
|
345
|
-
}
|
package/src/handlers.ts
DELETED
package/src/index.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* autotel-cloudflare
|
|
3
|
-
*
|
|
4
|
-
* The #1 OpenTelemetry package for Cloudflare Workers
|
|
5
|
-
*
|
|
6
|
-
* Features:
|
|
7
|
-
* - Native Cloudflare OTel integration (works with wrangler.toml destinations)
|
|
8
|
-
* - Complete bindings coverage (KV, R2, D1, DO, AI, Vectorize, etc.)
|
|
9
|
-
* - Multiple API styles (instrument, wrapModule, functional)
|
|
10
|
-
* - Advanced sampling strategies
|
|
11
|
-
* - Events integration
|
|
12
|
-
* - Zero vendor lock-in (OTLP compatible)
|
|
13
|
-
*
|
|
14
|
-
* @example Quick Start
|
|
15
|
-
* ```typescript
|
|
16
|
-
* import { wrapModule, trace } from 'autotel-cloudflare'
|
|
17
|
-
*
|
|
18
|
-
* const processOrder = trace(async (orderId: string) => {
|
|
19
|
-
* const order = await env.ORDERS_KV.get(orderId)
|
|
20
|
-
* return order
|
|
21
|
-
* })
|
|
22
|
-
*
|
|
23
|
-
* export default wrapModule(
|
|
24
|
-
* {
|
|
25
|
-
* service: { name: 'my-worker' },
|
|
26
|
-
* instrumentBindings: true,
|
|
27
|
-
* sampling: 'adaptive'
|
|
28
|
-
* },
|
|
29
|
-
* {
|
|
30
|
-
* async fetch(req, env, ctx) {
|
|
31
|
-
* return Response.json(await processOrder('123'))
|
|
32
|
-
* }
|
|
33
|
-
* }
|
|
34
|
-
* )
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
// Re-export EVERYTHING from autotel-edge (vendor-agnostic foundation)
|
|
39
|
-
export * from 'autotel-edge';
|
|
40
|
-
export {
|
|
41
|
-
getRequestLogger,
|
|
42
|
-
getQueueLogger,
|
|
43
|
-
getWorkflowLogger,
|
|
44
|
-
getActorLogger,
|
|
45
|
-
createWorkersLogger,
|
|
46
|
-
type ExecutionLogger,
|
|
47
|
-
type ExecutionLoggerOptions,
|
|
48
|
-
type ExecutionLogSnapshot,
|
|
49
|
-
type WorkersLoggerOptions,
|
|
50
|
-
} from './execution-logger';
|
|
51
|
-
|
|
52
|
-
// Cloudflare-specific wrappers
|
|
53
|
-
export {
|
|
54
|
-
instrument,
|
|
55
|
-
wrapModule,
|
|
56
|
-
wrapDurableObject,
|
|
57
|
-
defineWorkerFetch,
|
|
58
|
-
type DefineWorkerFetchOptions,
|
|
59
|
-
type WorkerFetchHandler,
|
|
60
|
-
} from './wrappers';
|
|
61
|
-
|
|
62
|
-
// Cloudflare-specific handlers
|
|
63
|
-
export { instrumentDO, instrumentWorkflow } from './handlers';
|
|
64
|
-
|
|
65
|
-
// Cloudflare-specific bindings
|
|
66
|
-
export {
|
|
67
|
-
instrumentKV,
|
|
68
|
-
instrumentR2,
|
|
69
|
-
instrumentD1,
|
|
70
|
-
instrumentServiceBinding,
|
|
71
|
-
instrumentBindings,
|
|
72
|
-
instrumentAI,
|
|
73
|
-
instrumentVectorize,
|
|
74
|
-
instrumentHyperdrive,
|
|
75
|
-
instrumentQueueProducer,
|
|
76
|
-
instrumentAnalyticsEngine,
|
|
77
|
-
instrumentImages,
|
|
78
|
-
instrumentRateLimiter,
|
|
79
|
-
instrumentBrowserRendering,
|
|
80
|
-
} from './bindings';
|
|
81
|
-
|
|
82
|
-
// Global instrumentations
|
|
83
|
-
export { instrumentGlobalFetch, instrumentGlobalCache } from './global';
|
|
84
|
-
|
|
85
|
-
// Cloudflare native tracing helpers (auto-wired by the handler wrappers;
|
|
86
|
-
// exported for manual detection). `enterSpan` is re-exported from autotel-edge
|
|
87
|
-
// above via `export * from 'autotel-edge'`.
|
|
88
|
-
export {
|
|
89
|
-
isNativeTracingAvailable,
|
|
90
|
-
getNativeTracerFromCtx,
|
|
91
|
-
} from './native/native-tracing';
|
package/src/logger.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Logger entry point
|
|
3
|
-
* Entry point: autotel-cloudflare/logger
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export * from 'autotel-edge/logger';
|
|
7
|
-
export {
|
|
8
|
-
getRequestLogger,
|
|
9
|
-
getQueueLogger,
|
|
10
|
-
getWorkflowLogger,
|
|
11
|
-
getActorLogger,
|
|
12
|
-
type ExecutionLogger,
|
|
13
|
-
type ExecutionLoggerOptions,
|
|
14
|
-
type ExecutionLogSnapshot,
|
|
15
|
-
} from './execution-logger';
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
-
import {
|
|
3
|
-
isNativeTracingAvailable,
|
|
4
|
-
getNativeTracerFromCtx,
|
|
5
|
-
} from './native-tracing';
|
|
6
|
-
|
|
7
|
-
function ctxWithTracing() {
|
|
8
|
-
const enterSpan = vi.fn((_name: string, cb: (s: any) => unknown) =>
|
|
9
|
-
cb({ isTraced: true, setAttribute: vi.fn() }),
|
|
10
|
-
);
|
|
11
|
-
return { tracing: { enterSpan }, waitUntil() {}, passThroughOnException() {} };
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
describe('isNativeTracingAvailable', () => {
|
|
15
|
-
it('is true when ctx.tracing.enterSpan is a function', () => {
|
|
16
|
-
expect(isNativeTracingAvailable(ctxWithTracing())).toBe(true);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('is false for a plain ExecutionContext (tracing disabled / old runtime)', () => {
|
|
20
|
-
expect(isNativeTracingAvailable({ waitUntil() {} })).toBe(false);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it('is false for null/undefined or malformed tracing', () => {
|
|
24
|
-
expect(isNativeTracingAvailable(undefined)).toBe(false);
|
|
25
|
-
expect(isNativeTracingAvailable(null)).toBe(false);
|
|
26
|
-
expect(isNativeTracingAvailable({ tracing: {} })).toBe(false);
|
|
27
|
-
expect(isNativeTracingAvailable({ tracing: { enterSpan: 123 } })).toBe(false);
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
describe('getNativeTracerFromCtx', () => {
|
|
32
|
-
it('returns null when native tracing is unavailable', () => {
|
|
33
|
-
expect(getNativeTracerFromCtx({ waitUntil() {} })).toBeNull();
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it('wraps ctx.tracing.enterSpan as a NativeTracer', () => {
|
|
37
|
-
const ctx = ctxWithTracing();
|
|
38
|
-
const tracer = getNativeTracerFromCtx(ctx);
|
|
39
|
-
expect(tracer).not.toBeNull();
|
|
40
|
-
|
|
41
|
-
const result = tracer!.enterSpan('work', (span) => {
|
|
42
|
-
span.setAttribute('k', 'v');
|
|
43
|
-
return 7;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
expect(result).toBe(7);
|
|
47
|
-
expect(ctx.tracing.enterSpan).toHaveBeenCalledWith('work', expect.any(Function));
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it('attaches the supplied correlation id to the tracer', () => {
|
|
51
|
-
const tracer = getNativeTracerFromCtx(ctxWithTracing(), 'ray-xyz');
|
|
52
|
-
expect(tracer?.correlationId).toBe('ray-xyz');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cloudflare native tracing adapter
|
|
3
|
-
*
|
|
4
|
-
* Bridges Cloudflare Workers' built-in custom-span API
|
|
5
|
-
* (`ctx.tracing.enterSpan()` / `import { tracing } from "cloudflare:workers"`)
|
|
6
|
-
* to autotel-edge's runtime-agnostic {@link NativeTracer} seam.
|
|
7
|
-
*
|
|
8
|
-
* When a Worker has tracing enabled (`observability.traces.enabled = true` in
|
|
9
|
-
* Wrangler) the runtime exposes `ctx.tracing`. The handler wrappers detect it,
|
|
10
|
-
* wrap it as a {@link NativeTracer}, and install it into the active context with
|
|
11
|
-
* `withNativeTracer()`. From then on every autotel `span()` / `trace()` /
|
|
12
|
-
* `enterSpan()` call — including deep inside utility functions and libraries —
|
|
13
|
-
* automatically routes to Cloudflare's native tracer and nests inside the
|
|
14
|
-
* platform's trace waterfall (fetch / KV / R2 / D1 / handler spans), exported
|
|
15
|
-
* by Cloudflare to whichever destination is configured in Wrangler.
|
|
16
|
-
*
|
|
17
|
-
* No `cloudflare:workers` import is required here: the native tracer travels
|
|
18
|
-
* through autotel's AsyncLocalStorage context, so code without access to `ctx`
|
|
19
|
-
* still picks it up via `getActiveNativeTracer()`.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import type { NativeTracer, NativeSpanHandle } from 'autotel-edge';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Cloudflare's native custom-span surface. Declared locally because it is not
|
|
26
|
-
* yet present in `@cloudflare/workers-types`. Structurally compatible with
|
|
27
|
-
* autotel-edge's {@link NativeSpanHandle}.
|
|
28
|
-
*/
|
|
29
|
-
interface CloudflareSpan {
|
|
30
|
-
readonly isTraced: boolean;
|
|
31
|
-
setAttribute(key: string, value: string | number | boolean | undefined): void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Cloudflare's `tracing` object, available as `ctx.tracing` on the
|
|
36
|
-
* ExecutionContext and as the `tracing` export of `cloudflare:workers`.
|
|
37
|
-
*/
|
|
38
|
-
interface CloudflareTracing {
|
|
39
|
-
enterSpan<T, A extends unknown[]>(
|
|
40
|
-
name: string,
|
|
41
|
-
callback: (span: CloudflareSpan, ...args: A) => T,
|
|
42
|
-
...args: A
|
|
43
|
-
): T;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type MaybeTracingCarrier = { tracing?: CloudflareTracing } | null | undefined;
|
|
47
|
-
|
|
48
|
-
function readTracing(carrier: unknown): CloudflareTracing | undefined {
|
|
49
|
-
const tracing = (carrier as MaybeTracingCarrier)?.tracing;
|
|
50
|
-
return typeof tracing?.enterSpan === 'function' ? tracing : undefined;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Returns `true` when Cloudflare native custom-span tracing is available on the
|
|
55
|
-
* given ExecutionContext (i.e. tracing is enabled for this Worker).
|
|
56
|
-
*/
|
|
57
|
-
export function isNativeTracingAvailable(ctx: unknown): boolean {
|
|
58
|
-
return readTracing(ctx) !== undefined;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Wrap Cloudflare's `ctx.tracing` as an autotel {@link NativeTracer}, or return
|
|
63
|
-
* `null` when native tracing is unavailable on this context.
|
|
64
|
-
*
|
|
65
|
-
* @param correlationId Optional per-request id (e.g. the `cf-ray` header)
|
|
66
|
-
* surfaced as `ctx.correlationId` and a `correlation.id` span attribute, so
|
|
67
|
-
* logs, custom spans, and the Cloudflare dashboard share one queryable key
|
|
68
|
-
* today — before Cloudflare exposes in-code trace/span ids.
|
|
69
|
-
*/
|
|
70
|
-
export function getNativeTracerFromCtx(
|
|
71
|
-
ctx: unknown,
|
|
72
|
-
correlationId?: string,
|
|
73
|
-
): NativeTracer | null {
|
|
74
|
-
const tracing = readTracing(ctx);
|
|
75
|
-
if (!tracing) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
return {
|
|
79
|
-
correlationId,
|
|
80
|
-
enterSpan: <T>(name: string, callback: (span: NativeSpanHandle) => T): T =>
|
|
81
|
-
tracing.enterSpan(name, callback as (span: CloudflareSpan) => T),
|
|
82
|
-
};
|
|
83
|
-
}
|
package/src/native.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* autotel-cloudflare/native
|
|
3
|
-
*
|
|
4
|
-
* Cloudflare native tracing helpers. Most users never need this entry point —
|
|
5
|
-
* the handler wrappers (`instrument`, `wrapModule`, `defineWorkerFetch`,
|
|
6
|
-
* `wrapDurableObject`) auto-detect and wire up native tracing for you. Import
|
|
7
|
-
* from here only when you want to detect native tracing yourself.
|
|
8
|
-
*/
|
|
9
|
-
export {
|
|
10
|
-
isNativeTracingAvailable,
|
|
11
|
-
getNativeTracerFromCtx,
|
|
12
|
-
} from './native/native-tracing';
|
package/src/parse-error.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { parseError, type ParsedError } from 'autotel-edge/parse-error';
|
package/src/sampling.ts
DELETED