autotel-cloudflare 2.18.3 → 2.18.5
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/README.md +64 -0
- package/dist/chunk-C3QLNZRK.js +63 -0
- package/dist/chunk-C3QLNZRK.js.map +1 -0
- package/dist/{chunk-WDNZVVRW.js → chunk-MIDMNKDC.js} +38 -2
- package/dist/chunk-MIDMNKDC.js.map +1 -0
- package/dist/handlers.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +37 -2
- package/dist/index.js.map +1 -1
- package/dist/logger-DGS3kP-A.d.ts +20 -0
- package/dist/logger.d.ts +2 -0
- package/dist/logger.js +1 -0
- package/dist/sampling.d.ts +0 -1
- package/package.json +12 -12
- package/src/execution-logger.test.ts +127 -0
- package/src/execution-logger.ts +112 -0
- package/src/handlers/workflows.test.ts +86 -0
- package/src/handlers/workflows.ts +47 -30
- package/src/index.ts +11 -0
- package/src/logger.ts +10 -1
- package/src/wrappers/cf-attributes.test.ts +59 -0
- package/src/wrappers/instrument.ts +55 -0
- package/dist/chunk-WDNZVVRW.js.map +0 -1
package/README.md
CHANGED
|
@@ -17,6 +17,16 @@
|
|
|
17
17
|
- ✅ **Tree-shakeable** - Import only what you need
|
|
18
18
|
- ✅ **TypeScript native** - Full type safety
|
|
19
19
|
|
|
20
|
+
## DX Direction
|
|
21
|
+
|
|
22
|
+
The package direction is to make Cloudflare observability feel the same across Workers, Queues, Durable Objects, alarms, and Workflows:
|
|
23
|
+
|
|
24
|
+
- use Cloudflare-native wrappers to create the root span
|
|
25
|
+
- use the `trace(..., (ctx) => ...)` factory form for business logic
|
|
26
|
+
- prefer span attributes and one execution snapshot over scattered info logs
|
|
27
|
+
|
|
28
|
+
See [docs/CLOUDFLARE-DX.md](../../docs/CLOUDFLARE-DX.md) for the design target and review rules.
|
|
29
|
+
|
|
20
30
|
## Installation
|
|
21
31
|
|
|
22
32
|
```bash
|
|
@@ -99,6 +109,35 @@ export default instrument(
|
|
|
99
109
|
)
|
|
100
110
|
```
|
|
101
111
|
|
|
112
|
+
### Fetch Route Controls
|
|
113
|
+
|
|
114
|
+
Filter which fetch routes are instrumented and map route patterns to service names:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
import { wrapModule } from 'autotel-cloudflare'
|
|
118
|
+
|
|
119
|
+
export default wrapModule(
|
|
120
|
+
{
|
|
121
|
+
service: { name: 'edge-gateway' },
|
|
122
|
+
handlers: {
|
|
123
|
+
fetch: {
|
|
124
|
+
include: ['/api/**'],
|
|
125
|
+
exclude: ['/api/internal/**', '/health'],
|
|
126
|
+
routes: {
|
|
127
|
+
'/api/auth/**': { service: 'auth-service' },
|
|
128
|
+
'/api/**': { service: 'api-service' },
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
async fetch(req) {
|
|
135
|
+
return new Response('ok')
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
102
141
|
### Style 3: Functional API (Unique)
|
|
103
142
|
|
|
104
143
|
Zero-boilerplate function tracing:
|
|
@@ -122,6 +161,31 @@ export const processPayment = trace(ctx => async (amount: number) => {
|
|
|
122
161
|
})
|
|
123
162
|
```
|
|
124
163
|
|
|
164
|
+
## Request Logger Bootstrap
|
|
165
|
+
|
|
166
|
+
Use `createWorkersLogger()` for request-scoped snapshots with Cloudflare context pre-filled.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { wrapModule, createWorkersLogger } from 'autotel-cloudflare'
|
|
170
|
+
|
|
171
|
+
export default wrapModule(
|
|
172
|
+
{ service: { name: 'checkout-worker' } },
|
|
173
|
+
{
|
|
174
|
+
async fetch(request) {
|
|
175
|
+
const log = createWorkersLogger(request, {
|
|
176
|
+
headers: ['x-request-id'],
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
log.info('checkout.started')
|
|
180
|
+
log.set({ checkout: { stage: 'validated' } })
|
|
181
|
+
log.emitNow({ status: 200 })
|
|
182
|
+
|
|
183
|
+
return new Response('ok')
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
|
|
125
189
|
## Complete Bindings Coverage
|
|
126
190
|
|
|
127
191
|
### Auto-Instrumented Bindings
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getExecutionLogger } from 'autotel-edge';
|
|
2
|
+
|
|
3
|
+
// src/execution-logger.ts
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function collectHeaders(headers, include) {
|
|
8
|
+
if (!include || include.length === 0) return void 0;
|
|
9
|
+
const allowlist = new Set(include.map((h) => h.toLowerCase()));
|
|
10
|
+
const out = {};
|
|
11
|
+
headers.forEach((value, key) => {
|
|
12
|
+
if (allowlist.has(key.toLowerCase())) {
|
|
13
|
+
out[key] = value;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
17
|
+
}
|
|
18
|
+
function pickCfContext(request) {
|
|
19
|
+
const cf = Reflect.get(request, "cf");
|
|
20
|
+
if (!isRecord(cf)) return {};
|
|
21
|
+
const out = {};
|
|
22
|
+
if (typeof cf.colo === "string") out.colo = cf.colo;
|
|
23
|
+
if (typeof cf.country === "string") out.country = cf.country;
|
|
24
|
+
if (typeof cf.asn === "number") out.asn = cf.asn;
|
|
25
|
+
if (typeof cf.city === "string") out.city = cf.city;
|
|
26
|
+
if (typeof cf.region === "string") out.region = cf.region;
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
function createWorkersLogger(request, options = {}, ctx) {
|
|
30
|
+
const log = getExecutionLogger(ctx);
|
|
31
|
+
const url = new URL(request.url);
|
|
32
|
+
const cfRay = request.headers.get("cf-ray") ?? void 0;
|
|
33
|
+
const traceparent = request.headers.get("traceparent") ?? void 0;
|
|
34
|
+
log.set({
|
|
35
|
+
request: {
|
|
36
|
+
method: request.method,
|
|
37
|
+
path: url.pathname,
|
|
38
|
+
url: request.url,
|
|
39
|
+
requestId: options.requestId ?? cfRay,
|
|
40
|
+
headers: collectHeaders(request.headers, options.headers)
|
|
41
|
+
},
|
|
42
|
+
cfRay,
|
|
43
|
+
traceparent,
|
|
44
|
+
...pickCfContext(request)
|
|
45
|
+
});
|
|
46
|
+
return log;
|
|
47
|
+
}
|
|
48
|
+
function getRequestLogger(ctx, options) {
|
|
49
|
+
return getExecutionLogger(ctx, options);
|
|
50
|
+
}
|
|
51
|
+
function getQueueLogger(ctx, options) {
|
|
52
|
+
return getExecutionLogger(ctx, options);
|
|
53
|
+
}
|
|
54
|
+
function getWorkflowLogger(ctx, options) {
|
|
55
|
+
return getExecutionLogger(ctx, options);
|
|
56
|
+
}
|
|
57
|
+
function getActorLogger(ctx, options) {
|
|
58
|
+
return getExecutionLogger(ctx, options);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { createWorkersLogger, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger };
|
|
62
|
+
//# sourceMappingURL=chunk-C3QLNZRK.js.map
|
|
63
|
+
//# sourceMappingURL=chunk-C3QLNZRK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/execution-logger.ts"],"names":[],"mappings":"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","file":"chunk-C3QLNZRK.js","sourcesContent":["import {\n type ExecutionLogger,\n type ExecutionLoggerOptions,\n type ExecutionLogSnapshot,\n getExecutionLogger,\n type TraceContext,\n} from 'autotel-edge';\n\nexport type {\n ExecutionLogger,\n ExecutionLoggerOptions,\n ExecutionLogSnapshot,\n};\n\nexport interface WorkersLoggerOptions {\n /** Override derived request id (default: cf-ray header value when present). */\n requestId?: string;\n /** Optional request header allowlist to include in logger context. */\n headers?: string[];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction collectHeaders(\n headers: Headers,\n include: string[] | undefined,\n): Record<string, string> | undefined {\n if (!include || include.length === 0) return undefined;\n\n const allowlist = new Set(include.map((h) => h.toLowerCase()));\n const out: Record<string, string> = {};\n headers.forEach((value, key) => {\n if (allowlist.has(key.toLowerCase())) {\n out[key] = value;\n }\n });\n\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction pickCfContext(request: Request): Record<string, unknown> {\n const cf = Reflect.get(request, 'cf');\n if (!isRecord(cf)) return {};\n\n const out: Record<string, unknown> = {};\n if (typeof cf.colo === 'string') out.colo = cf.colo;\n if (typeof cf.country === 'string') out.country = cf.country;\n if (typeof cf.asn === 'number') out.asn = cf.asn;\n if (typeof cf.city === 'string') out.city = cf.city;\n if (typeof cf.region === 'string') out.region = cf.region;\n return out;\n}\n\n/**\n * Create an execution logger pre-populated with common request context.\n * Best used from fetch handlers that already run inside autotel span context.\n */\nexport function createWorkersLogger(\n request: Request,\n options: WorkersLoggerOptions = {},\n ctx?: TraceContext,\n): ExecutionLogger {\n const log = getExecutionLogger(ctx);\n const url = new URL(request.url);\n const cfRay = request.headers.get('cf-ray') ?? undefined;\n const traceparent = request.headers.get('traceparent') ?? undefined;\n\n log.set({\n request: {\n method: request.method,\n path: url.pathname,\n url: request.url,\n requestId: options.requestId ?? cfRay,\n headers: collectHeaders(request.headers, options.headers),\n },\n cfRay,\n traceparent,\n ...pickCfContext(request),\n });\n\n return log;\n}\n\nexport function getRequestLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getQueueLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getWorkflowLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n\nexport function getActorLogger(\n ctx?: TraceContext,\n options?: ExecutionLoggerOptions,\n): ExecutionLogger {\n return getExecutionLogger(ctx, options);\n}\n"]}
|
|
@@ -209,6 +209,42 @@ function instrumentWorkflowStep(step, workflowName) {
|
|
|
209
209
|
}
|
|
210
210
|
});
|
|
211
211
|
}
|
|
212
|
+
if (prop === "sleepUntil" && typeof value === "function") {
|
|
213
|
+
return new Proxy(value, {
|
|
214
|
+
apply: (fnTarget, thisArg, args) => {
|
|
215
|
+
const [sleepName, timestamp] = args;
|
|
216
|
+
const tracer = trace.getTracer("autotel-edge");
|
|
217
|
+
const wakeAt = timestamp instanceof Date ? timestamp.toISOString() : new Date(timestamp).toISOString();
|
|
218
|
+
return tracer.startActiveSpan(
|
|
219
|
+
`Workflow ${workflowName}: sleepUntil ${sleepName}`,
|
|
220
|
+
{
|
|
221
|
+
kind: SpanKind.INTERNAL,
|
|
222
|
+
attributes: {
|
|
223
|
+
"workflow.sleep.name": sleepName,
|
|
224
|
+
"workflow.sleep.until": wakeAt,
|
|
225
|
+
"workflow.name": workflowName
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
async (span) => {
|
|
229
|
+
try {
|
|
230
|
+
const result = await Reflect.apply(fnTarget, thisArg, args);
|
|
231
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
232
|
+
return result;
|
|
233
|
+
} catch (error) {
|
|
234
|
+
span.recordException(error);
|
|
235
|
+
span.setStatus({
|
|
236
|
+
code: SpanStatusCode.ERROR,
|
|
237
|
+
message: error instanceof Error ? error.message : String(error)
|
|
238
|
+
});
|
|
239
|
+
throw error;
|
|
240
|
+
} finally {
|
|
241
|
+
span.end();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
212
248
|
if (typeof value === "function") {
|
|
213
249
|
return value.bind(target);
|
|
214
250
|
}
|
|
@@ -293,5 +329,5 @@ function instrumentWorkflow(workflowClass, workflowName, config) {
|
|
|
293
329
|
}
|
|
294
330
|
|
|
295
331
|
export { instrumentDO, instrumentWorkflow };
|
|
296
|
-
//# sourceMappingURL=chunk-
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
332
|
+
//# sourceMappingURL=chunk-MIDMNKDC.js.map
|
|
333
|
+
//# sourceMappingURL=chunk-MIDMNKDC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/handlers/durable-objects.ts","../src/handlers/workflows.ts"],"names":["api_context","context","coldStarts","isColdStart","trace","SpanKind","SpanStatusCode","createInitialiser","setConfig"],"mappings":"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","file":"chunk-MIDMNKDC.js","sourcesContent":["/**\n * Durable Objects instrumentation for Cloudflare Workers\n * \n * Note: This file uses Cloudflare Workers types (DurableObjectId, DurableObjectState, etc.)\n * which are globally available via @cloudflare/workers-types when listed in tsconfig.json.\n * These types are devDependencies only - they're not runtime dependencies.\n * At runtime, Cloudflare Workers runtime provides the actual implementations.\n */\n\nimport {\n trace,\n context as api_context,\n propagation,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { ConfigurationOption } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\n// Durable Object types\ntype DOFetchFn = (request: Request) => Response | Promise<Response>;\ntype DOAlarmFn = () => void | Promise<void>;\n\n/**\n * Track cold starts per DO class\n */\nconst coldStarts = new WeakMap<any, boolean>();\n\nfunction isColdStart(doClass: any): boolean {\n if (!coldStarts.has(doClass)) {\n coldStarts.set(doClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Instrument a Durable Object fetch method\n */\nfunction instrumentDOFetch(\n fetchFn: DOFetchFn,\n id: DurableObjectId,\n doClass: any,\n): DOFetchFn {\n return async function instrumentedFetch(\n this: any,\n request: Request,\n ): Promise<Response> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Extract parent context from request headers\n const parentContext = propagation.extract(\n api_context.active(),\n request.headers,\n );\n\n const url = new URL(request.url);\n const spanName = `DO ${id.name || id.toString()}: ${request.method} ${url.pathname}`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.SERVER,\n attributes: {\n 'http.request.method': request.method,\n 'url.full': request.url,\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'http',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n parentContext,\n async (span) => {\n try {\n const response = await fetchFn.call(this, request);\n\n span.setAttributes({\n 'http.response.status_code': response.status,\n });\n\n if (response.ok) {\n span.setStatus({ code: SpanStatusCode.OK });\n } else {\n span.setStatus({ code: SpanStatusCode.ERROR });\n }\n\n return response;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object alarm method\n */\nfunction instrumentDOAlarm(\n alarmFn: DOAlarmFn,\n id: DurableObjectId,\n doClass: any,\n): DOAlarmFn {\n return async function instrumentedAlarm(this: any): Promise<void> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n const spanName = `DO ${id.name || id.toString()}: alarm`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'do.id': id.toString(),\n 'do.id.name': id.name || '',\n 'faas.trigger': 'timer',\n 'faas.coldstart': isColdStart(doClass),\n },\n },\n async (span) => {\n try {\n await alarmFn.call(this);\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Durable Object instance\n */\nfunction instrumentDOInstance(\n doInstance: any,\n state: DurableObjectState,\n _env: any,\n doClass: any,\n): any {\n const instanceHandler: ProxyHandler<any> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'fetch' && typeof value === 'function') {\n return instrumentDOFetch(value.bind(target), state.id, doClass);\n }\n\n if (prop === 'alarm' && typeof value === 'function') {\n return instrumentDOAlarm(value.bind(target), state.id, doClass);\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(doInstance, instanceHandler);\n}\n\n/**\n * Instrument a Durable Object class\n *\n * This wraps the DO class to automatically trace all fetch and alarm calls,\n * as well as initialize the telemetry configuration.\n *\n * **Usage:**\n * ```typescript\n * import { DurableObject } from 'cloudflare:workers'\n * import { instrumentDO } from 'autotel-edge'\n *\n * export class Counter extends DurableObject<Env> {\n * async fetch(request: Request) {\n * // Your DO logic here\n * return new Response('OK')\n * }\n * }\n *\n * // Wrap the class before exporting\n * export const CounterDO = instrumentDO(Counter, (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'my-durable-object',\n * version: '1.0.0'\n * }\n * }))\n * ```\n *\n * **What you get:**\n * - 🎯 Automatic spans for fetch() calls with HTTP attributes\n * - ⏰ Automatic spans for alarm() calls\n * - 🥶 Cold start tracking\n * - 🔗 Context propagation from incoming requests\n * - ⚡ Automatic span lifecycle management\n *\n * @param doClass - The Durable Object class to instrument\n * @param config - Configuration or configuration function\n * @returns Instrumented Durable Object class\n */\nexport function instrumentDO<C extends new (state: DurableObjectState, env: any) => any>(\n doClass: C,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, [state, env]: [DurableObjectState, any]) {\n // Initialize config for this DO instance\n const trigger = {\n id: state.id.toString(),\n name: state.id.name,\n };\n const doConfig = initialiser(env, trigger);\n const context = setConfig(doConfig);\n\n // Create the DO instance within the config context\n const doInstance = api_context.with(context, () => {\n return new target(state, env);\n });\n\n // Instrument the instance\n return instrumentDOInstance(doInstance, state, env, doClass);\n },\n };\n\n return wrap(doClass, classHandler);\n}\n","/**\n * Cloudflare Workflows instrumentation for autotel-edge\n *\n * Instruments WorkflowEntrypoint classes to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * Based on Cloudflare Workflows API:\n * https://developers.cloudflare.com/workflows/\n */\n\nimport {\n trace,\n context as api_context,\n SpanStatusCode,\n SpanKind,\n} from '@opentelemetry/api';\nimport type { WorkflowEvent, WorkflowStep } from 'cloudflare:workers';\nimport type { ConfigurationOption, WorkflowTrigger } from 'autotel-edge';\nimport { createInitialiser, setConfig, WorkerTracer } from 'autotel-edge';\nimport { wrap } from '../bindings/common';\n\ntype WorkflowRunFn = (\n event: Readonly<WorkflowEvent<unknown>>,\n step: WorkflowStep,\n) => Promise<unknown> | void;\n\n/**\n * Track cold starts per Workflow class\n */\nconst coldStarts = new WeakMap<object, boolean>();\n\nfunction isColdStart(workflowClass: object): boolean {\n if (!coldStarts.has(workflowClass)) {\n coldStarts.set(workflowClass, true);\n return true;\n }\n return false;\n}\n\n/**\n * Proxy the step object to instrument step.do(), step.sleep(), and step.sleepUntil() calls\n */\nfunction instrumentWorkflowStep(\n step: WorkflowStep,\n workflowName: string,\n): WorkflowStep {\n const stepHandler: ProxyHandler<WorkflowStep> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n // Instrument step.do() to create spans for each workflow step\n if (prop === 'do' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [stepName] = args as [string, ...unknown[]];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: ${stepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.step.name': stepName,\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Instrument step.sleep() to track workflow delays\n if (prop === 'sleep' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [sleepName, duration] = args as [string, string | number];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: sleep ${sleepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.sleep.name': sleepName,\n 'workflow.sleep.duration': String(duration),\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n if (prop === 'sleepUntil' && typeof value === 'function') {\n return new Proxy(value, {\n apply: (fnTarget, thisArg, args) => {\n const [sleepName, timestamp] = args as [string, Date | number];\n\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n const wakeAt =\n timestamp instanceof Date\n ? timestamp.toISOString()\n : new Date(timestamp).toISOString();\n\n return tracer.startActiveSpan(\n `Workflow ${workflowName}: sleepUntil ${sleepName}`,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.sleep.name': sleepName,\n 'workflow.sleep.until': wakeAt,\n 'workflow.name': workflowName,\n },\n },\n async (span) => {\n try {\n const result = await Reflect.apply(fnTarget, thisArg, args);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message:\n error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n },\n });\n }\n\n // Pass through other step methods\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(step, stepHandler);\n}\n\n/**\n * Instrument a Workflow run method\n */\nfunction instrumentWorkflowRun(\n runFn: WorkflowRunFn,\n workflowName: string,\n workflowClass: object,\n): WorkflowRunFn {\n return async function instrumentedRun(\n this: unknown,\n event: Readonly<WorkflowEvent<unknown>>,\n step: WorkflowStep,\n ): Promise<unknown> {\n const tracer = trace.getTracer('autotel-edge') as WorkerTracer;\n\n // Instrument the step object to track individual operations\n const instrumentedStep = instrumentWorkflowStep(step, workflowName);\n\n const spanName = `Workflow ${workflowName}: run`;\n\n return tracer.startActiveSpan(\n spanName,\n {\n kind: SpanKind.INTERNAL,\n attributes: {\n 'workflow.name': workflowName,\n 'workflow.instance_id': event.instanceId,\n 'faas.trigger': 'workflow',\n 'faas.coldstart': isColdStart(workflowClass),\n },\n },\n async (span) => {\n try {\n const result = await runFn.call(this, event, instrumentedStep);\n span.setStatus({ code: SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.recordException(error as Error);\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n throw error;\n } finally {\n span.end();\n }\n },\n );\n };\n}\n\n/**\n * Instrument a Workflow instance\n */\nfunction instrumentWorkflowInstance(\n workflowInstance: Record<string, unknown>,\n workflowName: string,\n workflowClass: object,\n): Record<string, unknown> {\n const instanceHandler: ProxyHandler<Record<string, unknown>> = {\n get(target, prop) {\n const value = Reflect.get(target, prop);\n\n if (prop === 'run' && typeof value === 'function') {\n return instrumentWorkflowRun(\n value.bind(target) as WorkflowRunFn,\n workflowName,\n workflowClass,\n );\n }\n\n // Bind other methods to the target\n if (typeof value === 'function') {\n return value.bind(target);\n }\n\n return value;\n },\n };\n\n return wrap(workflowInstance, instanceHandler);\n}\n\n/**\n * Instrument a Cloudflare Workflow class\n *\n * This wraps the WorkflowEntrypoint class to automatically trace workflow execution,\n * step operations, retries, and sleeps.\n *\n * **Usage:**\n * ```typescript\n * import { WorkflowEntrypoint } from 'cloudflare:workers'\n * import { instrumentWorkflow } from 'autotel-cloudflare/handlers'\n *\n * class MyWorkflow extends WorkflowEntrypoint {\n * async run(event, step) {\n * await step.do('submit payment', async () => {\n * return await submitToPaymentProcessor(event.payload.payment)\n * })\n *\n * await step.sleep('wait for feedback', '2 days')\n *\n * await step.do('send feedback email', sendFeedbackEmail)\n * }\n * }\n *\n * export const CheckoutWorkflow = instrumentWorkflow(\n * MyWorkflow,\n * 'checkout-workflow',\n * (env: Env) => ({\n * exporter: {\n * url: env.OTLP_ENDPOINT,\n * headers: { 'x-api-key': env.API_KEY }\n * },\n * service: {\n * name: 'checkout-workflow',\n * version: '1.0.0'\n * }\n * })\n * )\n * ```\n *\n * @param workflowClass - The WorkflowEntrypoint class to instrument\n * @param workflowName - The name of the workflow (used in span names)\n * @param config - Configuration or configuration function\n * @returns Instrumented Workflow class\n */\nexport function instrumentWorkflow<\n C extends new (...args: any[]) => any,\n>(\n workflowClass: C,\n workflowName: string,\n config: ConfigurationOption,\n): C {\n const initialiser = createInitialiser(config);\n\n const classHandler: ProxyHandler<C> = {\n construct(target, args: any[]) {\n // Extract env from constructor args (typically last arg)\n const env = args[args.length - 1] || {};\n\n const trigger: WorkflowTrigger = { type: 'workflow', name: workflowName };\n const workflowConfig = initialiser(env, trigger);\n const context = setConfig(workflowConfig);\n\n // Create the workflow instance within the config context\n const workflowInstance = api_context.with(context, () => {\n return new target(...args);\n });\n\n // Instrument the instance\n return instrumentWorkflowInstance(\n workflowInstance,\n workflowName,\n workflowClass,\n );\n },\n };\n\n return wrap(workflowClass, classHandler);\n}\n"]}
|
package/dist/handlers.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { ConfigurationOption } from 'autotel-edge';
|
|
2
2
|
export * from 'autotel-edge';
|
|
3
|
+
export { ExecutionLogSnapshot, ExecutionLogger, ExecutionLoggerOptions } from 'autotel-edge';
|
|
4
|
+
export { W as WorkersLoggerOptions, c as createWorkersLogger, g as getActorLogger, a as getQueueLogger, b as getRequestLogger, d as getWorkflowLogger } from './logger-DGS3kP-A.js';
|
|
3
5
|
export { instrumentDO, instrumentWorkflow } from './handlers.js';
|
|
4
6
|
export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './bindings.js';
|
|
7
|
+
import 'autotel-edge/logger';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Handler instrumentation for Cloudflare Workers
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { instrumentBindings } from './chunk-KAUHT25H.js';
|
|
2
2
|
export { instrumentAI, instrumentAnalyticsEngine, instrumentBindings, instrumentBrowserRendering, instrumentD1, instrumentHyperdrive, instrumentImages, instrumentKV, instrumentQueueProducer, instrumentR2, instrumentRateLimiter, instrumentServiceBinding, instrumentVectorize } from './chunk-KAUHT25H.js';
|
|
3
|
-
import { instrumentDO } from './chunk-
|
|
4
|
-
export { instrumentDO, instrumentWorkflow } from './chunk-
|
|
3
|
+
import { instrumentDO } from './chunk-MIDMNKDC.js';
|
|
4
|
+
export { instrumentDO, instrumentWorkflow } from './chunk-MIDMNKDC.js';
|
|
5
|
+
export { createWorkersLogger, getActorLogger, getQueueLogger, getRequestLogger, getWorkflowLogger } from './chunk-C3QLNZRK.js';
|
|
5
6
|
import { wrap, unwrap, proxyExecutionContext } from './chunk-O4IYKWPJ.js';
|
|
6
7
|
import { createInitialiser, getActiveConfig, setConfig, WorkerTracerProvider, WorkerTracer } from 'autotel-edge';
|
|
7
8
|
export * from 'autotel-edge';
|
|
@@ -176,6 +177,28 @@ function instrumentGlobalCache() {
|
|
|
176
177
|
}
|
|
177
178
|
|
|
178
179
|
// src/wrappers/instrument.ts
|
|
180
|
+
function matchesPattern(path, pattern) {
|
|
181
|
+
const regexPattern = pattern.replaceAll(/[.+^${}()|[\]\\]/g, String.raw`\$&`).replaceAll("**", "{{GLOBSTAR}}").replaceAll("*", "[^/]*").replaceAll("{{GLOBSTAR}}", ".*").replaceAll("?", "[^/]");
|
|
182
|
+
return new RegExp(`^${regexPattern}$`).test(path);
|
|
183
|
+
}
|
|
184
|
+
function shouldInstrumentPath(path, include, exclude) {
|
|
185
|
+
if (exclude && exclude.some((pattern) => matchesPattern(path, pattern))) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
if (!include || include.length === 0) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
return include.some((pattern) => matchesPattern(path, pattern));
|
|
192
|
+
}
|
|
193
|
+
function getServiceForPath(path, routes) {
|
|
194
|
+
if (!routes) return void 0;
|
|
195
|
+
for (const [pattern, config] of Object.entries(routes)) {
|
|
196
|
+
if (matchesPattern(path, pattern)) {
|
|
197
|
+
return config.service;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return void 0;
|
|
201
|
+
}
|
|
179
202
|
function extractCfAttributes(request) {
|
|
180
203
|
const cf = request.cf;
|
|
181
204
|
if (!cf) return {};
|
|
@@ -206,6 +229,10 @@ function createFetchInstrumentation(config) {
|
|
|
206
229
|
return {
|
|
207
230
|
getInitialSpanInfo: (request) => {
|
|
208
231
|
const url = new URL(request.url);
|
|
232
|
+
const routeService = getServiceForPath(
|
|
233
|
+
url.pathname,
|
|
234
|
+
config.handlers.fetch.routes
|
|
235
|
+
);
|
|
209
236
|
const cfAttrs = config.extractCfAttributes === false ? {} : extractCfAttributes(request);
|
|
210
237
|
return {
|
|
211
238
|
name: `${request.method} ${url.pathname}`,
|
|
@@ -214,6 +241,7 @@ function createFetchInstrumentation(config) {
|
|
|
214
241
|
attributes: {
|
|
215
242
|
"http.request.method": request.method,
|
|
216
243
|
"url.full": request.url,
|
|
244
|
+
...routeService ? { "service.name": routeService, "autotel.route.service": routeService } : {},
|
|
217
245
|
...cfAttrs
|
|
218
246
|
}
|
|
219
247
|
},
|
|
@@ -525,6 +553,13 @@ function createHandlerProxyWithConfig(_handler, handlerFn, initialiser, createIn
|
|
|
525
553
|
if (config.instrumentation.disabled) {
|
|
526
554
|
return handlerFn(trigger, env, ctx);
|
|
527
555
|
}
|
|
556
|
+
if (trigger instanceof Request) {
|
|
557
|
+
const pathname = new URL(trigger.url).pathname;
|
|
558
|
+
const fetchCfg = config.handlers.fetch;
|
|
559
|
+
if (!shouldInstrumentPath(pathname, fetchCfg.include, fetchCfg.exclude)) {
|
|
560
|
+
return handlerFn(trigger, env, ctx);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
528
563
|
const instrumentedEnv = instrumentBindings(env);
|
|
529
564
|
const configContext = setConfig(config);
|
|
530
565
|
initProvider(config);
|