autotel-cloudflare 2.18.18 → 2.19.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/actors.d.ts +54 -89
- package/dist/actors.d.ts.map +1 -0
- package/dist/actors.js +990 -986
- package/dist/actors.js.map +1 -1
- package/dist/agents.d.ts +102 -128
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +275 -259
- package/dist/agents.js.map +1 -1
- package/dist/bindings-C10RI6Il.js +975 -0
- package/dist/bindings-C10RI6Il.js.map +1 -0
- package/dist/bindings-xEZcXo5r.d.ts +149 -0
- package/dist/bindings-xEZcXo5r.d.ts.map +1 -0
- package/dist/bindings.d.ts +2 -139
- package/dist/bindings.js +3 -4
- package/dist/common-DiWH6nmG.js +63 -0
- package/dist/common-DiWH6nmG.js.map +1 -0
- package/dist/events.d.ts +1 -1
- package/dist/events.js +3 -3
- package/dist/execution-logger-BxmgP8jF.js +65 -0
- package/dist/execution-logger-BxmgP8jF.js.map +1 -0
- package/dist/{logger-Cm_73k3-.d.ts → execution-logger-tgQmJeeU.d.ts} +9 -7
- package/dist/execution-logger-tgQmJeeU.d.ts.map +1 -0
- package/dist/handlers-CMg9l_T-.js +378 -0
- package/dist/handlers-CMg9l_T-.js.map +1 -0
- package/dist/handlers-C_VojUeA.d.ts +96 -0
- package/dist/handlers-C_VojUeA.d.ts.map +1 -0
- package/dist/handlers.d.ts +2 -112
- package/dist/handlers.js +3 -4
- package/dist/index.d.ts +20 -99
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +644 -600
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +3 -3
- package/dist/logger.js +5 -4
- package/dist/parse-error.d.ts +2 -1
- package/dist/parse-error.js +3 -3
- package/dist/sampling.d.ts +1 -4
- package/dist/sampling.js +3 -3
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +3 -3
- package/package.json +6 -6
- package/src/bindings/ai.test.ts +1 -1
- package/src/bindings/ai.ts +3 -1
- package/dist/bindings.js.map +0 -1
- package/dist/chunk-KAUHT25H.js +0 -1084
- package/dist/chunk-KAUHT25H.js.map +0 -1
- package/dist/chunk-MIDMNKDC.js +0 -333
- package/dist/chunk-MIDMNKDC.js.map +0 -1
- package/dist/chunk-O4IYKWPJ.js +0 -55
- package/dist/chunk-O4IYKWPJ.js.map +0 -1
- package/dist/chunk-RVVMMPWN.js +0 -63
- package/dist/chunk-RVVMMPWN.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/handlers.js.map +0 -1
- package/dist/logger.js.map +0 -1
- package/dist/parse-error.js.map +0 -1
- package/dist/sampling.js.map +0 -1
- package/dist/testing.js.map +0 -1
package/dist/actors.js
CHANGED
|
@@ -1,1030 +1,1034 @@
|
|
|
1
|
-
import { wrap } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { a as wrap } from "./common-DiWH6nmG.js";
|
|
2
|
+
import { createInitialiser, setConfig } from "autotel-edge";
|
|
3
|
+
import { SpanKind, SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
//#region src/actors/storage.ts
|
|
6
|
+
/**
|
|
7
|
+
* Actor storage instrumentation
|
|
8
|
+
*
|
|
9
|
+
* Traces operations on actor.storage including SQL queries
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Get the tracer instance
|
|
13
|
+
*/
|
|
14
|
+
function getTracer$4() {
|
|
15
|
+
return trace.getTracer("autotel-cloudflare-actors");
|
|
7
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Instrument Actor storage for tracing
|
|
19
|
+
*
|
|
20
|
+
* Captures:
|
|
21
|
+
* - SQL query operations
|
|
22
|
+
* - Key-value operations (if available)
|
|
23
|
+
*/
|
|
8
24
|
function instrumentActorStorage(storage, actorInstance, actorClass) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
return tracer.startActiveSpan(
|
|
167
|
-
spanName,
|
|
168
|
-
{
|
|
169
|
-
kind: SpanKind.CLIENT,
|
|
170
|
-
attributes: {
|
|
171
|
-
"actor.name": actorName,
|
|
172
|
-
"actor.class": actorClassName,
|
|
173
|
-
"db.system": "durable_object_storage",
|
|
174
|
-
"db.operation": "delete",
|
|
175
|
-
"db.key": key
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
async (span) => {
|
|
179
|
-
try {
|
|
180
|
-
const result = await value.call(target, key);
|
|
181
|
-
span.setAttributes({
|
|
182
|
-
"db.result.deleted": result
|
|
183
|
-
});
|
|
184
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
185
|
-
return result;
|
|
186
|
-
} catch (error) {
|
|
187
|
-
span.recordException(error);
|
|
188
|
-
span.setStatus({
|
|
189
|
-
code: SpanStatusCode.ERROR,
|
|
190
|
-
message: error instanceof Error ? error.message : String(error)
|
|
191
|
-
});
|
|
192
|
-
throw error;
|
|
193
|
-
} finally {
|
|
194
|
-
span.end();
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
);
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
if (typeof value === "function") {
|
|
201
|
-
return value.bind(target);
|
|
202
|
-
}
|
|
203
|
-
return value;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
return wrap(storage, storageHandler);
|
|
25
|
+
if (!storage || typeof storage !== "object") return storage;
|
|
26
|
+
const actorClassName = actorClass.name || "Actor";
|
|
27
|
+
const actorName = actorInstance.name || actorClassName;
|
|
28
|
+
return wrap(storage, { get(target, prop) {
|
|
29
|
+
const value = Reflect.get(target, prop);
|
|
30
|
+
if (prop === "exec" && typeof value === "function") return function instrumentedExec(query, ...params) {
|
|
31
|
+
const tracer = getTracer$4();
|
|
32
|
+
const spanName = `Actor ${actorName}: storage.exec`;
|
|
33
|
+
return tracer.startActiveSpan(spanName, {
|
|
34
|
+
kind: SpanKind.CLIENT,
|
|
35
|
+
attributes: {
|
|
36
|
+
"actor.name": actorName,
|
|
37
|
+
"actor.class": actorClassName,
|
|
38
|
+
"db.system": "sqlite",
|
|
39
|
+
"db.operation": "exec",
|
|
40
|
+
"db.statement": query,
|
|
41
|
+
"db.statement.params_count": params.length
|
|
42
|
+
}
|
|
43
|
+
}, (span) => {
|
|
44
|
+
try {
|
|
45
|
+
const result = value.call(target, query, ...params);
|
|
46
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
47
|
+
return result;
|
|
48
|
+
} catch (error) {
|
|
49
|
+
span.recordException(error);
|
|
50
|
+
span.setStatus({
|
|
51
|
+
code: SpanStatusCode.ERROR,
|
|
52
|
+
message: error instanceof Error ? error.message : String(error)
|
|
53
|
+
});
|
|
54
|
+
throw error;
|
|
55
|
+
} finally {
|
|
56
|
+
span.end();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
if (prop === "query" && typeof value === "function") return function instrumentedQuery(query, ...params) {
|
|
61
|
+
const tracer = getTracer$4();
|
|
62
|
+
const spanName = `Actor ${actorName}: storage.query`;
|
|
63
|
+
return tracer.startActiveSpan(spanName, {
|
|
64
|
+
kind: SpanKind.CLIENT,
|
|
65
|
+
attributes: {
|
|
66
|
+
"actor.name": actorName,
|
|
67
|
+
"actor.class": actorClassName,
|
|
68
|
+
"db.system": "sqlite",
|
|
69
|
+
"db.operation": "query",
|
|
70
|
+
"db.statement": query,
|
|
71
|
+
"db.statement.params_count": params.length
|
|
72
|
+
}
|
|
73
|
+
}, (span) => {
|
|
74
|
+
try {
|
|
75
|
+
const result = value.call(target, query, ...params);
|
|
76
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
77
|
+
return result;
|
|
78
|
+
} catch (error) {
|
|
79
|
+
span.recordException(error);
|
|
80
|
+
span.setStatus({
|
|
81
|
+
code: SpanStatusCode.ERROR,
|
|
82
|
+
message: error instanceof Error ? error.message : String(error)
|
|
83
|
+
});
|
|
84
|
+
throw error;
|
|
85
|
+
} finally {
|
|
86
|
+
span.end();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
if (prop === "get" && typeof value === "function") return async function instrumentedGet(key) {
|
|
91
|
+
const tracer = getTracer$4();
|
|
92
|
+
const spanName = `Actor ${actorName}: storage.get`;
|
|
93
|
+
return tracer.startActiveSpan(spanName, {
|
|
94
|
+
kind: SpanKind.CLIENT,
|
|
95
|
+
attributes: {
|
|
96
|
+
"actor.name": actorName,
|
|
97
|
+
"actor.class": actorClassName,
|
|
98
|
+
"db.system": "durable_object_storage",
|
|
99
|
+
"db.operation": "get",
|
|
100
|
+
"db.key": key
|
|
101
|
+
}
|
|
102
|
+
}, async (span) => {
|
|
103
|
+
try {
|
|
104
|
+
const result = await value.call(target, key);
|
|
105
|
+
span.setAttributes({ "db.result.found": result !== null && result !== void 0 });
|
|
106
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
107
|
+
return result;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
span.recordException(error);
|
|
110
|
+
span.setStatus({
|
|
111
|
+
code: SpanStatusCode.ERROR,
|
|
112
|
+
message: error instanceof Error ? error.message : String(error)
|
|
113
|
+
});
|
|
114
|
+
throw error;
|
|
115
|
+
} finally {
|
|
116
|
+
span.end();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
if (prop === "put" && typeof value === "function") return async function instrumentedPut(key, val) {
|
|
121
|
+
const tracer = getTracer$4();
|
|
122
|
+
const spanName = `Actor ${actorName}: storage.put`;
|
|
123
|
+
return tracer.startActiveSpan(spanName, {
|
|
124
|
+
kind: SpanKind.CLIENT,
|
|
125
|
+
attributes: {
|
|
126
|
+
"actor.name": actorName,
|
|
127
|
+
"actor.class": actorClassName,
|
|
128
|
+
"db.system": "durable_object_storage",
|
|
129
|
+
"db.operation": "put",
|
|
130
|
+
"db.key": key,
|
|
131
|
+
"db.value_type": typeof val
|
|
132
|
+
}
|
|
133
|
+
}, async (span) => {
|
|
134
|
+
try {
|
|
135
|
+
await value.call(target, key, val);
|
|
136
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
137
|
+
} catch (error) {
|
|
138
|
+
span.recordException(error);
|
|
139
|
+
span.setStatus({
|
|
140
|
+
code: SpanStatusCode.ERROR,
|
|
141
|
+
message: error instanceof Error ? error.message : String(error)
|
|
142
|
+
});
|
|
143
|
+
throw error;
|
|
144
|
+
} finally {
|
|
145
|
+
span.end();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
if (prop === "delete" && typeof value === "function") return async function instrumentedDelete(key) {
|
|
150
|
+
const tracer = getTracer$4();
|
|
151
|
+
const spanName = `Actor ${actorName}: storage.delete`;
|
|
152
|
+
return tracer.startActiveSpan(spanName, {
|
|
153
|
+
kind: SpanKind.CLIENT,
|
|
154
|
+
attributes: {
|
|
155
|
+
"actor.name": actorName,
|
|
156
|
+
"actor.class": actorClassName,
|
|
157
|
+
"db.system": "durable_object_storage",
|
|
158
|
+
"db.operation": "delete",
|
|
159
|
+
"db.key": key
|
|
160
|
+
}
|
|
161
|
+
}, async (span) => {
|
|
162
|
+
try {
|
|
163
|
+
const result = await value.call(target, key);
|
|
164
|
+
span.setAttributes({ "db.result.deleted": result });
|
|
165
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
166
|
+
return result;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
span.recordException(error);
|
|
169
|
+
span.setStatus({
|
|
170
|
+
code: SpanStatusCode.ERROR,
|
|
171
|
+
message: error instanceof Error ? error.message : String(error)
|
|
172
|
+
});
|
|
173
|
+
throw error;
|
|
174
|
+
} finally {
|
|
175
|
+
span.end();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
if (typeof value === "function") return value.bind(target);
|
|
180
|
+
return value;
|
|
181
|
+
} });
|
|
207
182
|
}
|
|
208
|
-
|
|
209
|
-
|
|
183
|
+
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region src/actors/alarms.ts
|
|
186
|
+
/**
|
|
187
|
+
* Actor alarms instrumentation
|
|
188
|
+
*
|
|
189
|
+
* Traces operations on actor.alarms
|
|
190
|
+
*/
|
|
191
|
+
/**
|
|
192
|
+
* Get the tracer instance
|
|
193
|
+
*/
|
|
194
|
+
function getTracer$3() {
|
|
195
|
+
return trace.getTracer("autotel-cloudflare-actors");
|
|
210
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* Instrument Actor alarms for tracing
|
|
199
|
+
*
|
|
200
|
+
* Captures:
|
|
201
|
+
* - set: Schedule a single alarm
|
|
202
|
+
* - setMultiple: Schedule multiple alarms
|
|
203
|
+
* - cancel: Cancel an alarm
|
|
204
|
+
* - cancelAll: Cancel all alarms
|
|
205
|
+
*/
|
|
211
206
|
function instrumentActorAlarms(alarms, actorInstance, actorClass) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
spanName,
|
|
338
|
-
{
|
|
339
|
-
kind: SpanKind.CLIENT,
|
|
340
|
-
attributes: {
|
|
341
|
-
"actor.name": actorName,
|
|
342
|
-
"actor.class": actorClassName,
|
|
343
|
-
"alarm.operation": "cancelAll"
|
|
344
|
-
}
|
|
345
|
-
},
|
|
346
|
-
async (span) => {
|
|
347
|
-
try {
|
|
348
|
-
const result = await value.call(target);
|
|
349
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
350
|
-
return result;
|
|
351
|
-
} catch (error) {
|
|
352
|
-
span.recordException(error);
|
|
353
|
-
span.setStatus({
|
|
354
|
-
code: SpanStatusCode.ERROR,
|
|
355
|
-
message: error instanceof Error ? error.message : String(error)
|
|
356
|
-
});
|
|
357
|
-
throw error;
|
|
358
|
-
} finally {
|
|
359
|
-
span.end();
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
);
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
if (typeof value === "function") {
|
|
366
|
-
return value.bind(target);
|
|
367
|
-
}
|
|
368
|
-
return value;
|
|
369
|
-
}
|
|
370
|
-
};
|
|
371
|
-
return wrap(alarms, alarmsHandler);
|
|
207
|
+
if (!alarms || typeof alarms !== "object") return alarms;
|
|
208
|
+
const actorClassName = actorClass.name || "Actor";
|
|
209
|
+
const actorName = actorInstance.name || actorClassName;
|
|
210
|
+
return wrap(alarms, { get(target, prop) {
|
|
211
|
+
const value = Reflect.get(target, prop);
|
|
212
|
+
if (prop === "set" && typeof value === "function") return async function instrumentedSet(...args) {
|
|
213
|
+
const tracer = getTracer$3();
|
|
214
|
+
const spanName = `Actor ${actorName}: alarms.set`;
|
|
215
|
+
const alarmAttributes = {
|
|
216
|
+
"actor.name": actorName,
|
|
217
|
+
"actor.class": actorClassName,
|
|
218
|
+
"alarm.operation": "set"
|
|
219
|
+
};
|
|
220
|
+
if (args.length > 0) {
|
|
221
|
+
const firstArg = args[0];
|
|
222
|
+
if (typeof firstArg === "number") alarmAttributes["alarm.delay_ms"] = firstArg;
|
|
223
|
+
else if (firstArg instanceof Date) alarmAttributes["alarm.scheduled_time"] = firstArg.toISOString();
|
|
224
|
+
else if (typeof firstArg === "string") alarmAttributes["alarm.cron"] = firstArg;
|
|
225
|
+
}
|
|
226
|
+
return tracer.startActiveSpan(spanName, {
|
|
227
|
+
kind: SpanKind.CLIENT,
|
|
228
|
+
attributes: alarmAttributes
|
|
229
|
+
}, async (span) => {
|
|
230
|
+
try {
|
|
231
|
+
const result = await value.apply(target, args);
|
|
232
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
233
|
+
return result;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
span.recordException(error);
|
|
236
|
+
span.setStatus({
|
|
237
|
+
code: SpanStatusCode.ERROR,
|
|
238
|
+
message: error instanceof Error ? error.message : String(error)
|
|
239
|
+
});
|
|
240
|
+
throw error;
|
|
241
|
+
} finally {
|
|
242
|
+
span.end();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
if (prop === "setMultiple" && typeof value === "function") return async function instrumentedSetMultiple(alarmDefs) {
|
|
247
|
+
const tracer = getTracer$3();
|
|
248
|
+
const spanName = `Actor ${actorName}: alarms.setMultiple`;
|
|
249
|
+
return tracer.startActiveSpan(spanName, {
|
|
250
|
+
kind: SpanKind.CLIENT,
|
|
251
|
+
attributes: {
|
|
252
|
+
"actor.name": actorName,
|
|
253
|
+
"actor.class": actorClassName,
|
|
254
|
+
"alarm.operation": "setMultiple",
|
|
255
|
+
"alarm.count": Array.isArray(alarmDefs) ? alarmDefs.length : 0
|
|
256
|
+
}
|
|
257
|
+
}, async (span) => {
|
|
258
|
+
try {
|
|
259
|
+
const result = await value.call(target, alarmDefs);
|
|
260
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
261
|
+
return result;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
span.recordException(error);
|
|
264
|
+
span.setStatus({
|
|
265
|
+
code: SpanStatusCode.ERROR,
|
|
266
|
+
message: error instanceof Error ? error.message : String(error)
|
|
267
|
+
});
|
|
268
|
+
throw error;
|
|
269
|
+
} finally {
|
|
270
|
+
span.end();
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
};
|
|
274
|
+
if (prop === "cancel" && typeof value === "function") return async function instrumentedCancel(alarmId) {
|
|
275
|
+
const tracer = getTracer$3();
|
|
276
|
+
const spanName = `Actor ${actorName}: alarms.cancel`;
|
|
277
|
+
return tracer.startActiveSpan(spanName, {
|
|
278
|
+
kind: SpanKind.CLIENT,
|
|
279
|
+
attributes: {
|
|
280
|
+
"actor.name": actorName,
|
|
281
|
+
"actor.class": actorClassName,
|
|
282
|
+
"alarm.operation": "cancel",
|
|
283
|
+
"alarm.id": alarmId
|
|
284
|
+
}
|
|
285
|
+
}, async (span) => {
|
|
286
|
+
try {
|
|
287
|
+
const result = await value.call(target, alarmId);
|
|
288
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
289
|
+
return result;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
span.recordException(error);
|
|
292
|
+
span.setStatus({
|
|
293
|
+
code: SpanStatusCode.ERROR,
|
|
294
|
+
message: error instanceof Error ? error.message : String(error)
|
|
295
|
+
});
|
|
296
|
+
throw error;
|
|
297
|
+
} finally {
|
|
298
|
+
span.end();
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
if (prop === "cancelAll" && typeof value === "function") return async function instrumentedCancelAll() {
|
|
303
|
+
const tracer = getTracer$3();
|
|
304
|
+
const spanName = `Actor ${actorName}: alarms.cancelAll`;
|
|
305
|
+
return tracer.startActiveSpan(spanName, {
|
|
306
|
+
kind: SpanKind.CLIENT,
|
|
307
|
+
attributes: {
|
|
308
|
+
"actor.name": actorName,
|
|
309
|
+
"actor.class": actorClassName,
|
|
310
|
+
"alarm.operation": "cancelAll"
|
|
311
|
+
}
|
|
312
|
+
}, async (span) => {
|
|
313
|
+
try {
|
|
314
|
+
const result = await value.call(target);
|
|
315
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
316
|
+
return result;
|
|
317
|
+
} catch (error) {
|
|
318
|
+
span.recordException(error);
|
|
319
|
+
span.setStatus({
|
|
320
|
+
code: SpanStatusCode.ERROR,
|
|
321
|
+
message: error instanceof Error ? error.message : String(error)
|
|
322
|
+
});
|
|
323
|
+
throw error;
|
|
324
|
+
} finally {
|
|
325
|
+
span.end();
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
};
|
|
329
|
+
if (typeof value === "function") return value.bind(target);
|
|
330
|
+
return value;
|
|
331
|
+
} });
|
|
372
332
|
}
|
|
373
|
-
|
|
374
|
-
|
|
333
|
+
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/actors/sockets.ts
|
|
336
|
+
/**
|
|
337
|
+
* Actor sockets instrumentation
|
|
338
|
+
*
|
|
339
|
+
* Traces operations on actor.sockets
|
|
340
|
+
*/
|
|
341
|
+
/**
|
|
342
|
+
* Get the tracer instance
|
|
343
|
+
*/
|
|
344
|
+
function getTracer$2() {
|
|
345
|
+
return trace.getTracer("autotel-cloudflare-actors");
|
|
375
346
|
}
|
|
347
|
+
/**
|
|
348
|
+
* Instrument Actor sockets for tracing
|
|
349
|
+
*
|
|
350
|
+
* Captures:
|
|
351
|
+
* - acceptWebSocket: Accept an incoming WebSocket connection
|
|
352
|
+
* - broadcast: Send message to all connected sockets
|
|
353
|
+
* - send: Send message to a specific socket
|
|
354
|
+
*/
|
|
376
355
|
function instrumentActorSockets(sockets, actorInstance, actorClass) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
"actor.class": actorClassName,
|
|
498
|
-
"websocket.operation": "getConnections"
|
|
499
|
-
}
|
|
500
|
-
},
|
|
501
|
-
(span) => {
|
|
502
|
-
try {
|
|
503
|
-
const result = value.call(target);
|
|
504
|
-
if (Array.isArray(result)) {
|
|
505
|
-
span.setAttribute("websocket.connections.count", result.length);
|
|
506
|
-
}
|
|
507
|
-
span.setStatus({ code: SpanStatusCode.OK });
|
|
508
|
-
return result;
|
|
509
|
-
} catch (error) {
|
|
510
|
-
span.recordException(error);
|
|
511
|
-
span.setStatus({
|
|
512
|
-
code: SpanStatusCode.ERROR,
|
|
513
|
-
message: error instanceof Error ? error.message : String(error)
|
|
514
|
-
});
|
|
515
|
-
throw error;
|
|
516
|
-
} finally {
|
|
517
|
-
span.end();
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
);
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
if (typeof value === "function") {
|
|
524
|
-
return value.bind(target);
|
|
525
|
-
}
|
|
526
|
-
return value;
|
|
527
|
-
}
|
|
528
|
-
};
|
|
529
|
-
return wrap(sockets, socketsHandler);
|
|
356
|
+
if (!sockets || typeof sockets !== "object") return sockets;
|
|
357
|
+
const actorClassName = actorClass.name || "Actor";
|
|
358
|
+
const actorName = actorInstance.name || actorClassName;
|
|
359
|
+
return wrap(sockets, { get(target, prop) {
|
|
360
|
+
const value = Reflect.get(target, prop);
|
|
361
|
+
if (prop === "acceptWebSocket" && typeof value === "function") return function instrumentedAcceptWebSocket(request) {
|
|
362
|
+
const tracer = getTracer$2();
|
|
363
|
+
const spanName = `Actor ${actorName}: sockets.acceptWebSocket`;
|
|
364
|
+
return tracer.startActiveSpan(spanName, {
|
|
365
|
+
kind: SpanKind.SERVER,
|
|
366
|
+
attributes: {
|
|
367
|
+
"actor.name": actorName,
|
|
368
|
+
"actor.class": actorClassName,
|
|
369
|
+
"websocket.operation": "accept",
|
|
370
|
+
"url.full": request.url
|
|
371
|
+
}
|
|
372
|
+
}, (span) => {
|
|
373
|
+
try {
|
|
374
|
+
const result = value.call(target, request);
|
|
375
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
376
|
+
return result;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
span.recordException(error);
|
|
379
|
+
span.setStatus({
|
|
380
|
+
code: SpanStatusCode.ERROR,
|
|
381
|
+
message: error instanceof Error ? error.message : String(error)
|
|
382
|
+
});
|
|
383
|
+
throw error;
|
|
384
|
+
} finally {
|
|
385
|
+
span.end();
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
};
|
|
389
|
+
if (prop === "broadcast" && typeof value === "function") return function instrumentedBroadcast(message) {
|
|
390
|
+
const tracer = getTracer$2();
|
|
391
|
+
const spanName = `Actor ${actorName}: sockets.broadcast`;
|
|
392
|
+
tracer.startActiveSpan(spanName, {
|
|
393
|
+
kind: SpanKind.PRODUCER,
|
|
394
|
+
attributes: {
|
|
395
|
+
"actor.name": actorName,
|
|
396
|
+
"actor.class": actorClassName,
|
|
397
|
+
"websocket.operation": "broadcast",
|
|
398
|
+
"websocket.message.type": typeof message,
|
|
399
|
+
"websocket.message.size": typeof message === "string" ? message.length : message instanceof ArrayBuffer ? message.byteLength : 0
|
|
400
|
+
}
|
|
401
|
+
}, (span) => {
|
|
402
|
+
try {
|
|
403
|
+
value.call(target, message);
|
|
404
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
405
|
+
} catch (error) {
|
|
406
|
+
span.recordException(error);
|
|
407
|
+
span.setStatus({
|
|
408
|
+
code: SpanStatusCode.ERROR,
|
|
409
|
+
message: error instanceof Error ? error.message : String(error)
|
|
410
|
+
});
|
|
411
|
+
throw error;
|
|
412
|
+
} finally {
|
|
413
|
+
span.end();
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
};
|
|
417
|
+
if (prop === "send" && typeof value === "function") return function instrumentedSend(ws, message) {
|
|
418
|
+
const tracer = getTracer$2();
|
|
419
|
+
const spanName = `Actor ${actorName}: sockets.send`;
|
|
420
|
+
tracer.startActiveSpan(spanName, {
|
|
421
|
+
kind: SpanKind.PRODUCER,
|
|
422
|
+
attributes: {
|
|
423
|
+
"actor.name": actorName,
|
|
424
|
+
"actor.class": actorClassName,
|
|
425
|
+
"websocket.operation": "send",
|
|
426
|
+
"websocket.message.type": typeof message,
|
|
427
|
+
"websocket.message.size": typeof message === "string" ? message.length : message instanceof ArrayBuffer ? message.byteLength : 0
|
|
428
|
+
}
|
|
429
|
+
}, (span) => {
|
|
430
|
+
try {
|
|
431
|
+
value.call(target, ws, message);
|
|
432
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
433
|
+
} catch (error) {
|
|
434
|
+
span.recordException(error);
|
|
435
|
+
span.setStatus({
|
|
436
|
+
code: SpanStatusCode.ERROR,
|
|
437
|
+
message: error instanceof Error ? error.message : String(error)
|
|
438
|
+
});
|
|
439
|
+
throw error;
|
|
440
|
+
} finally {
|
|
441
|
+
span.end();
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
};
|
|
445
|
+
if (prop === "getConnections" && typeof value === "function") return function instrumentedGetConnections() {
|
|
446
|
+
const tracer = getTracer$2();
|
|
447
|
+
const spanName = `Actor ${actorName}: sockets.getConnections`;
|
|
448
|
+
return tracer.startActiveSpan(spanName, {
|
|
449
|
+
kind: SpanKind.CLIENT,
|
|
450
|
+
attributes: {
|
|
451
|
+
"actor.name": actorName,
|
|
452
|
+
"actor.class": actorClassName,
|
|
453
|
+
"websocket.operation": "getConnections"
|
|
454
|
+
}
|
|
455
|
+
}, (span) => {
|
|
456
|
+
try {
|
|
457
|
+
const result = value.call(target);
|
|
458
|
+
if (Array.isArray(result)) span.setAttribute("websocket.connections.count", result.length);
|
|
459
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
460
|
+
return result;
|
|
461
|
+
} catch (error) {
|
|
462
|
+
span.recordException(error);
|
|
463
|
+
span.setStatus({
|
|
464
|
+
code: SpanStatusCode.ERROR,
|
|
465
|
+
message: error instanceof Error ? error.message : String(error)
|
|
466
|
+
});
|
|
467
|
+
throw error;
|
|
468
|
+
} finally {
|
|
469
|
+
span.end();
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
};
|
|
473
|
+
if (typeof value === "function") return value.bind(target);
|
|
474
|
+
return value;
|
|
475
|
+
} });
|
|
530
476
|
}
|
|
531
477
|
|
|
532
|
-
|
|
533
|
-
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/actors/instrument-actor.ts
|
|
480
|
+
/**
|
|
481
|
+
* Actor class instrumentation for @cloudflare/actors
|
|
482
|
+
*
|
|
483
|
+
* Wraps Actor lifecycle methods with OpenTelemetry tracing:
|
|
484
|
+
* - onInit: Traced as 'actor.lifecycle': 'init'
|
|
485
|
+
* - onRequest: Traced with full HTTP semantics
|
|
486
|
+
* - onAlarm: Traced as 'actor.lifecycle': 'alarm'
|
|
487
|
+
* - onPersist: Traced as 'actor.lifecycle': 'persist'
|
|
488
|
+
* - WebSocket methods: Traced with socket semantics
|
|
489
|
+
*/
|
|
490
|
+
/**
|
|
491
|
+
* Track cold starts per Actor class
|
|
492
|
+
*/
|
|
493
|
+
const coldStarts = /* @__PURE__ */ new WeakMap();
|
|
534
494
|
function isColdStart(actorClass) {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
495
|
+
if (!coldStarts.has(actorClass)) {
|
|
496
|
+
coldStarts.set(actorClass, true);
|
|
497
|
+
return true;
|
|
498
|
+
}
|
|
499
|
+
return false;
|
|
540
500
|
}
|
|
541
|
-
|
|
542
|
-
|
|
501
|
+
/**
|
|
502
|
+
* Get the tracer instance
|
|
503
|
+
*/
|
|
504
|
+
function getTracer$1() {
|
|
505
|
+
return trace.getTracer("autotel-cloudflare-actors");
|
|
543
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Default span name formatter
|
|
509
|
+
*/
|
|
544
510
|
function defaultSpanNameFormatter(actorName, actorClass, lifecycle) {
|
|
545
|
-
|
|
546
|
-
return `Actor ${displayName}: ${lifecycle}`;
|
|
511
|
+
return `Actor ${actorName || actorClass}: ${lifecycle}`;
|
|
547
512
|
}
|
|
513
|
+
/**
|
|
514
|
+
* Create base Actor span attributes
|
|
515
|
+
*/
|
|
548
516
|
function createActorAttributes(actorInstance, actorClass, lifecycle) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
517
|
+
return {
|
|
518
|
+
"actor.name": actorInstance.name || "unknown",
|
|
519
|
+
"actor.class": actorClass.name || "Actor",
|
|
520
|
+
"actor.lifecycle": lifecycle,
|
|
521
|
+
"actor.coldstart": isColdStart(actorClass),
|
|
522
|
+
...actorInstance.identifier && { "actor.identifier": actorInstance.identifier }
|
|
523
|
+
};
|
|
556
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* Instrument the onInit lifecycle method
|
|
527
|
+
*/
|
|
557
528
|
function instrumentOnInit(originalMethod, actorInstance, actorClass, options) {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
);
|
|
584
|
-
};
|
|
529
|
+
return async function instrumentedOnInit() {
|
|
530
|
+
const tracer = getTracer$1();
|
|
531
|
+
const actorClassName = actorClass.name || "Actor";
|
|
532
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "init") : defaultSpanNameFormatter(actorInstance.name || "", actorClassName, "init");
|
|
533
|
+
return tracer.startActiveSpan(spanName, {
|
|
534
|
+
kind: SpanKind.INTERNAL,
|
|
535
|
+
attributes: createActorAttributes(actorInstance, actorClass, "init")
|
|
536
|
+
}, async (span) => {
|
|
537
|
+
try {
|
|
538
|
+
await originalMethod.call(actorInstance);
|
|
539
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
540
|
+
} catch (error) {
|
|
541
|
+
span.recordException(error);
|
|
542
|
+
span.setStatus({
|
|
543
|
+
code: SpanStatusCode.ERROR,
|
|
544
|
+
message: error instanceof Error ? error.message : String(error)
|
|
545
|
+
});
|
|
546
|
+
throw error;
|
|
547
|
+
} finally {
|
|
548
|
+
span.end();
|
|
549
|
+
}
|
|
550
|
+
});
|
|
551
|
+
};
|
|
585
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Instrument the onRequest lifecycle method
|
|
555
|
+
*/
|
|
586
556
|
function instrumentOnRequest(originalMethod, actorInstance, actorClass, options) {
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
code: SpanStatusCode.ERROR,
|
|
622
|
-
message: error instanceof Error ? error.message : String(error)
|
|
623
|
-
});
|
|
624
|
-
throw error;
|
|
625
|
-
} finally {
|
|
626
|
-
span.end();
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
);
|
|
630
|
-
};
|
|
557
|
+
return async function instrumentedOnRequest(request) {
|
|
558
|
+
const tracer = getTracer$1();
|
|
559
|
+
const parentContext = propagation.extract(context.active(), request.headers);
|
|
560
|
+
const url = new URL(request.url);
|
|
561
|
+
const actorClassName = actorClass.name || "Actor";
|
|
562
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "request") : `Actor ${actorInstance.name || actorClassName}: ${request.method} ${url.pathname}`;
|
|
563
|
+
return tracer.startActiveSpan(spanName, {
|
|
564
|
+
kind: SpanKind.SERVER,
|
|
565
|
+
attributes: {
|
|
566
|
+
...createActorAttributes(actorInstance, actorClass, "request"),
|
|
567
|
+
"http.request.method": request.method,
|
|
568
|
+
"url.full": request.url,
|
|
569
|
+
"url.path": url.pathname,
|
|
570
|
+
"url.query": url.search
|
|
571
|
+
}
|
|
572
|
+
}, parentContext, async (span) => {
|
|
573
|
+
try {
|
|
574
|
+
const response = await originalMethod.call(actorInstance, request);
|
|
575
|
+
span.setAttributes({ "http.response.status_code": response.status });
|
|
576
|
+
if (response.ok) span.setStatus({ code: SpanStatusCode.OK });
|
|
577
|
+
else span.setStatus({ code: SpanStatusCode.ERROR });
|
|
578
|
+
return response;
|
|
579
|
+
} catch (error) {
|
|
580
|
+
span.recordException(error);
|
|
581
|
+
span.setStatus({
|
|
582
|
+
code: SpanStatusCode.ERROR,
|
|
583
|
+
message: error instanceof Error ? error.message : String(error)
|
|
584
|
+
});
|
|
585
|
+
throw error;
|
|
586
|
+
} finally {
|
|
587
|
+
span.end();
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
};
|
|
631
591
|
}
|
|
592
|
+
/**
|
|
593
|
+
* Instrument the onAlarm lifecycle method
|
|
594
|
+
*/
|
|
632
595
|
function instrumentOnAlarm(originalMethod, actorInstance, actorClass, options) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
);
|
|
662
|
-
};
|
|
596
|
+
return async function instrumentedOnAlarm(alarmInfo) {
|
|
597
|
+
const tracer = getTracer$1();
|
|
598
|
+
const actorClassName = actorClass.name || "Actor";
|
|
599
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "alarm") : defaultSpanNameFormatter(actorInstance.name || "", actorClassName, "alarm");
|
|
600
|
+
return tracer.startActiveSpan(spanName, {
|
|
601
|
+
kind: SpanKind.INTERNAL,
|
|
602
|
+
attributes: {
|
|
603
|
+
...createActorAttributes(actorInstance, actorClass, "alarm"),
|
|
604
|
+
"faas.trigger": "timer"
|
|
605
|
+
}
|
|
606
|
+
}, async (span) => {
|
|
607
|
+
try {
|
|
608
|
+
await originalMethod.call(actorInstance, alarmInfo);
|
|
609
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
610
|
+
} catch (error) {
|
|
611
|
+
span.recordException(error);
|
|
612
|
+
span.setStatus({
|
|
613
|
+
code: SpanStatusCode.ERROR,
|
|
614
|
+
message: error instanceof Error ? error.message : String(error)
|
|
615
|
+
});
|
|
616
|
+
throw error;
|
|
617
|
+
} finally {
|
|
618
|
+
span.end();
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
};
|
|
663
622
|
}
|
|
623
|
+
/**
|
|
624
|
+
* Instrument the onPersist lifecycle method
|
|
625
|
+
*/
|
|
664
626
|
function instrumentOnPersist(originalMethod, actorInstance, actorClass, options) {
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
} finally {
|
|
694
|
-
span.end();
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
);
|
|
698
|
-
};
|
|
627
|
+
if (!options.capturePersistEvents) return originalMethod;
|
|
628
|
+
return function instrumentedOnPersist(key, value) {
|
|
629
|
+
const tracer = getTracer$1();
|
|
630
|
+
const actorClassName = actorClass.name || "Actor";
|
|
631
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "persist") : `Actor ${actorInstance.name || actorClassName}: persist ${key}`;
|
|
632
|
+
tracer.startActiveSpan(spanName, {
|
|
633
|
+
kind: SpanKind.INTERNAL,
|
|
634
|
+
attributes: {
|
|
635
|
+
...createActorAttributes(actorInstance, actorClass, "persist"),
|
|
636
|
+
"actor.persist.key": key,
|
|
637
|
+
"actor.persist.value_type": typeof value
|
|
638
|
+
}
|
|
639
|
+
}, (span) => {
|
|
640
|
+
try {
|
|
641
|
+
originalMethod.call(actorInstance, key, value);
|
|
642
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
643
|
+
} catch (error) {
|
|
644
|
+
span.recordException(error);
|
|
645
|
+
span.setStatus({
|
|
646
|
+
code: SpanStatusCode.ERROR,
|
|
647
|
+
message: error instanceof Error ? error.message : String(error)
|
|
648
|
+
});
|
|
649
|
+
throw error;
|
|
650
|
+
} finally {
|
|
651
|
+
span.end();
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
};
|
|
699
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Instrument WebSocket lifecycle methods
|
|
658
|
+
*/
|
|
700
659
|
function instrumentWebSocketConnect(originalMethod, actorInstance, actorClass, options) {
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
);
|
|
730
|
-
};
|
|
660
|
+
return function instrumentedWebSocketConnect(ws, request) {
|
|
661
|
+
const tracer = getTracer$1();
|
|
662
|
+
const actorClassName = actorClass.name || "Actor";
|
|
663
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "websocket.connect") : defaultSpanNameFormatter(actorInstance.name || "", actorClassName, "websocket.connect");
|
|
664
|
+
tracer.startActiveSpan(spanName, {
|
|
665
|
+
kind: SpanKind.SERVER,
|
|
666
|
+
attributes: {
|
|
667
|
+
...createActorAttributes(actorInstance, actorClass, "websocket.connect"),
|
|
668
|
+
"url.full": request.url
|
|
669
|
+
}
|
|
670
|
+
}, (span) => {
|
|
671
|
+
try {
|
|
672
|
+
originalMethod.call(actorInstance, ws, request);
|
|
673
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
674
|
+
} catch (error) {
|
|
675
|
+
span.recordException(error);
|
|
676
|
+
span.setStatus({
|
|
677
|
+
code: SpanStatusCode.ERROR,
|
|
678
|
+
message: error instanceof Error ? error.message : String(error)
|
|
679
|
+
});
|
|
680
|
+
throw error;
|
|
681
|
+
} finally {
|
|
682
|
+
span.end();
|
|
683
|
+
}
|
|
684
|
+
});
|
|
685
|
+
};
|
|
731
686
|
}
|
|
732
687
|
function instrumentWebSocketMessage(originalMethod, actorInstance, actorClass, options) {
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
);
|
|
763
|
-
};
|
|
688
|
+
return function instrumentedWebSocketMessage(ws, message) {
|
|
689
|
+
const tracer = getTracer$1();
|
|
690
|
+
const actorClassName = actorClass.name || "Actor";
|
|
691
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "websocket.message") : defaultSpanNameFormatter(actorInstance.name || "", actorClassName, "websocket.message");
|
|
692
|
+
tracer.startActiveSpan(spanName, {
|
|
693
|
+
kind: SpanKind.SERVER,
|
|
694
|
+
attributes: {
|
|
695
|
+
...createActorAttributes(actorInstance, actorClass, "websocket.message"),
|
|
696
|
+
"websocket.message.type": typeof message,
|
|
697
|
+
"websocket.message.size": typeof message === "string" ? message.length : message instanceof ArrayBuffer ? message.byteLength : 0
|
|
698
|
+
}
|
|
699
|
+
}, (span) => {
|
|
700
|
+
try {
|
|
701
|
+
originalMethod.call(actorInstance, ws, message);
|
|
702
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
703
|
+
} catch (error) {
|
|
704
|
+
span.recordException(error);
|
|
705
|
+
span.setStatus({
|
|
706
|
+
code: SpanStatusCode.ERROR,
|
|
707
|
+
message: error instanceof Error ? error.message : String(error)
|
|
708
|
+
});
|
|
709
|
+
throw error;
|
|
710
|
+
} finally {
|
|
711
|
+
span.end();
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
};
|
|
764
715
|
}
|
|
765
716
|
function instrumentWebSocketDisconnect(originalMethod, actorInstance, actorClass, options) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
);
|
|
792
|
-
};
|
|
717
|
+
return function instrumentedWebSocketDisconnect(ws) {
|
|
718
|
+
const tracer = getTracer$1();
|
|
719
|
+
const actorClassName = actorClass.name || "Actor";
|
|
720
|
+
const spanName = options.spanNameFormatter ? options.spanNameFormatter(actorInstance.name || "", "websocket.disconnect") : defaultSpanNameFormatter(actorInstance.name || "", actorClassName, "websocket.disconnect");
|
|
721
|
+
tracer.startActiveSpan(spanName, {
|
|
722
|
+
kind: SpanKind.SERVER,
|
|
723
|
+
attributes: createActorAttributes(actorInstance, actorClass, "websocket.disconnect")
|
|
724
|
+
}, (span) => {
|
|
725
|
+
try {
|
|
726
|
+
originalMethod.call(actorInstance, ws);
|
|
727
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
728
|
+
} catch (error) {
|
|
729
|
+
span.recordException(error);
|
|
730
|
+
span.setStatus({
|
|
731
|
+
code: SpanStatusCode.ERROR,
|
|
732
|
+
message: error instanceof Error ? error.message : String(error)
|
|
733
|
+
});
|
|
734
|
+
throw error;
|
|
735
|
+
} finally {
|
|
736
|
+
span.end();
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
};
|
|
793
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Instrument an Actor instance by wrapping all lifecycle methods
|
|
743
|
+
*/
|
|
794
744
|
function instrumentActorInstance(actorInstance, _state, _env, actorClass, options) {
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
if (prop === "onWebSocketConnect" && typeof value === "function") {
|
|
811
|
-
return instrumentWebSocketConnect(value.bind(target), target, actorClass, options);
|
|
812
|
-
}
|
|
813
|
-
if (prop === "onWebSocketMessage" && typeof value === "function") {
|
|
814
|
-
return instrumentWebSocketMessage(value.bind(target), target, actorClass, options);
|
|
815
|
-
}
|
|
816
|
-
if (prop === "onWebSocketDisconnect" && typeof value === "function") {
|
|
817
|
-
return instrumentWebSocketDisconnect(value.bind(target), target, actorClass, options);
|
|
818
|
-
}
|
|
819
|
-
if (prop === "storage" && value && options.instrumentStorage !== false) {
|
|
820
|
-
return instrumentActorStorage(value, target, actorClass);
|
|
821
|
-
}
|
|
822
|
-
if (prop === "alarms" && value && options.instrumentAlarms !== false) {
|
|
823
|
-
return instrumentActorAlarms(value, target, actorClass);
|
|
824
|
-
}
|
|
825
|
-
if (prop === "sockets" && value && options.instrumentSockets !== false) {
|
|
826
|
-
return instrumentActorSockets(value, target, actorClass);
|
|
827
|
-
}
|
|
828
|
-
if (typeof value === "function") {
|
|
829
|
-
return value.bind(target);
|
|
830
|
-
}
|
|
831
|
-
return value;
|
|
832
|
-
}
|
|
833
|
-
};
|
|
834
|
-
return wrap(actorInstance, instanceHandler);
|
|
745
|
+
return wrap(actorInstance, { get(target, prop) {
|
|
746
|
+
const value = Reflect.get(target, prop);
|
|
747
|
+
if (prop === "onInit" && typeof value === "function") return instrumentOnInit(value.bind(target), target, actorClass, options);
|
|
748
|
+
if (prop === "onRequest" && typeof value === "function") return instrumentOnRequest(value.bind(target), target, actorClass, options);
|
|
749
|
+
if (prop === "onAlarm" && typeof value === "function") return instrumentOnAlarm(value.bind(target), target, actorClass, options);
|
|
750
|
+
if (prop === "onPersist" && typeof value === "function") return instrumentOnPersist(value.bind(target), target, actorClass, options);
|
|
751
|
+
if (prop === "onWebSocketConnect" && typeof value === "function") return instrumentWebSocketConnect(value.bind(target), target, actorClass, options);
|
|
752
|
+
if (prop === "onWebSocketMessage" && typeof value === "function") return instrumentWebSocketMessage(value.bind(target), target, actorClass, options);
|
|
753
|
+
if (prop === "onWebSocketDisconnect" && typeof value === "function") return instrumentWebSocketDisconnect(value.bind(target), target, actorClass, options);
|
|
754
|
+
if (prop === "storage" && value && options.instrumentStorage !== false) return instrumentActorStorage(value, target, actorClass);
|
|
755
|
+
if (prop === "alarms" && value && options.instrumentAlarms !== false) return instrumentActorAlarms(value, target, actorClass);
|
|
756
|
+
if (prop === "sockets" && value && options.instrumentSockets !== false) return instrumentActorSockets(value, target, actorClass);
|
|
757
|
+
if (typeof value === "function") return value.bind(target);
|
|
758
|
+
return value;
|
|
759
|
+
} });
|
|
835
760
|
}
|
|
761
|
+
/**
|
|
762
|
+
* Instrument an Actor class for comprehensive OpenTelemetry tracing
|
|
763
|
+
*
|
|
764
|
+
* This wraps the Actor class to automatically trace all lifecycle methods:
|
|
765
|
+
* - onInit: Actor initialization
|
|
766
|
+
* - onRequest: HTTP request handling
|
|
767
|
+
* - onAlarm: Alarm triggers
|
|
768
|
+
* - onPersist: Property persistence events
|
|
769
|
+
* - WebSocket methods: Connection, message, disconnect
|
|
770
|
+
*
|
|
771
|
+
* It also optionally instruments:
|
|
772
|
+
* - actor.storage: SQL queries and storage operations
|
|
773
|
+
* - actor.alarms: Alarm scheduling operations
|
|
774
|
+
* - actor.sockets: WebSocket operations
|
|
775
|
+
*
|
|
776
|
+
* @example
|
|
777
|
+
* ```typescript
|
|
778
|
+
* import { Actor } from '@cloudflare/actors'
|
|
779
|
+
* import { instrumentActor } from 'autotel-cloudflare/actors'
|
|
780
|
+
*
|
|
781
|
+
* class Counter extends Actor<Env> {
|
|
782
|
+
* protected onInit() {
|
|
783
|
+
* console.log('Counter initialized')
|
|
784
|
+
* }
|
|
785
|
+
*
|
|
786
|
+
* protected onRequest(request: Request) {
|
|
787
|
+
* return new Response('count: 42')
|
|
788
|
+
* }
|
|
789
|
+
* }
|
|
790
|
+
*
|
|
791
|
+
* // Wrap the class
|
|
792
|
+
* export const InstrumentedCounter = instrumentActor(Counter, (env: Env) => ({
|
|
793
|
+
* service: { name: 'counter-actor' },
|
|
794
|
+
* exporter: { url: env.OTLP_ENDPOINT },
|
|
795
|
+
* actors: {
|
|
796
|
+
* instrumentStorage: true,
|
|
797
|
+
* capturePersistEvents: true
|
|
798
|
+
* }
|
|
799
|
+
* }))
|
|
800
|
+
* ```
|
|
801
|
+
*
|
|
802
|
+
* @param actorClass - The Actor class to instrument
|
|
803
|
+
* @param config - Configuration (static object or function)
|
|
804
|
+
* @returns Instrumented Actor class
|
|
805
|
+
*/
|
|
836
806
|
function instrumentActor(actorClass, config) {
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
}
|
|
863
|
-
};
|
|
864
|
-
return wrap(actorClass, classHandler);
|
|
807
|
+
const initialiser = createInitialiser(config);
|
|
808
|
+
const defaultOptions = {
|
|
809
|
+
instrumentStorage: true,
|
|
810
|
+
instrumentAlarms: true,
|
|
811
|
+
instrumentSockets: true,
|
|
812
|
+
capturePersistEvents: true
|
|
813
|
+
};
|
|
814
|
+
return wrap(actorClass, { construct(target, [state, env]) {
|
|
815
|
+
const resolvedConfig = typeof config === "function" ? config(env, {
|
|
816
|
+
id: state.id.toString(),
|
|
817
|
+
name: state.id.name
|
|
818
|
+
}) : config;
|
|
819
|
+
const actorOptions = resolvedConfig && typeof resolvedConfig === "object" && "actors" in resolvedConfig ? resolvedConfig.actors : void 0;
|
|
820
|
+
const options = {
|
|
821
|
+
...defaultOptions,
|
|
822
|
+
...actorOptions
|
|
823
|
+
};
|
|
824
|
+
const context$1 = setConfig(initialiser(env, {
|
|
825
|
+
id: state.id.toString(),
|
|
826
|
+
name: state.id.name
|
|
827
|
+
}));
|
|
828
|
+
return instrumentActorInstance(context.with(context$1, () => {
|
|
829
|
+
return new target(state, env);
|
|
830
|
+
}), state, env, actorClass, options);
|
|
831
|
+
} });
|
|
865
832
|
}
|
|
866
|
-
|
|
867
|
-
|
|
833
|
+
|
|
834
|
+
//#endregion
|
|
835
|
+
//#region src/actors/traced-handler.ts
|
|
836
|
+
/**
|
|
837
|
+
* Traced handler wrapper for @cloudflare/actors
|
|
838
|
+
*
|
|
839
|
+
* Wraps the Actors handler() to provide:
|
|
840
|
+
* - Root span for the entire request lifecycle
|
|
841
|
+
* - Actor name extraction and correlation
|
|
842
|
+
* - Request routing tracing
|
|
843
|
+
*/
|
|
844
|
+
/**
|
|
845
|
+
* Get the tracer instance
|
|
846
|
+
*/
|
|
847
|
+
function getTracer() {
|
|
848
|
+
return trace.getTracer("autotel-cloudflare-actors");
|
|
868
849
|
}
|
|
850
|
+
/**
|
|
851
|
+
* Create a traced handler that combines Actor instrumentation with request tracing
|
|
852
|
+
*
|
|
853
|
+
* This is an all-in-one wrapper that:
|
|
854
|
+
* 1. Initializes telemetry for the Worker
|
|
855
|
+
* 2. Creates a root span for each incoming request
|
|
856
|
+
* 3. Extracts the Actor name using `nameFromRequest`
|
|
857
|
+
* 4. Instruments the Actor class with lifecycle tracing
|
|
858
|
+
* 5. Routes the request to the instrumented Actor
|
|
859
|
+
*
|
|
860
|
+
* @example
|
|
861
|
+
* ```typescript
|
|
862
|
+
* import { Actor } from '@cloudflare/actors'
|
|
863
|
+
* import { tracedHandler } from 'autotel-cloudflare/actors'
|
|
864
|
+
*
|
|
865
|
+
* class MyActor extends Actor<Env> {
|
|
866
|
+
* protected onRequest(request: Request) {
|
|
867
|
+
* return new Response('Hello!')
|
|
868
|
+
* }
|
|
869
|
+
* }
|
|
870
|
+
*
|
|
871
|
+
* // Export the Actor class and use tracedHandler
|
|
872
|
+
* export { MyActor }
|
|
873
|
+
* export default tracedHandler(MyActor, (env) => ({
|
|
874
|
+
* service: { name: 'my-actor-service' },
|
|
875
|
+
* exporter: { url: env.OTLP_ENDPOINT }
|
|
876
|
+
* }))
|
|
877
|
+
* ```
|
|
878
|
+
*
|
|
879
|
+
* @param actorClass - The Actor class to handle requests
|
|
880
|
+
* @param config - Configuration (static object or function)
|
|
881
|
+
* @returns A Worker handler with full tracing
|
|
882
|
+
*/
|
|
869
883
|
function tracedHandler(actorClass, config) {
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
});
|
|
955
|
-
return Response.json(
|
|
956
|
-
{
|
|
957
|
-
error: "Internal Server Error",
|
|
958
|
-
message: error instanceof Error ? error.message : "Unknown error"
|
|
959
|
-
},
|
|
960
|
-
{ status: 500, headers: { "Content-Type": "application/json" } }
|
|
961
|
-
);
|
|
962
|
-
} finally {
|
|
963
|
-
span.end();
|
|
964
|
-
}
|
|
965
|
-
}
|
|
966
|
-
);
|
|
967
|
-
}
|
|
968
|
-
};
|
|
884
|
+
const initialiser = createInitialiser(config);
|
|
885
|
+
return { async fetch(request, env, _ctx) {
|
|
886
|
+
const configContext = setConfig(initialiser(env, { type: "http" }));
|
|
887
|
+
const parentContext = propagation.extract(configContext, request.headers);
|
|
888
|
+
const tracer = getTracer();
|
|
889
|
+
const url = new URL(request.url);
|
|
890
|
+
const actorClassName = actorClass.name || "Actor";
|
|
891
|
+
let actorName;
|
|
892
|
+
try {
|
|
893
|
+
if (actorClass.nameFromRequest) actorName = await actorClass.nameFromRequest(request);
|
|
894
|
+
} catch {
|
|
895
|
+
actorName = void 0;
|
|
896
|
+
}
|
|
897
|
+
const spanName = `${actorClassName} handler: ${request.method} ${url.pathname}`;
|
|
898
|
+
return tracer.startActiveSpan(spanName, {
|
|
899
|
+
kind: SpanKind.SERVER,
|
|
900
|
+
attributes: {
|
|
901
|
+
"http.request.method": request.method,
|
|
902
|
+
"url.full": request.url,
|
|
903
|
+
"url.path": url.pathname,
|
|
904
|
+
"url.query": url.search,
|
|
905
|
+
"actor.class": actorClassName,
|
|
906
|
+
...actorName && { "actor.name": actorName },
|
|
907
|
+
"faas.trigger": "http"
|
|
908
|
+
}
|
|
909
|
+
}, parentContext, async (span) => {
|
|
910
|
+
try {
|
|
911
|
+
const envObj = env;
|
|
912
|
+
const bindingName = Object.keys(envObj).find((key) => {
|
|
913
|
+
const binding = env.__DURABLE_OBJECT_BINDINGS;
|
|
914
|
+
return key === actorClassName || binding?.[key]?.class_name === actorClassName;
|
|
915
|
+
});
|
|
916
|
+
if (!bindingName) {
|
|
917
|
+
span.setStatus({
|
|
918
|
+
code: SpanStatusCode.ERROR,
|
|
919
|
+
message: `No Durable Object binding found for ${actorClassName}`
|
|
920
|
+
});
|
|
921
|
+
return Response.json({
|
|
922
|
+
error: "Configuration Error",
|
|
923
|
+
message: `No Durable Object binding found for actor class ${actorClassName}`
|
|
924
|
+
}, {
|
|
925
|
+
status: 500,
|
|
926
|
+
headers: { "Content-Type": "application/json" }
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
const namespace = envObj[bindingName];
|
|
930
|
+
const idString = actorName || "default";
|
|
931
|
+
const locationHint = actorClass.configuration?.(request)?.locationHint;
|
|
932
|
+
const stub = namespace.getByName(idString, { locationHint });
|
|
933
|
+
if ("setName" in stub && typeof stub.setName === "function") stub.setName(idString);
|
|
934
|
+
const headers = new Headers(request.headers);
|
|
935
|
+
propagation.inject(context.active(), headers);
|
|
936
|
+
const tracedRequest = new Request(request.url, {
|
|
937
|
+
method: request.method,
|
|
938
|
+
headers,
|
|
939
|
+
body: request.body,
|
|
940
|
+
redirect: request.redirect
|
|
941
|
+
});
|
|
942
|
+
const response = await stub.fetch(tracedRequest);
|
|
943
|
+
span.setAttributes({
|
|
944
|
+
"http.response.status_code": response.status,
|
|
945
|
+
"actor.name": idString
|
|
946
|
+
});
|
|
947
|
+
if (response.ok) span.setStatus({ code: SpanStatusCode.OK });
|
|
948
|
+
else span.setStatus({ code: SpanStatusCode.ERROR });
|
|
949
|
+
return response;
|
|
950
|
+
} catch (error) {
|
|
951
|
+
span.recordException(error);
|
|
952
|
+
span.setStatus({
|
|
953
|
+
code: SpanStatusCode.ERROR,
|
|
954
|
+
message: error instanceof Error ? error.message : String(error)
|
|
955
|
+
});
|
|
956
|
+
return Response.json({
|
|
957
|
+
error: "Internal Server Error",
|
|
958
|
+
message: error instanceof Error ? error.message : "Unknown error"
|
|
959
|
+
}, {
|
|
960
|
+
status: 500,
|
|
961
|
+
headers: { "Content-Type": "application/json" }
|
|
962
|
+
});
|
|
963
|
+
} finally {
|
|
964
|
+
span.end();
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
} };
|
|
969
968
|
}
|
|
969
|
+
/**
|
|
970
|
+
* Alternative: Create a handler wrapper that uses the existing @cloudflare/actors handler
|
|
971
|
+
*
|
|
972
|
+
* This is useful if you want to use the original handler() but add tracing around it.
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* ```typescript
|
|
976
|
+
* import { Actor, handler } from '@cloudflare/actors'
|
|
977
|
+
* import { wrapHandler } from 'autotel-cloudflare/actors'
|
|
978
|
+
*
|
|
979
|
+
* class MyActor extends Actor<Env> {}
|
|
980
|
+
*
|
|
981
|
+
* export { MyActor }
|
|
982
|
+
* export default wrapHandler(handler(MyActor), (env) => ({
|
|
983
|
+
* service: { name: 'my-service' }
|
|
984
|
+
* }))
|
|
985
|
+
* ```
|
|
986
|
+
*/
|
|
970
987
|
function wrapHandler(originalHandler, config) {
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
span.recordException(error);
|
|
1014
|
-
span.setStatus({
|
|
1015
|
-
code: SpanStatusCode.ERROR,
|
|
1016
|
-
message: error instanceof Error ? error.message : String(error)
|
|
1017
|
-
});
|
|
1018
|
-
throw error;
|
|
1019
|
-
} finally {
|
|
1020
|
-
span.end();
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
);
|
|
1024
|
-
}
|
|
1025
|
-
};
|
|
988
|
+
const initialiser = createInitialiser(config);
|
|
989
|
+
return { async fetch(request, env, ctx) {
|
|
990
|
+
const configContext = setConfig(initialiser(env, { type: "http" }));
|
|
991
|
+
const parentContext = propagation.extract(configContext, request.headers);
|
|
992
|
+
const tracer = getTracer();
|
|
993
|
+
const url = new URL(request.url);
|
|
994
|
+
return tracer.startActiveSpan(`Worker: ${request.method} ${url.pathname}`, {
|
|
995
|
+
kind: SpanKind.SERVER,
|
|
996
|
+
attributes: {
|
|
997
|
+
"http.request.method": request.method,
|
|
998
|
+
"url.full": request.url,
|
|
999
|
+
"url.path": url.pathname,
|
|
1000
|
+
"url.query": url.search,
|
|
1001
|
+
"faas.trigger": "http"
|
|
1002
|
+
}
|
|
1003
|
+
}, parentContext, async (span) => {
|
|
1004
|
+
try {
|
|
1005
|
+
const headers = new Headers(request.headers);
|
|
1006
|
+
propagation.inject(context.active(), headers);
|
|
1007
|
+
const tracedRequest = new Request(request.url, {
|
|
1008
|
+
method: request.method,
|
|
1009
|
+
headers,
|
|
1010
|
+
body: request.body,
|
|
1011
|
+
redirect: request.redirect
|
|
1012
|
+
});
|
|
1013
|
+
const response = await originalHandler.fetch(tracedRequest, env, ctx);
|
|
1014
|
+
span.setAttributes({ "http.response.status_code": response.status });
|
|
1015
|
+
if (response.ok) span.setStatus({ code: SpanStatusCode.OK });
|
|
1016
|
+
else span.setStatus({ code: SpanStatusCode.ERROR });
|
|
1017
|
+
return response;
|
|
1018
|
+
} catch (error) {
|
|
1019
|
+
span.recordException(error);
|
|
1020
|
+
span.setStatus({
|
|
1021
|
+
code: SpanStatusCode.ERROR,
|
|
1022
|
+
message: error instanceof Error ? error.message : String(error)
|
|
1023
|
+
});
|
|
1024
|
+
throw error;
|
|
1025
|
+
} finally {
|
|
1026
|
+
span.end();
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
} };
|
|
1026
1030
|
}
|
|
1027
1031
|
|
|
1032
|
+
//#endregion
|
|
1028
1033
|
export { instrumentActor, instrumentActorAlarms, instrumentActorSockets, instrumentActorStorage, tracedHandler, wrapHandler };
|
|
1029
|
-
//# sourceMappingURL=actors.js.map
|
|
1030
1034
|
//# sourceMappingURL=actors.js.map
|