@rasputin-ai/node 0.4.1 → 0.5.0-alpha.10
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 +188 -162
- package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts +2 -37
- package/dist/auto-instrumentation/collect-instrumentation-delta.d.ts.map +1 -1
- package/dist/auto-instrumentation/instrument-compiled-esm.d.ts +19 -0
- package/dist/auto-instrumentation/instrument-compiled-esm.d.ts.map +1 -0
- package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts +41 -0
- package/dist/auto-instrumentation/instrumentation-manifest-delta.d.ts.map +1 -0
- package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts +5 -2
- package/dist/auto-instrumentation/instrumentation-manifest-registry.d.ts.map +1 -1
- package/dist/auto-instrumentation/transform-source.d.ts +7 -1
- package/dist/auto-instrumentation/transform-source.d.ts.map +1 -1
- package/dist/auto-instrumentation/warn-production-runtime-transform.d.ts +8 -0
- package/dist/auto-instrumentation/warn-production-runtime-transform.d.ts.map +1 -0
- package/dist/derivation/analyze-function.d.ts +42 -0
- package/dist/derivation/analyze-function.d.ts.map +1 -0
- package/dist/derivation/build-dependency-graph.d.ts +21 -0
- package/dist/derivation/build-dependency-graph.d.ts.map +1 -0
- package/dist/derivation/derivation-ir.d.ts +33 -0
- package/dist/derivation/derivation-ir.d.ts.map +1 -0
- package/dist/derivation/derivation-proof.d.ts +14 -0
- package/dist/derivation/derivation-proof.d.ts.map +1 -0
- package/dist/derivation/emit-capture-plan.d.ts +8 -0
- package/dist/derivation/emit-capture-plan.d.ts.map +1 -0
- package/dist/execution-recorder/automatic-runtime.d.ts +21 -10
- package/dist/execution-recorder/automatic-runtime.d.ts.map +1 -1
- package/dist/execution-recorder/execution-journal.d.ts +84 -0
- package/dist/execution-recorder/execution-journal.d.ts.map +1 -0
- package/dist/execution-recorder/execution-recorder-types.d.ts +36 -0
- package/dist/execution-recorder/execution-recorder-types.d.ts.map +1 -1
- package/dist/execution-recorder/execution-recorder.d.ts.map +1 -1
- package/dist/execution-recorder/function-plan.d.ts +26 -0
- package/dist/execution-recorder/function-plan.d.ts.map +1 -0
- package/dist/execution-recorder/recorder-memory-budget.d.ts +8 -1
- package/dist/execution-recorder/recorder-memory-budget.d.ts.map +1 -1
- package/dist/execution-recorder/safe-serialize.d.ts +8 -0
- package/dist/execution-recorder/safe-serialize.d.ts.map +1 -1
- package/dist/index.js +1432 -418
- package/dist/instrument/build.d.ts +2 -0
- package/dist/instrument/build.d.ts.map +1 -0
- package/dist/instrument/build.js +1430 -0
- package/dist/instrument/bun.js +825 -82
- package/dist/instrument/node.js +825 -82
- package/dist/rasputin-init.d.ts +5 -5
- package/dist/rasputin-init.d.ts.map +1 -1
- package/dist/sdk-meta.d.ts +1 -1
- package/dist/sdk-meta.d.ts.map +1 -1
- package/package.json +10 -2
- package/dist/execution-recorder/call-aware-event-buffer.d.ts +0 -23
- package/dist/execution-recorder/call-aware-event-buffer.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -104,76 +104,38 @@ var runtimeLabel = () => {
|
|
|
104
104
|
|
|
105
105
|
// src/auto-instrumentation/instrumentation-manifest-registry.ts
|
|
106
106
|
import { createHash } from "node:crypto";
|
|
107
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
107
108
|
import {
|
|
108
109
|
INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
|
|
109
110
|
sourceLocatorFromFile as sourceLocatorFromFile2
|
|
110
111
|
} from "@rasputin-ai/core";
|
|
111
112
|
|
|
112
|
-
// src/execution-recorder/
|
|
113
|
+
// src/execution-recorder/function-plan.ts
|
|
113
114
|
import {
|
|
114
115
|
runtimeFunctionId,
|
|
115
116
|
sourceLocatorFromFile
|
|
116
117
|
} from "@rasputin-ai/core";
|
|
117
|
-
var
|
|
118
|
-
var
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
};
|
|
131
|
-
return { ...definition, functionId: runtimeFunctionId(definition) };
|
|
132
|
-
} catch {
|
|
133
|
-
return void 0;
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
var getRegistry = () => {
|
|
137
|
-
const existing = Reflect.get(globalThis, runtimeSymbol);
|
|
138
|
-
if (existing?.__rasputinRuntimeRegistry && Array.isArray(existing.runtimes)) {
|
|
139
|
-
return existing;
|
|
140
|
-
}
|
|
141
|
-
const runtimes = [];
|
|
142
|
-
const registry = {
|
|
143
|
-
__rasputinRuntimeRegistry: true,
|
|
144
|
-
runtimes,
|
|
145
|
-
run: (sourceToken, args, callback) => {
|
|
146
|
-
const runtime = runtimes.at(-1);
|
|
147
|
-
return runtime ? runtime.run(sourceToken, args, callback) : callback();
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
Reflect.set(globalThis, runtimeSymbol, registry);
|
|
151
|
-
return registry;
|
|
152
|
-
};
|
|
153
|
-
var installAutomaticExecutionRuntime = (execution) => {
|
|
154
|
-
const registry = getRegistry();
|
|
155
|
-
const definitions = /* @__PURE__ */ new Map();
|
|
156
|
-
const runtime = {
|
|
157
|
-
run: (sourceToken, args, callback) => {
|
|
158
|
-
let definition = definitions.get(sourceToken);
|
|
159
|
-
if (!definitions.has(sourceToken)) {
|
|
160
|
-
definition = decodeAutomaticFunctionSource(sourceToken);
|
|
161
|
-
definitions.set(sourceToken, definition);
|
|
162
|
-
}
|
|
163
|
-
return definition ? execution.runFunction(definition, args, callback) : callback();
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
registry.runtimes.push(runtime);
|
|
167
|
-
return () => {
|
|
168
|
-
const index = registry.runtimes.lastIndexOf(runtime);
|
|
169
|
-
if (index >= 0) registry.runtimes.splice(index, 1);
|
|
118
|
+
var EVENT_PAIR_BASE_ESTIMATED_BYTES = 512;
|
|
119
|
+
var definitionFromEncodedPlan = (plan) => {
|
|
120
|
+
const [functionId, name, packageName, packageRelativePath, line, column] = plan;
|
|
121
|
+
const source = packageRelativePath ? {
|
|
122
|
+
...packageName ? { packageName } : {},
|
|
123
|
+
packageRelativePath,
|
|
124
|
+
...line == null ? {} : { line },
|
|
125
|
+
...column == null ? {} : { column }
|
|
126
|
+
} : void 0;
|
|
127
|
+
return {
|
|
128
|
+
functionId,
|
|
129
|
+
name,
|
|
130
|
+
...source ? { source } : {}
|
|
170
131
|
};
|
|
171
132
|
};
|
|
133
|
+
var estimatedCallBytesFor = (functionId) => EVENT_PAIR_BASE_ESTIMATED_BYTES + Buffer.byteLength(functionId, "utf8") * 2;
|
|
172
134
|
|
|
173
135
|
// src/auto-instrumentation/instrumentation-manifest-registry.ts
|
|
174
|
-
var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.
|
|
136
|
+
var INSTRUMENTATION_MANIFEST_SYMBOL = "rasputin.instrumentation.manifest.v3";
|
|
175
137
|
var registrySymbol = Symbol.for(INSTRUMENTATION_MANIFEST_SYMBOL);
|
|
176
|
-
var
|
|
138
|
+
var getRegistry = () => {
|
|
177
139
|
const existing = Reflect.get(globalThis, registrySymbol);
|
|
178
140
|
if (existing?.__rasputinManifestRegistry && existing.files instanceof Map && typeof existing.generation === "number" && typeof existing.uploadedGeneration === "number") {
|
|
179
141
|
return existing;
|
|
@@ -192,20 +154,47 @@ var sourceAt = (filePath, line, column) => {
|
|
|
192
154
|
return source ? { ...source, line, column } : void 0;
|
|
193
155
|
};
|
|
194
156
|
var stableId = (kind, ...parts) => `${kind}_${createHash("sha256").update(parts.join("\0")).digest("base64url").slice(0, 24)}`;
|
|
157
|
+
var recordPrebuiltInstrumentationManifest = (manifest) => {
|
|
158
|
+
const registry = getRegistry();
|
|
159
|
+
registry.prebuilt = manifest;
|
|
160
|
+
registry.generation += 1;
|
|
161
|
+
registry.onDirty?.();
|
|
162
|
+
};
|
|
163
|
+
var loadInstrumentationManifestFile = (path) => {
|
|
164
|
+
try {
|
|
165
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
166
|
+
if (parsed.schema_version !== INSTRUMENTATION_MANIFEST_SCHEMA_VERSION) return false;
|
|
167
|
+
if (!Array.isArray(parsed.functions)) return false;
|
|
168
|
+
recordPrebuiltInstrumentationManifest(parsed);
|
|
169
|
+
return true;
|
|
170
|
+
} catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
var loadInstrumentationManifestIfPresent = (path) => {
|
|
175
|
+
if (!path || !existsSync(path)) return;
|
|
176
|
+
loadInstrumentationManifestFile(path);
|
|
177
|
+
};
|
|
195
178
|
var isInstrumentationManifestDirty = () => {
|
|
196
|
-
const registry =
|
|
197
|
-
return registry.generation !== registry.uploadedGeneration && registry.files.size > 0;
|
|
179
|
+
const registry = getRegistry();
|
|
180
|
+
return registry.generation !== registry.uploadedGeneration && (registry.files.size > 0 || registry.prebuilt !== void 0);
|
|
181
|
+
};
|
|
182
|
+
var instrumentationManifestGeneration = () => getRegistry().generation;
|
|
183
|
+
var instrumentationManifestModuleCount = () => {
|
|
184
|
+
const registry = getRegistry();
|
|
185
|
+
if (registry.files.size > 0) return registry.files.size;
|
|
186
|
+
if (!registry.prebuilt) return 0;
|
|
187
|
+
return new Set(registry.prebuilt.functions.map((fn) => fn.source.packageRelativePath)).size;
|
|
198
188
|
};
|
|
199
|
-
var instrumentationManifestGeneration = () => getRegistry2().generation;
|
|
200
|
-
var instrumentationManifestModuleCount = () => getRegistry2().files.size;
|
|
201
189
|
var snapshotInstrumentationManifest = (options = {}) => {
|
|
202
190
|
const functions = [];
|
|
203
191
|
const callSites = [];
|
|
204
192
|
const destructures = [];
|
|
205
|
-
|
|
193
|
+
const derivationPlans = [];
|
|
194
|
+
for (const delta of getRegistry().files.values()) {
|
|
206
195
|
for (const fn of delta.functions) {
|
|
207
|
-
const definition =
|
|
208
|
-
if (!definition
|
|
196
|
+
const definition = definitionFromEncodedPlan(fn.plan);
|
|
197
|
+
if (!definition.source) continue;
|
|
209
198
|
functions.push({
|
|
210
199
|
functionId: definition.functionId,
|
|
211
200
|
source: definition.source,
|
|
@@ -218,19 +207,18 @@ var snapshotInstrumentationManifest = (options = {}) => {
|
|
|
218
207
|
});
|
|
219
208
|
}
|
|
220
209
|
for (const site of delta.callSites) {
|
|
221
|
-
const caller = decodeAutomaticFunctionSource(site.callerSourceToken);
|
|
222
210
|
const source = sourceAt(site.filePath, site.line, site.column);
|
|
223
|
-
if (!
|
|
211
|
+
if (!source) continue;
|
|
224
212
|
callSites.push({
|
|
225
213
|
id: stableId(
|
|
226
214
|
"cs",
|
|
227
|
-
|
|
215
|
+
site.callerFunctionId,
|
|
228
216
|
source.packageName ?? "",
|
|
229
217
|
source.packageRelativePath,
|
|
230
218
|
site.line,
|
|
231
219
|
site.column
|
|
232
220
|
),
|
|
233
|
-
callerFunctionId:
|
|
221
|
+
callerFunctionId: site.callerFunctionId,
|
|
234
222
|
calleeName: site.calleeName,
|
|
235
223
|
calleeText: site.calleeText,
|
|
236
224
|
source,
|
|
@@ -243,11 +231,10 @@ var snapshotInstrumentationManifest = (options = {}) => {
|
|
|
243
231
|
});
|
|
244
232
|
}
|
|
245
233
|
for (const destructure of delta.destructures) {
|
|
246
|
-
const caller = decodeAutomaticFunctionSource(destructure.callerSourceToken);
|
|
247
234
|
const source = sourceAt(destructure.filePath, destructure.line, destructure.column);
|
|
248
|
-
if (!
|
|
235
|
+
if (!source) continue;
|
|
249
236
|
destructures.push({
|
|
250
|
-
callerFunctionId:
|
|
237
|
+
callerFunctionId: destructure.callerFunctionId,
|
|
251
238
|
sourceParam: destructure.sourceParam,
|
|
252
239
|
source,
|
|
253
240
|
line: destructure.line,
|
|
@@ -255,6 +242,19 @@ var snapshotInstrumentationManifest = (options = {}) => {
|
|
|
255
242
|
binding: destructure.binding
|
|
256
243
|
});
|
|
257
244
|
}
|
|
245
|
+
derivationPlans.push(...delta.derivationPlans ?? []);
|
|
246
|
+
}
|
|
247
|
+
const registry = getRegistry();
|
|
248
|
+
if (registry.prebuilt && registry.files.size === 0) {
|
|
249
|
+
const prebuilt = registry.prebuilt;
|
|
250
|
+
if (!options.sourceRoot && !options.sourceRoots) return prebuilt;
|
|
251
|
+
return {
|
|
252
|
+
...prebuilt,
|
|
253
|
+
sourceRoots: {
|
|
254
|
+
...options.sourceRoot ? { default: options.sourceRoot } : {},
|
|
255
|
+
packages: { ...options.sourceRoots ?? {} }
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
258
|
}
|
|
259
259
|
if (functions.length === 0 && callSites.length === 0 && destructures.length === 0) {
|
|
260
260
|
return void 0;
|
|
@@ -270,15 +270,16 @@ var snapshotInstrumentationManifest = (options = {}) => {
|
|
|
270
270
|
} : {},
|
|
271
271
|
functions,
|
|
272
272
|
callSites,
|
|
273
|
-
destructures
|
|
273
|
+
destructures,
|
|
274
|
+
derivationPlans
|
|
274
275
|
};
|
|
275
276
|
};
|
|
276
277
|
var markInstrumentationManifestUploaded = (generation) => {
|
|
277
|
-
const registry =
|
|
278
|
+
const registry = getRegistry();
|
|
278
279
|
if (registry.generation === generation) registry.uploadedGeneration = generation;
|
|
279
280
|
};
|
|
280
281
|
var setInstrumentationManifestOnDirty = (onDirty) => {
|
|
281
|
-
|
|
282
|
+
getRegistry().onDirty = onDirty;
|
|
282
283
|
};
|
|
283
284
|
|
|
284
285
|
// src/auto-instrumentation/schedule-instrumentation-manifest-upload.ts
|
|
@@ -386,92 +387,397 @@ var scheduleInstrumentationManifestUpload = (options) => {
|
|
|
386
387
|
|
|
387
388
|
// src/execution-recorder/execution-recorder.ts
|
|
388
389
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
389
|
-
import {
|
|
390
|
+
import {
|
|
391
|
+
capturedValueCompleteness,
|
|
392
|
+
hashInstrumentationManifest,
|
|
393
|
+
rasputinOmitted,
|
|
394
|
+
rasputinTagKind,
|
|
395
|
+
runtimeFunctionId as runtimeFunctionId2
|
|
396
|
+
} from "@rasputin-ai/core";
|
|
390
397
|
|
|
391
|
-
// src/execution-recorder/
|
|
392
|
-
var
|
|
398
|
+
// src/execution-recorder/execution-journal.ts
|
|
399
|
+
var KIND_ENTER = 1;
|
|
400
|
+
var KIND_EXIT = 2;
|
|
401
|
+
var KIND_THROW = 3;
|
|
402
|
+
var KIND_SUPPRESSED = 4;
|
|
403
|
+
var NO_PARENT = 4294967295;
|
|
404
|
+
var NO_SUPPRESSION = 4294967295;
|
|
405
|
+
var MAX_POOLED_JOURNALS = 8;
|
|
406
|
+
var MAX_POOLED_JOURNAL_CAPACITY = 4096;
|
|
407
|
+
var INITIAL_JOURNAL_STORAGE = 32;
|
|
408
|
+
var BYTES_PER_EVENT = Uint8Array.BYTES_PER_ELEMENT + Uint32Array.BYTES_PER_ELEMENT * 4 + BigInt64Array.BYTES_PER_ELEMENT * 2;
|
|
409
|
+
var DEFAULT_MAX_EVENTS_PER_EXECUTION = 500;
|
|
410
|
+
var MAX_JOURNAL_EVENTS = 16384;
|
|
411
|
+
var elapsedMs = (startedAtNs, endedAtNs) => Number(endedAtNs - startedAtNs) / 1e6;
|
|
412
|
+
var roundedMilliseconds = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
|
|
413
|
+
var relativeMs = (relativeNs) => Number(relativeNs) / 1e6;
|
|
414
|
+
var sanitizeJournalCapacity = (value) => {
|
|
415
|
+
const requested = value ?? DEFAULT_MAX_EVENTS_PER_EXECUTION;
|
|
416
|
+
if (!Number.isFinite(requested)) return DEFAULT_MAX_EVENTS_PER_EXECUTION;
|
|
417
|
+
return Math.min(MAX_JOURNAL_EVENTS, Math.max(2, Math.floor(requested)));
|
|
418
|
+
};
|
|
419
|
+
var ExecutionJournal = class {
|
|
420
|
+
dropped = 0;
|
|
421
|
+
allocatedBytes = 0;
|
|
422
|
+
onGrow;
|
|
423
|
+
length = 0;
|
|
424
|
+
kind = new Uint8Array(0);
|
|
425
|
+
planId = new Uint32Array(0);
|
|
426
|
+
callId = new Uint32Array(0);
|
|
427
|
+
parentCallId = new Uint32Array(0);
|
|
428
|
+
timestampNs = new BigInt64Array(0);
|
|
429
|
+
durationNs = new BigInt64Array(0);
|
|
430
|
+
suppressionIndex = new Uint32Array(0);
|
|
431
|
+
payloads = [];
|
|
432
|
+
suppressions = [];
|
|
433
|
+
openCallIds = /* @__PURE__ */ new Set();
|
|
434
|
+
notedPlanIds = [];
|
|
435
|
+
notedPlanSet = /* @__PURE__ */ new Set();
|
|
436
|
+
maxCapacity;
|
|
393
437
|
constructor(capacity) {
|
|
394
|
-
this.
|
|
438
|
+
this.maxCapacity = sanitizeJournalCapacity(capacity);
|
|
439
|
+
this.reallocate(Math.min(this.maxCapacity, INITIAL_JOURNAL_STORAGE));
|
|
440
|
+
}
|
|
441
|
+
get capacity() {
|
|
442
|
+
return this.maxCapacity;
|
|
443
|
+
}
|
|
444
|
+
get hasOpenCalls() {
|
|
445
|
+
return this.openCallIds.size > 0;
|
|
446
|
+
}
|
|
447
|
+
get eventCount() {
|
|
448
|
+
return this.length;
|
|
449
|
+
}
|
|
450
|
+
get payloadSlotCount() {
|
|
451
|
+
return this.payloads.length;
|
|
395
452
|
}
|
|
396
|
-
items = [];
|
|
397
|
-
openCallIds = /* @__PURE__ */ new Set();
|
|
398
|
-
dropped = 0;
|
|
399
453
|
canStartCall() {
|
|
400
|
-
|
|
454
|
+
if (this.length + this.openCallIds.size + 2 > this.maxCapacity) return false;
|
|
455
|
+
return this.ensureCapacity(this.length + 2);
|
|
456
|
+
}
|
|
457
|
+
notePlan(runtimePlanId) {
|
|
458
|
+
if (this.notedPlanSet.has(runtimePlanId)) return;
|
|
459
|
+
this.notedPlanSet.add(runtimePlanId);
|
|
460
|
+
this.notedPlanIds.push(runtimePlanId);
|
|
401
461
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
this.
|
|
462
|
+
registerSuppression(group) {
|
|
463
|
+
if (group.storageIndex >= 0) return group;
|
|
464
|
+
group.storageIndex = this.suppressions.length;
|
|
465
|
+
this.suppressions.push(group);
|
|
466
|
+
return group;
|
|
467
|
+
}
|
|
468
|
+
startCall(runtimePlanId, callId, parentCallId, timestampNs, args) {
|
|
469
|
+
if (!this.write(
|
|
470
|
+
KIND_ENTER,
|
|
471
|
+
runtimePlanId,
|
|
472
|
+
callId,
|
|
473
|
+
parentCallId,
|
|
474
|
+
timestampNs,
|
|
475
|
+
0n,
|
|
476
|
+
args,
|
|
477
|
+
NO_SUPPRESSION
|
|
478
|
+
)) {
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
this.openCallIds.add(callId);
|
|
405
482
|
}
|
|
406
|
-
finishCall(
|
|
407
|
-
if (
|
|
408
|
-
|
|
409
|
-
this.items.push(event);
|
|
483
|
+
finishCall(kind, callId, timestampNs, durationNs, payload) {
|
|
484
|
+
if (!this.openCallIds.delete(callId)) return;
|
|
485
|
+
this.write(kind, 0, callId, void 0, timestampNs, durationNs, payload, NO_SUPPRESSION);
|
|
410
486
|
}
|
|
411
487
|
dropCall() {
|
|
412
488
|
this.dropped += 2;
|
|
413
489
|
}
|
|
414
|
-
|
|
415
|
-
if (this.
|
|
490
|
+
appendSuppressed(group) {
|
|
491
|
+
if (this.length + this.openCallIds.size + 1 > this.maxCapacity) {
|
|
492
|
+
this.dropped++;
|
|
493
|
+
return false;
|
|
494
|
+
}
|
|
495
|
+
this.registerSuppression(group);
|
|
496
|
+
group.retainedIndex = this.length;
|
|
497
|
+
if (!this.write(
|
|
498
|
+
KIND_SUPPRESSED,
|
|
499
|
+
group.runtimePlanId,
|
|
500
|
+
0,
|
|
501
|
+
group.parentCallId,
|
|
502
|
+
0n,
|
|
503
|
+
0n,
|
|
504
|
+
void 0,
|
|
505
|
+
group.storageIndex
|
|
506
|
+
)) {
|
|
507
|
+
group.retainedIndex = -1;
|
|
416
508
|
this.dropped++;
|
|
417
509
|
return false;
|
|
418
510
|
}
|
|
419
|
-
this.items.push(event);
|
|
420
511
|
return true;
|
|
421
512
|
}
|
|
422
|
-
forceCompletedCall(
|
|
423
|
-
while (this.
|
|
513
|
+
forceCompletedCall(runtimePlanId, callId, parentCallId, enterTimestampNs, args, terminalKind, terminalTimestampNs, durationNs, payload) {
|
|
514
|
+
while (this.length + this.openCallIds.size + 2 > this.maxCapacity) {
|
|
424
515
|
if (!this.evictCompletedLeafOrSummary()) {
|
|
425
516
|
this.dropCall();
|
|
426
517
|
return false;
|
|
427
518
|
}
|
|
428
519
|
}
|
|
429
|
-
this.
|
|
520
|
+
if (!this.ensureCapacity(this.length + 2)) {
|
|
521
|
+
this.dropCall();
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
this.write(
|
|
525
|
+
KIND_ENTER,
|
|
526
|
+
runtimePlanId,
|
|
527
|
+
callId,
|
|
528
|
+
parentCallId,
|
|
529
|
+
enterTimestampNs,
|
|
530
|
+
0n,
|
|
531
|
+
args,
|
|
532
|
+
NO_SUPPRESSION
|
|
533
|
+
);
|
|
534
|
+
this.write(
|
|
535
|
+
terminalKind,
|
|
536
|
+
0,
|
|
537
|
+
callId,
|
|
538
|
+
void 0,
|
|
539
|
+
terminalTimestampNs,
|
|
540
|
+
durationNs,
|
|
541
|
+
payload,
|
|
542
|
+
NO_SUPPRESSION
|
|
543
|
+
);
|
|
544
|
+
return true;
|
|
545
|
+
}
|
|
546
|
+
materialize(plansByRuntimeId, executionStartedAtNs) {
|
|
547
|
+
const events = [];
|
|
548
|
+
const referencedFunctionIds = /* @__PURE__ */ new Set();
|
|
549
|
+
for (let index = 0; index < this.length; index++) {
|
|
550
|
+
const event = this.eventAt(index, plansByRuntimeId, executionStartedAtNs);
|
|
551
|
+
if (!event) continue;
|
|
552
|
+
events.push(event);
|
|
553
|
+
if (event.type === "function_enter" || event.type === "function_calls_suppressed") {
|
|
554
|
+
referencedFunctionIds.add(event.functionId);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
const functions = [];
|
|
558
|
+
const seenFunctionIds = /* @__PURE__ */ new Set();
|
|
559
|
+
for (const runtimePlanId of this.notedPlanIds) {
|
|
560
|
+
const definition = plansByRuntimeId[runtimePlanId]?.definition;
|
|
561
|
+
if (!definition || !referencedFunctionIds.has(definition.functionId)) continue;
|
|
562
|
+
if (seenFunctionIds.has(definition.functionId)) continue;
|
|
563
|
+
seenFunctionIds.add(definition.functionId);
|
|
564
|
+
functions.push(definition);
|
|
565
|
+
}
|
|
566
|
+
return { events, functions };
|
|
567
|
+
}
|
|
568
|
+
clear() {
|
|
569
|
+
this.length = 0;
|
|
570
|
+
this.dropped = 0;
|
|
571
|
+
this.onGrow = void 0;
|
|
572
|
+
this.openCallIds.clear();
|
|
573
|
+
this.notedPlanIds.length = 0;
|
|
574
|
+
this.notedPlanSet.clear();
|
|
575
|
+
for (let index = 0; index < this.payloads.length; index++) this.payloads[index] = void 0;
|
|
576
|
+
this.payloads.length = 0;
|
|
577
|
+
for (const group of this.suppressions) {
|
|
578
|
+
group.retainedIndex = -1;
|
|
579
|
+
group.storageIndex = -1;
|
|
580
|
+
}
|
|
581
|
+
this.suppressions.length = 0;
|
|
582
|
+
}
|
|
583
|
+
eventAt(index, plansByRuntimeId, executionStartedAtNs) {
|
|
584
|
+
const kind = this.kind[index];
|
|
585
|
+
if (kind === KIND_ENTER) {
|
|
586
|
+
const functionId = plansByRuntimeId[this.planId[index] ?? 0]?.functionId;
|
|
587
|
+
if (!functionId) return void 0;
|
|
588
|
+
const parentCallId = this.parentCallId[index] ?? NO_PARENT;
|
|
589
|
+
const payload = this.payloads[index];
|
|
590
|
+
return {
|
|
591
|
+
type: "function_enter",
|
|
592
|
+
callId: this.callId[index] ?? 0,
|
|
593
|
+
functionId,
|
|
594
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
595
|
+
args: Array.isArray(payload) ? payload : [],
|
|
596
|
+
...parentCallId === NO_PARENT ? {} : { parentCallId }
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (kind === KIND_EXIT) {
|
|
600
|
+
return {
|
|
601
|
+
type: "function_exit",
|
|
602
|
+
callId: this.callId[index] ?? 0,
|
|
603
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
604
|
+
durationMs: relativeMs(this.durationNs[index] ?? 0n),
|
|
605
|
+
returnValue: this.payloads[index]
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (kind === KIND_THROW) {
|
|
609
|
+
return {
|
|
610
|
+
type: "function_throw",
|
|
611
|
+
callId: this.callId[index] ?? 0,
|
|
612
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
613
|
+
durationMs: relativeMs(this.durationNs[index] ?? 0n),
|
|
614
|
+
error: this.payloads[index]
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
if (kind === KIND_SUPPRESSED) {
|
|
618
|
+
const group = this.suppressions[this.suppressionIndex[index] ?? 0];
|
|
619
|
+
if (!group) return void 0;
|
|
620
|
+
return {
|
|
621
|
+
type: "function_calls_suppressed",
|
|
622
|
+
functionId: group.functionId,
|
|
623
|
+
timestampMs: elapsedMs(executionStartedAtNs, group.firstTimestampNs),
|
|
624
|
+
lastTimestampMs: elapsedMs(executionStartedAtNs, group.lastTimestampNs),
|
|
625
|
+
suppressedCallCount: group.count,
|
|
626
|
+
totalDurationMs: roundedMilliseconds(group.totalDurationNs),
|
|
627
|
+
...group.parentCallId === void 0 ? {} : { parentCallId: group.parentCallId }
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
return void 0;
|
|
631
|
+
}
|
|
632
|
+
write(kind, runtimePlanId, callId, parentCallId, timestampNs, durationNs, payload, suppressionIndex) {
|
|
633
|
+
if (!this.ensureCapacity(this.length + 1)) return false;
|
|
634
|
+
const index = this.length;
|
|
635
|
+
this.kind[index] = kind;
|
|
636
|
+
this.planId[index] = runtimePlanId;
|
|
637
|
+
this.callId[index] = callId;
|
|
638
|
+
this.parentCallId[index] = parentCallId === void 0 ? NO_PARENT : parentCallId;
|
|
639
|
+
this.timestampNs[index] = timestampNs;
|
|
640
|
+
this.durationNs[index] = durationNs;
|
|
641
|
+
this.payloads[index] = payload;
|
|
642
|
+
this.suppressionIndex[index] = suppressionIndex;
|
|
643
|
+
this.length++;
|
|
430
644
|
return true;
|
|
431
645
|
}
|
|
432
|
-
|
|
433
|
-
|
|
646
|
+
ensureCapacity(needed) {
|
|
647
|
+
if (needed <= this.kind.length) return true;
|
|
648
|
+
if (needed > this.maxCapacity) return false;
|
|
649
|
+
let next = this.kind.length === 0 ? Math.min(INITIAL_JOURNAL_STORAGE, this.maxCapacity) : this.kind.length;
|
|
650
|
+
while (next < needed) {
|
|
651
|
+
const grown = Math.min(this.maxCapacity, next * 2);
|
|
652
|
+
if (grown <= next) return false;
|
|
653
|
+
next = grown;
|
|
654
|
+
}
|
|
655
|
+
const extraBytes = (next - this.kind.length) * BYTES_PER_EVENT;
|
|
656
|
+
if (this.onGrow && extraBytes > 0 && !this.onGrow(extraBytes)) return false;
|
|
657
|
+
this.reallocate(next);
|
|
658
|
+
return true;
|
|
434
659
|
}
|
|
435
|
-
|
|
436
|
-
|
|
660
|
+
reallocate(size) {
|
|
661
|
+
const nextKind = new Uint8Array(size);
|
|
662
|
+
const nextPlanId = new Uint32Array(size);
|
|
663
|
+
const nextCallId = new Uint32Array(size);
|
|
664
|
+
const nextParentCallId = new Uint32Array(size);
|
|
665
|
+
const nextTimestampNs = new BigInt64Array(size);
|
|
666
|
+
const nextDurationNs = new BigInt64Array(size);
|
|
667
|
+
const nextSuppressionIndex = new Uint32Array(size);
|
|
668
|
+
if (this.length > 0) {
|
|
669
|
+
nextKind.set(this.kind.subarray(0, this.length));
|
|
670
|
+
nextPlanId.set(this.planId.subarray(0, this.length));
|
|
671
|
+
nextCallId.set(this.callId.subarray(0, this.length));
|
|
672
|
+
nextParentCallId.set(this.parentCallId.subarray(0, this.length));
|
|
673
|
+
nextTimestampNs.set(this.timestampNs.subarray(0, this.length));
|
|
674
|
+
nextDurationNs.set(this.durationNs.subarray(0, this.length));
|
|
675
|
+
nextSuppressionIndex.set(this.suppressionIndex.subarray(0, this.length));
|
|
676
|
+
}
|
|
677
|
+
this.kind = nextKind;
|
|
678
|
+
this.planId = nextPlanId;
|
|
679
|
+
this.callId = nextCallId;
|
|
680
|
+
this.parentCallId = nextParentCallId;
|
|
681
|
+
this.timestampNs = nextTimestampNs;
|
|
682
|
+
this.durationNs = nextDurationNs;
|
|
683
|
+
this.suppressionIndex = nextSuppressionIndex;
|
|
684
|
+
this.allocatedBytes = size * BYTES_PER_EVENT;
|
|
437
685
|
}
|
|
438
686
|
evictCompletedLeafOrSummary() {
|
|
439
|
-
|
|
440
|
-
(
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
this.
|
|
687
|
+
for (let index = 0; index < this.length; index++) {
|
|
688
|
+
if (this.kind[index] !== KIND_SUPPRESSED) continue;
|
|
689
|
+
const group = this.suppressions[this.suppressionIndex[index] ?? 0];
|
|
690
|
+
if (group) group.retainedIndex = -1;
|
|
691
|
+
this.removeAt(index);
|
|
444
692
|
this.dropped++;
|
|
445
693
|
return true;
|
|
446
694
|
}
|
|
447
695
|
const parentCallIds = /* @__PURE__ */ new Set();
|
|
448
|
-
for (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
696
|
+
for (let index = 0; index < this.length; index++) {
|
|
697
|
+
const kind = this.kind[index];
|
|
698
|
+
if (kind !== KIND_ENTER && kind !== KIND_SUPPRESSED) continue;
|
|
699
|
+
const parentCallId = this.parentCallId[index] ?? NO_PARENT;
|
|
700
|
+
if (parentCallId !== NO_PARENT) parentCallIds.add(parentCallId);
|
|
452
701
|
}
|
|
453
|
-
for (let index = 0; index < this.
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
702
|
+
for (let index = 0; index < this.length; index++) {
|
|
703
|
+
if (this.kind[index] !== KIND_ENTER) continue;
|
|
704
|
+
const eventCallId = this.callId[index] ?? 0;
|
|
705
|
+
if (this.openCallIds.has(eventCallId) || parentCallIds.has(eventCallId)) continue;
|
|
706
|
+
let terminalIndex = -1;
|
|
707
|
+
for (let candidate = 0; candidate < this.length; candidate++) {
|
|
708
|
+
const kind = this.kind[candidate];
|
|
709
|
+
if ((kind === KIND_EXIT || kind === KIND_THROW) && this.callId[candidate] === eventCallId) {
|
|
710
|
+
terminalIndex = candidate;
|
|
711
|
+
break;
|
|
712
|
+
}
|
|
457
713
|
}
|
|
458
|
-
const terminalIndex = this.items.findIndex(
|
|
459
|
-
(candidate) => (candidate.type === "function_exit" || candidate.type === "function_throw") && candidate.callId === event.callId
|
|
460
|
-
);
|
|
461
714
|
if (terminalIndex < 0) continue;
|
|
462
|
-
|
|
463
|
-
|
|
715
|
+
const later = Math.max(index, terminalIndex);
|
|
716
|
+
const earlier = Math.min(index, terminalIndex);
|
|
717
|
+
this.removeAt(later);
|
|
718
|
+
this.removeAt(earlier);
|
|
464
719
|
this.dropped += 2;
|
|
465
720
|
return true;
|
|
466
721
|
}
|
|
467
722
|
return false;
|
|
468
723
|
}
|
|
724
|
+
removeAt(index) {
|
|
725
|
+
this.payloads[index] = void 0;
|
|
726
|
+
const next = index + 1;
|
|
727
|
+
if (next < this.length) {
|
|
728
|
+
this.kind.copyWithin(index, next, this.length);
|
|
729
|
+
this.planId.copyWithin(index, next, this.length);
|
|
730
|
+
this.callId.copyWithin(index, next, this.length);
|
|
731
|
+
this.parentCallId.copyWithin(index, next, this.length);
|
|
732
|
+
this.timestampNs.copyWithin(index, next, this.length);
|
|
733
|
+
this.durationNs.copyWithin(index, next, this.length);
|
|
734
|
+
this.suppressionIndex.copyWithin(index, next, this.length);
|
|
735
|
+
this.payloads.copyWithin(index, next, this.length);
|
|
736
|
+
}
|
|
737
|
+
this.payloads[this.length - 1] = void 0;
|
|
738
|
+
this.length--;
|
|
739
|
+
this.payloads.length = this.length;
|
|
740
|
+
for (const group of this.suppressions) {
|
|
741
|
+
if (group.retainedIndex > index) group.retainedIndex--;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
var ExecutionJournalPool = class {
|
|
746
|
+
constructor(capacity, maxPooled = MAX_POOLED_JOURNALS) {
|
|
747
|
+
this.capacity = capacity;
|
|
748
|
+
this.maxPooled = maxPooled;
|
|
749
|
+
}
|
|
750
|
+
hits = 0;
|
|
751
|
+
misses = 0;
|
|
752
|
+
available = [];
|
|
753
|
+
acquire() {
|
|
754
|
+
const pooled = this.available.pop();
|
|
755
|
+
if (pooled) {
|
|
756
|
+
this.hits++;
|
|
757
|
+
return pooled;
|
|
758
|
+
}
|
|
759
|
+
this.misses++;
|
|
760
|
+
return new ExecutionJournal(this.capacity);
|
|
761
|
+
}
|
|
762
|
+
release(journal) {
|
|
763
|
+
journal.clear();
|
|
764
|
+
if (this.available.length >= this.maxPooled || journal.capacity > MAX_POOLED_JOURNAL_CAPACITY || journal.capacity !== this.capacity) {
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
this.available.push(journal);
|
|
768
|
+
}
|
|
769
|
+
stats() {
|
|
770
|
+
return {
|
|
771
|
+
journalPoolHits: this.hits,
|
|
772
|
+
journalPoolMisses: this.misses,
|
|
773
|
+
journalPoolSize: this.available.length,
|
|
774
|
+
journalAllocatedCapacity: this.capacity
|
|
775
|
+
};
|
|
776
|
+
}
|
|
469
777
|
};
|
|
470
778
|
|
|
471
779
|
// src/execution-recorder/recorder-memory-budget.ts
|
|
472
|
-
import { Buffer } from "node:buffer";
|
|
473
780
|
var EXECUTION_BASE_ESTIMATED_BYTES = 1024;
|
|
474
|
-
var EVENT_PAIR_BASE_ESTIMATED_BYTES = 512;
|
|
475
781
|
var SUMMARY_EVENT_BASE_ESTIMATED_BYTES = 256;
|
|
476
782
|
var VALUE_HEAP_ESTIMATE_MULTIPLIER = 2;
|
|
477
783
|
var MEMORY_BUDGET_VALUE_MARKER = {
|
|
@@ -525,12 +831,11 @@ var RecorderMemoryBudget = class {
|
|
|
525
831
|
}
|
|
526
832
|
return serialized.value;
|
|
527
833
|
}
|
|
528
|
-
reserveCall(allocation,
|
|
834
|
+
reserveCall(allocation, estimatedBytes) {
|
|
529
835
|
if (allocation.mode === "metadata-only") {
|
|
530
836
|
this.dropEvents(allocation, 2);
|
|
531
837
|
return false;
|
|
532
838
|
}
|
|
533
|
-
const estimatedBytes = EVENT_PAIR_BASE_ESTIMATED_BYTES + Buffer.byteLength(functionId, "utf8") * 2;
|
|
534
839
|
if (this.reserve(allocation, estimatedBytes)) return true;
|
|
535
840
|
this.markPressure(allocation, "metadata-only");
|
|
536
841
|
this.dropEvents(allocation, 2);
|
|
@@ -546,6 +851,12 @@ var RecorderMemoryBudget = class {
|
|
|
546
851
|
this.dropEvents(allocation, 1);
|
|
547
852
|
return false;
|
|
548
853
|
}
|
|
854
|
+
reserveStorage(allocation, bytes) {
|
|
855
|
+
if (allocation.released || allocation.mode === "metadata-only") return false;
|
|
856
|
+
if (this.reserve(allocation, bytes)) return true;
|
|
857
|
+
this.markPressure(allocation, "metadata-only");
|
|
858
|
+
return false;
|
|
859
|
+
}
|
|
549
860
|
release(allocation) {
|
|
550
861
|
if (allocation.released) return;
|
|
551
862
|
allocation.released = true;
|
|
@@ -590,7 +901,7 @@ var RecorderMemoryBudget = class {
|
|
|
590
901
|
|
|
591
902
|
// src/execution-recorder/safe-serialize.ts
|
|
592
903
|
import { Buffer as Buffer2 } from "node:buffer";
|
|
593
|
-
var DEFAULT_REDACT_KEYS =
|
|
904
|
+
var DEFAULT_REDACT_KEYS = [
|
|
594
905
|
"password",
|
|
595
906
|
"token",
|
|
596
907
|
"authorization",
|
|
@@ -598,7 +909,7 @@ var DEFAULT_REDACT_KEYS = /* @__PURE__ */ new Set([
|
|
|
598
909
|
"secret",
|
|
599
910
|
"apikey",
|
|
600
911
|
"creditcard"
|
|
601
|
-
]
|
|
912
|
+
];
|
|
602
913
|
var defaults = {
|
|
603
914
|
maxDepth: 3,
|
|
604
915
|
maxObjectKeys: 30,
|
|
@@ -606,6 +917,7 @@ var defaults = {
|
|
|
606
917
|
maxStringLength: 500,
|
|
607
918
|
maxSerializedValueBytes: 8 * 1024
|
|
608
919
|
};
|
|
920
|
+
var REDACTED = "[RASPUTIN_REDACTED]";
|
|
609
921
|
var truncation = (reason, extra = {}) => ({
|
|
610
922
|
__rasputin_truncated: true,
|
|
611
923
|
__reason: reason,
|
|
@@ -615,135 +927,436 @@ var typeMarker = (type, value) => ({
|
|
|
615
927
|
__rasputin_type: type,
|
|
616
928
|
...value === void 0 ? {} : { value }
|
|
617
929
|
});
|
|
618
|
-
var
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
930
|
+
var jsonStringUtf8Bytes = (value) => {
|
|
931
|
+
let bytes = 2;
|
|
932
|
+
for (let index = 0; index < value.length; index++) {
|
|
933
|
+
const code = value.charCodeAt(index);
|
|
934
|
+
if (code === 34 || code === 92) {
|
|
935
|
+
bytes += 2;
|
|
936
|
+
continue;
|
|
937
|
+
}
|
|
938
|
+
if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
|
|
939
|
+
bytes += 2;
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
if (code < 32) {
|
|
943
|
+
bytes += 6;
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
if (code < 128) {
|
|
947
|
+
bytes += 1;
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
if (code < 2048) {
|
|
951
|
+
bytes += 2;
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
if (code >= 55296 && code <= 56319) {
|
|
955
|
+
const next = value.charCodeAt(index + 1);
|
|
956
|
+
if (index + 1 < value.length && next >= 56320 && next <= 57343) {
|
|
957
|
+
bytes += 4;
|
|
958
|
+
index++;
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
bytes += 6;
|
|
962
|
+
continue;
|
|
963
|
+
}
|
|
964
|
+
if (code >= 56320 && code <= 57343) {
|
|
965
|
+
bytes += 6;
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
bytes += 3;
|
|
624
969
|
}
|
|
625
|
-
|
|
626
|
-
|
|
970
|
+
return bytes;
|
|
971
|
+
};
|
|
972
|
+
var jsonLiteralUtf8Bytes = (value) => {
|
|
973
|
+
if (value === null) return 4;
|
|
974
|
+
switch (typeof value) {
|
|
975
|
+
case "boolean":
|
|
976
|
+
return value ? 4 : 5;
|
|
977
|
+
case "number":
|
|
978
|
+
if (!Number.isFinite(value)) return 4;
|
|
979
|
+
if (Object.is(value, -0)) return 1;
|
|
980
|
+
return String(value).length;
|
|
981
|
+
case "string":
|
|
982
|
+
return jsonStringUtf8Bytes(value);
|
|
983
|
+
case "object": {
|
|
984
|
+
if (Array.isArray(value)) {
|
|
985
|
+
let bytes2 = 2;
|
|
986
|
+
for (let index = 0; index < value.length; index++) {
|
|
987
|
+
if (index > 0) bytes2 += 1;
|
|
988
|
+
bytes2 += jsonLiteralUtf8Bytes(value[index]);
|
|
989
|
+
}
|
|
990
|
+
return bytes2;
|
|
991
|
+
}
|
|
992
|
+
const record = value;
|
|
993
|
+
let bytes = 2;
|
|
994
|
+
let first = true;
|
|
995
|
+
for (const key of Object.keys(record)) {
|
|
996
|
+
if (!first) bytes += 1;
|
|
997
|
+
first = false;
|
|
998
|
+
bytes += jsonStringUtf8Bytes(key) + 1;
|
|
999
|
+
bytes += jsonLiteralUtf8Bytes(record[key]);
|
|
1000
|
+
}
|
|
1001
|
+
return bytes;
|
|
1002
|
+
}
|
|
1003
|
+
default:
|
|
1004
|
+
return Buffer2.byteLength(JSON.stringify(value) ?? "null", "utf8");
|
|
627
1005
|
}
|
|
628
|
-
return item;
|
|
629
1006
|
};
|
|
630
|
-
var
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
1007
|
+
var compileLimits = (options) => ({
|
|
1008
|
+
maxDepth: options.maxDepth ?? defaults.maxDepth,
|
|
1009
|
+
maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
|
|
1010
|
+
maxArrayElements: options.maxArrayElements ?? defaults.maxArrayElements,
|
|
1011
|
+
maxStringLength: options.maxStringLength ?? defaults.maxStringLength,
|
|
1012
|
+
maxSerializedValueBytes: options.maxSerializedValueBytes ?? defaults.maxSerializedValueBytes
|
|
635
1013
|
});
|
|
636
|
-
var
|
|
637
|
-
if (
|
|
1014
|
+
var compileRedactKeys = (options) => {
|
|
1015
|
+
if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
|
|
1016
|
+
return /* @__PURE__ */ new Set([...DEFAULT_REDACT_KEYS, ...options.redactKeys.map((key) => key.toLowerCase())]);
|
|
1017
|
+
};
|
|
1018
|
+
var keyNeedsCaseFold = (key) => {
|
|
1019
|
+
for (let index = 0; index < key.length; index++) {
|
|
1020
|
+
const code = key.charCodeAt(index);
|
|
1021
|
+
if (code > 127 || code >= 65 && code <= 90) return true;
|
|
1022
|
+
}
|
|
1023
|
+
return false;
|
|
1024
|
+
};
|
|
1025
|
+
var isJsonSafeString = (value) => {
|
|
1026
|
+
for (let index = 0; index < value.length; index++) {
|
|
1027
|
+
const code = value.charCodeAt(index);
|
|
1028
|
+
if (code < 32 || code === 34 || code === 92) return false;
|
|
1029
|
+
if (code >= 55296 && code <= 56319) {
|
|
1030
|
+
const next = value.charCodeAt(index + 1);
|
|
1031
|
+
if (index + 1 >= value.length || next < 56320 || next > 57343) return false;
|
|
1032
|
+
index++;
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (code >= 56320 && code <= 57343) return false;
|
|
1036
|
+
}
|
|
1037
|
+
return true;
|
|
1038
|
+
};
|
|
1039
|
+
var primitiveFastPath = (value, maxStringLength) => {
|
|
1040
|
+
if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
|
|
1041
|
+
if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
|
|
1042
|
+
if (typeof value === "number") {
|
|
1043
|
+
if (!Number.isFinite(value)) return { value, bytes: 4, visitedNodes: 1 };
|
|
1044
|
+
if (Object.is(value, -0)) return { value, bytes: 1, visitedNodes: 1 };
|
|
1045
|
+
return { value, bytes: String(value).length, visitedNodes: 1 };
|
|
1046
|
+
}
|
|
638
1047
|
if (typeof value === "string") {
|
|
639
|
-
if (value.length
|
|
640
|
-
return
|
|
641
|
-
__original_length: value.length,
|
|
642
|
-
value: value.slice(0, limits.maxStringLength)
|
|
643
|
-
});
|
|
1048
|
+
if (value.length > maxStringLength || !isJsonSafeString(value)) return void 0;
|
|
1049
|
+
return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
|
|
644
1050
|
}
|
|
645
|
-
if (typeof value === "undefined")
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
if (
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
1051
|
+
if (typeof value === "undefined") {
|
|
1052
|
+
const serialized = typeMarker("undefined");
|
|
1053
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
1054
|
+
}
|
|
1055
|
+
if (typeof value === "bigint") {
|
|
1056
|
+
const serialized = typeMarker("bigint", value.toString());
|
|
1057
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
1058
|
+
}
|
|
1059
|
+
if (typeof value === "symbol") {
|
|
1060
|
+
const text = String(value);
|
|
1061
|
+
if (!isJsonSafeString(text)) return void 0;
|
|
1062
|
+
const serialized = typeMarker("symbol", text);
|
|
1063
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
1064
|
+
}
|
|
1065
|
+
if (typeof value === "function") {
|
|
1066
|
+
const name = value.name || "anonymous";
|
|
1067
|
+
if (!isJsonSafeString(name)) return void 0;
|
|
1068
|
+
const serialized = typeMarker("function", name);
|
|
1069
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
1070
|
+
}
|
|
1071
|
+
return void 0;
|
|
1072
|
+
};
|
|
1073
|
+
var createSafeSerializer = (options = {}) => {
|
|
1074
|
+
const limits = compileLimits(options);
|
|
1075
|
+
const redactKeys = compileRedactKeys(options);
|
|
1076
|
+
const sharedPath = /* @__PURE__ */ new Set();
|
|
1077
|
+
let serializing = false;
|
|
1078
|
+
const isRedactedKey = (key) => {
|
|
1079
|
+
if (redactKeys.has(key)) return true;
|
|
1080
|
+
if (!keyNeedsCaseFold(key)) return false;
|
|
1081
|
+
return redactKeys.has(key.toLowerCase());
|
|
1082
|
+
};
|
|
1083
|
+
const addBytes = (metrics, count) => {
|
|
1084
|
+
metrics.bytes += count;
|
|
1085
|
+
if (metrics.bytes > limits.maxSerializedValueBytes) metrics.oversize = true;
|
|
1086
|
+
};
|
|
1087
|
+
const boundedOversize = (bytes, visitedNodes) => {
|
|
1088
|
+
const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
|
|
1089
|
+
return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
|
|
1090
|
+
};
|
|
1091
|
+
const openObject = (metrics, allocate) => {
|
|
1092
|
+
addBytes(metrics, 2);
|
|
1093
|
+
return {
|
|
1094
|
+
target: allocate && !metrics.oversize ? {} : void 0,
|
|
1095
|
+
first: true
|
|
1096
|
+
};
|
|
1097
|
+
};
|
|
1098
|
+
const openArray = (metrics, allocate) => {
|
|
1099
|
+
addBytes(metrics, 2);
|
|
1100
|
+
return {
|
|
1101
|
+
items: allocate && !metrics.oversize ? [] : void 0,
|
|
1102
|
+
first: true
|
|
1103
|
+
};
|
|
1104
|
+
};
|
|
1105
|
+
const beginField = (metrics, object, key) => {
|
|
1106
|
+
if (!object.first) addBytes(metrics, 1);
|
|
1107
|
+
object.first = false;
|
|
1108
|
+
addBytes(metrics, jsonStringUtf8Bytes(key) + 1);
|
|
1109
|
+
};
|
|
1110
|
+
const assignField = (object, key, fieldValue) => {
|
|
1111
|
+
if (object.target) object.target[key] = fieldValue;
|
|
1112
|
+
};
|
|
1113
|
+
const writeLiteralField = (metrics, object, key, jsonValue) => {
|
|
1114
|
+
beginField(metrics, object, key);
|
|
1115
|
+
addBytes(metrics, jsonLiteralUtf8Bytes(jsonValue));
|
|
1116
|
+
assignField(object, key, jsonValue);
|
|
1117
|
+
};
|
|
1118
|
+
const writeTypeMarker = (metrics, allocate, type, nestedValue) => {
|
|
1119
|
+
const object = openObject(metrics, allocate);
|
|
1120
|
+
writeLiteralField(metrics, object, "__rasputin_type", type);
|
|
1121
|
+
if (nestedValue !== void 0) writeLiteralField(metrics, object, "value", nestedValue);
|
|
1122
|
+
return object.target;
|
|
1123
|
+
};
|
|
1124
|
+
const writeTruncation = (metrics, allocate, reason, extra = {}) => {
|
|
1125
|
+
const object = openObject(metrics, allocate);
|
|
1126
|
+
writeLiteralField(metrics, object, "__rasputin_truncated", true);
|
|
1127
|
+
writeLiteralField(metrics, object, "__reason", reason);
|
|
1128
|
+
for (const key of Object.keys(extra)) writeLiteralField(metrics, object, key, extra[key]);
|
|
1129
|
+
return object.target;
|
|
1130
|
+
};
|
|
1131
|
+
const serializeInner = (value, depth, path, allocate, metrics) => {
|
|
1132
|
+
metrics.visitedNodes++;
|
|
1133
|
+
const store = allocate && !metrics.oversize;
|
|
1134
|
+
if (value === null) {
|
|
1135
|
+
addBytes(metrics, 4);
|
|
1136
|
+
return store ? null : void 0;
|
|
662
1137
|
}
|
|
663
|
-
if (value
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
}
|
|
673
|
-
return {
|
|
674
|
-
__rasputin_type: "Map",
|
|
675
|
-
entries,
|
|
676
|
-
...value.size > limits.maxArrayElements ? truncation("max_array_elements", { __original_length: value.size }) : {}
|
|
677
|
-
};
|
|
1138
|
+
if (typeof value === "boolean") {
|
|
1139
|
+
addBytes(metrics, value ? 4 : 5);
|
|
1140
|
+
return store ? value : void 0;
|
|
1141
|
+
}
|
|
1142
|
+
if (typeof value === "number") {
|
|
1143
|
+
if (!Number.isFinite(value)) addBytes(metrics, 4);
|
|
1144
|
+
else if (Object.is(value, -0)) addBytes(metrics, 1);
|
|
1145
|
+
else addBytes(metrics, String(value).length);
|
|
1146
|
+
return store ? value : void 0;
|
|
678
1147
|
}
|
|
679
|
-
if (value
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
items.push(serializeInner(item, depth + 1, seen, limits));
|
|
1148
|
+
if (typeof value === "string") {
|
|
1149
|
+
if (value.length <= limits.maxStringLength) {
|
|
1150
|
+
addBytes(metrics, jsonStringUtf8Bytes(value));
|
|
1151
|
+
return store ? value : void 0;
|
|
684
1152
|
}
|
|
685
|
-
return {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
1153
|
+
return writeTruncation(metrics, store, "max_string_length", {
|
|
1154
|
+
__original_length: value.length,
|
|
1155
|
+
value: value.slice(0, limits.maxStringLength)
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
if (typeof value === "undefined") return writeTypeMarker(metrics, store, "undefined");
|
|
1159
|
+
if (typeof value === "bigint") {
|
|
1160
|
+
return writeTypeMarker(metrics, store, "bigint", value.toString());
|
|
690
1161
|
}
|
|
691
|
-
if (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
1162
|
+
if (typeof value === "symbol") {
|
|
1163
|
+
return writeTypeMarker(metrics, store, "symbol", String(value));
|
|
1164
|
+
}
|
|
1165
|
+
if (typeof value === "function") {
|
|
1166
|
+
return writeTypeMarker(metrics, store, "function", value.name || "anonymous");
|
|
1167
|
+
}
|
|
1168
|
+
if (depth >= limits.maxDepth) return writeTruncation(metrics, store, "max_depth");
|
|
1169
|
+
if (typeof value !== "object") return writeTypeMarker(metrics, store, typeof value);
|
|
1170
|
+
if (path.has(value)) return writeTypeMarker(metrics, store, "circular");
|
|
1171
|
+
path.add(value);
|
|
1172
|
+
const bytesBefore = metrics.bytes;
|
|
1173
|
+
const oversizeBefore = metrics.oversize;
|
|
1174
|
+
try {
|
|
1175
|
+
const childAllocate = allocate && !metrics.oversize;
|
|
1176
|
+
if (value instanceof Error) {
|
|
1177
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1178
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Error");
|
|
1179
|
+
writeLiteralField(metrics, object2, "name", value.name);
|
|
1180
|
+
beginField(metrics, object2, "message");
|
|
1181
|
+
assignField(
|
|
1182
|
+
object2,
|
|
1183
|
+
"message",
|
|
1184
|
+
serializeInner(value.message, depth + 1, path, childAllocate, metrics)
|
|
1185
|
+
);
|
|
1186
|
+
if (value.stack) {
|
|
1187
|
+
beginField(metrics, object2, "stack");
|
|
1188
|
+
assignField(
|
|
1189
|
+
object2,
|
|
1190
|
+
"stack",
|
|
1191
|
+
serializeInner(value.stack, depth + 1, path, childAllocate, metrics)
|
|
1192
|
+
);
|
|
1193
|
+
}
|
|
1194
|
+
return object2.target;
|
|
1195
|
+
}
|
|
1196
|
+
if (value instanceof Date) {
|
|
1197
|
+
return writeTypeMarker(metrics, childAllocate, "Date", value.toISOString());
|
|
1198
|
+
}
|
|
1199
|
+
if (Buffer2.isBuffer(value)) {
|
|
1200
|
+
return writeTypeMarker(metrics, childAllocate, "Buffer", {
|
|
1201
|
+
byteLength: value.byteLength,
|
|
1202
|
+
base64: value.subarray(0, limits.maxStringLength).toString("base64"),
|
|
1203
|
+
...value.byteLength > limits.maxStringLength ? { __rasputin_truncated: true } : {}
|
|
1204
|
+
});
|
|
1205
|
+
}
|
|
1206
|
+
if (value instanceof Promise) return writeTypeMarker(metrics, childAllocate, "Promise");
|
|
1207
|
+
if (value instanceof Map) {
|
|
1208
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1209
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Map");
|
|
1210
|
+
beginField(metrics, object2, "entries");
|
|
1211
|
+
const entries = openArray(metrics, childAllocate);
|
|
1212
|
+
let counted2 = 0;
|
|
1213
|
+
for (const entry of value.entries()) {
|
|
1214
|
+
if (counted2 >= limits.maxArrayElements) break;
|
|
1215
|
+
if (!entries.first) addBytes(metrics, 1);
|
|
1216
|
+
entries.first = false;
|
|
1217
|
+
addBytes(metrics, 2);
|
|
1218
|
+
const key = serializeInner(entry[0], depth + 1, path, childAllocate, metrics);
|
|
1219
|
+
addBytes(metrics, 1);
|
|
1220
|
+
const mapped = serializeInner(entry[1], depth + 1, path, childAllocate, metrics);
|
|
1221
|
+
entries.items?.push([key, mapped]);
|
|
1222
|
+
counted2++;
|
|
1223
|
+
}
|
|
1224
|
+
assignField(object2, "entries", entries.items ?? []);
|
|
1225
|
+
if (value.size > limits.maxArrayElements) {
|
|
1226
|
+
writeLiteralField(metrics, object2, "__rasputin_truncated", true);
|
|
1227
|
+
writeLiteralField(metrics, object2, "__reason", "max_array_elements");
|
|
1228
|
+
writeLiteralField(metrics, object2, "__original_length", value.size);
|
|
1229
|
+
}
|
|
1230
|
+
return object2.target;
|
|
1231
|
+
}
|
|
1232
|
+
if (value instanceof Set) {
|
|
1233
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1234
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Set");
|
|
1235
|
+
beginField(metrics, object2, "values");
|
|
1236
|
+
const items = openArray(metrics, childAllocate);
|
|
1237
|
+
let counted2 = 0;
|
|
1238
|
+
for (const item of value.values()) {
|
|
1239
|
+
if (counted2 >= limits.maxArrayElements) break;
|
|
1240
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1241
|
+
items.first = false;
|
|
1242
|
+
const serializedItem = serializeInner(item, depth + 1, path, childAllocate, metrics);
|
|
1243
|
+
items.items?.push(serializedItem);
|
|
1244
|
+
counted2++;
|
|
1245
|
+
}
|
|
1246
|
+
assignField(object2, "values", items.items ?? []);
|
|
1247
|
+
if (value.size > limits.maxArrayElements) {
|
|
1248
|
+
writeLiteralField(metrics, object2, "__rasputin_truncated", true);
|
|
1249
|
+
writeLiteralField(metrics, object2, "__reason", "max_array_elements");
|
|
1250
|
+
writeLiteralField(metrics, object2, "__original_length", value.size);
|
|
1251
|
+
}
|
|
1252
|
+
return object2.target;
|
|
1253
|
+
}
|
|
1254
|
+
if (Array.isArray(value)) {
|
|
1255
|
+
const items = openArray(metrics, childAllocate);
|
|
1256
|
+
const maxItems = value.length > limits.maxArrayElements ? limits.maxArrayElements - 1 : value.length;
|
|
1257
|
+
for (let index = 0; index < maxItems; index++) {
|
|
1258
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1259
|
+
items.first = false;
|
|
1260
|
+
items.items?.push(serializeInner(value[index], depth + 1, path, childAllocate, metrics));
|
|
1261
|
+
}
|
|
1262
|
+
if (value.length > limits.maxArrayElements) {
|
|
1263
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1264
|
+
items.first = false;
|
|
1265
|
+
items.items?.push(
|
|
1266
|
+
writeTruncation(metrics, childAllocate, "max_array_elements", {
|
|
1267
|
+
__original_length: value.length
|
|
1268
|
+
})
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
return items.items;
|
|
1272
|
+
}
|
|
1273
|
+
const object = openObject(metrics, childAllocate);
|
|
1274
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1275
|
+
if (prototype && prototype !== Object.prototype) {
|
|
1276
|
+
writeLiteralField(
|
|
1277
|
+
metrics,
|
|
1278
|
+
object,
|
|
1279
|
+
"__rasputin_type",
|
|
1280
|
+
prototype.constructor?.name ?? "instance"
|
|
1281
|
+
);
|
|
696
1282
|
}
|
|
697
|
-
|
|
1283
|
+
const keys = Object.keys(value);
|
|
1284
|
+
const maxKeys = keys.length > limits.maxObjectKeys ? limits.maxObjectKeys - 1 : keys.length;
|
|
1285
|
+
for (let index = 0; index < maxKeys; index++) {
|
|
1286
|
+
const key = keys[index];
|
|
1287
|
+
if (key === void 0) continue;
|
|
1288
|
+
if (isRedactedKey(key)) {
|
|
1289
|
+
writeLiteralField(metrics, object, key, REDACTED);
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1293
|
+
if (descriptor && "value" in descriptor) {
|
|
1294
|
+
beginField(metrics, object, key);
|
|
1295
|
+
assignField(
|
|
1296
|
+
object,
|
|
1297
|
+
key,
|
|
1298
|
+
serializeInner(descriptor.value, depth + 1, path, childAllocate, metrics)
|
|
1299
|
+
);
|
|
1300
|
+
} else {
|
|
1301
|
+
beginField(metrics, object, key);
|
|
1302
|
+
assignField(object, key, writeTypeMarker(metrics, childAllocate, "accessor"));
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
if (keys.length > limits.maxObjectKeys) {
|
|
1306
|
+
writeLiteralField(metrics, object, "__rasputin_truncated", true);
|
|
1307
|
+
writeLiteralField(metrics, object, "__reason", "max_object_keys");
|
|
1308
|
+
writeLiteralField(metrics, object, "__original_length", keys.length);
|
|
1309
|
+
}
|
|
1310
|
+
return object.target;
|
|
1311
|
+
} catch (error) {
|
|
1312
|
+
metrics.bytes = bytesBefore;
|
|
1313
|
+
metrics.oversize = oversizeBefore;
|
|
1314
|
+
return writeTypeMarker(
|
|
1315
|
+
metrics,
|
|
1316
|
+
allocate && !metrics.oversize,
|
|
1317
|
+
"unserializable",
|
|
1318
|
+
error instanceof Error ? error.message : void 0
|
|
1319
|
+
);
|
|
1320
|
+
} finally {
|
|
1321
|
+
path.delete(value);
|
|
698
1322
|
}
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
1323
|
+
};
|
|
1324
|
+
const serializeWithBytes = (value) => {
|
|
1325
|
+
const fast = primitiveFastPath(value, limits.maxStringLength);
|
|
1326
|
+
if (fast) {
|
|
1327
|
+
return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
|
|
703
1328
|
}
|
|
704
|
-
const
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
1329
|
+
const metrics = { visitedNodes: 0, bytes: 0, oversize: false };
|
|
1330
|
+
const reentrant = serializing;
|
|
1331
|
+
const path = reentrant ? /* @__PURE__ */ new Set() : sharedPath;
|
|
1332
|
+
if (!reentrant) {
|
|
1333
|
+
serializing = true;
|
|
1334
|
+
sharedPath.clear();
|
|
709
1335
|
}
|
|
710
|
-
|
|
711
|
-
|
|
1336
|
+
try {
|
|
1337
|
+
const serialized = serializeInner(value, 0, path, true, metrics);
|
|
1338
|
+
if (metrics.bytes > limits.maxSerializedValueBytes) {
|
|
1339
|
+
return boundedOversize(metrics.bytes, metrics.visitedNodes);
|
|
1340
|
+
}
|
|
1341
|
+
return { value: serialized, bytes: metrics.bytes, visitedNodes: metrics.visitedNodes };
|
|
1342
|
+
} catch {
|
|
1343
|
+
const failed = typeMarker("unserializable");
|
|
1344
|
+
return {
|
|
1345
|
+
value: failed,
|
|
1346
|
+
bytes: jsonLiteralUtf8Bytes(failed),
|
|
1347
|
+
visitedNodes: metrics.visitedNodes
|
|
1348
|
+
};
|
|
1349
|
+
} finally {
|
|
1350
|
+
path.clear();
|
|
1351
|
+
if (!reentrant) serializing = false;
|
|
712
1352
|
}
|
|
713
|
-
return serialized;
|
|
714
|
-
} catch (error) {
|
|
715
|
-
return typeMarker("unserializable", error instanceof Error ? error.message : void 0);
|
|
716
|
-
} finally {
|
|
717
|
-
seen.delete(value);
|
|
718
|
-
}
|
|
719
|
-
};
|
|
720
|
-
var safeSerializeWithBytes = (value, options = {}) => {
|
|
721
|
-
const limits = {
|
|
722
|
-
maxDepth: options.maxDepth ?? defaults.maxDepth,
|
|
723
|
-
maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
|
|
724
|
-
maxArrayElements: options.maxArrayElements ?? defaults.maxArrayElements,
|
|
725
|
-
maxStringLength: options.maxStringLength ?? defaults.maxStringLength,
|
|
726
|
-
maxSerializedValueBytes: options.maxSerializedValueBytes ?? defaults.maxSerializedValueBytes
|
|
727
1353
|
};
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
]);
|
|
733
|
-
const serialized = serializeInner(value, 0, /* @__PURE__ */ new WeakSet(), limits);
|
|
734
|
-
const redacted = redact(serialized, redactKeys, /* @__PURE__ */ new WeakSet());
|
|
735
|
-
const bytes = Buffer2.byteLength(JSON.stringify(redacted), "utf8");
|
|
736
|
-
const bounded = bytes <= limits.maxSerializedValueBytes ? redacted : truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
|
|
737
|
-
return {
|
|
738
|
-
value: bounded,
|
|
739
|
-
bytes: bounded === redacted ? bytes : Buffer2.byteLength(JSON.stringify(bounded), "utf8")
|
|
740
|
-
};
|
|
741
|
-
} catch {
|
|
742
|
-
const value2 = typeMarker("unserializable");
|
|
743
|
-
return { value: value2, bytes: Buffer2.byteLength(JSON.stringify(value2), "utf8") };
|
|
744
|
-
}
|
|
1354
|
+
return {
|
|
1355
|
+
serialize: (value) => serializeWithBytes(value).value,
|
|
1356
|
+
serializeWithBytes
|
|
1357
|
+
};
|
|
745
1358
|
};
|
|
746
|
-
var
|
|
1359
|
+
var defaultSerializer = createSafeSerializer();
|
|
747
1360
|
|
|
748
1361
|
// src/execution-recorder/source-exclusions.ts
|
|
749
1362
|
var sourcePathFrom = (definition) => definition.source?.packageRelativePath.replaceAll("\\", "/") ?? definition.name;
|
|
@@ -811,6 +1424,8 @@ var createSourceExclusionMatcher = (exclusions) => {
|
|
|
811
1424
|
|
|
812
1425
|
// src/execution-recorder/execution-recorder.ts
|
|
813
1426
|
var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
|
|
1427
|
+
var DERIVATION_ROOT_RECORD_BYTES = 64;
|
|
1428
|
+
var phaseTimingEnabled = process.env.RASPUTIN_RECORDER_PHASE_TIMING === "1";
|
|
814
1429
|
var manualFunctionDefinition = (value) => {
|
|
815
1430
|
const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
|
|
816
1431
|
const named = located ? void 0 : /^(.+):([^:@]+)$/.exec(value);
|
|
@@ -825,8 +1440,8 @@ var manualFunctionDefinition = (value) => {
|
|
|
825
1440
|
return { ...definition, functionId: runtimeFunctionId2(definition) };
|
|
826
1441
|
};
|
|
827
1442
|
var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualFunctionDefinition(value) : value;
|
|
828
|
-
var
|
|
829
|
-
var
|
|
1443
|
+
var elapsedMs2 = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
|
|
1444
|
+
var roundedMilliseconds2 = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
|
|
830
1445
|
var addRecorderTime = (recording, nanoseconds) => {
|
|
831
1446
|
if (nanoseconds > 0n) recording.inlineRecorderTimeNs += nanoseconds;
|
|
832
1447
|
};
|
|
@@ -896,6 +1511,43 @@ var observeRecordedCallback = (recording, recorderStartedAtNs, callback, onRetur
|
|
|
896
1511
|
recordExitWork(callbackEndedAtNs);
|
|
897
1512
|
return result;
|
|
898
1513
|
};
|
|
1514
|
+
var emptyStats = {
|
|
1515
|
+
functionCallsObserved: 0,
|
|
1516
|
+
functionCallsCaptured: 0,
|
|
1517
|
+
functionCallsExcluded: 0,
|
|
1518
|
+
serializedValues: 0,
|
|
1519
|
+
serializedValueNodes: 0,
|
|
1520
|
+
serializedValueBytes: 0,
|
|
1521
|
+
errorSnapshots: 0,
|
|
1522
|
+
successfulExecutionsDiscarded: 0,
|
|
1523
|
+
truncatedEvents: 0,
|
|
1524
|
+
repeatedCallsSuppressed: 0,
|
|
1525
|
+
activeExecutions: 0,
|
|
1526
|
+
peakActiveExecutions: 0,
|
|
1527
|
+
memoryPressureExecutions: 0,
|
|
1528
|
+
memoryPressureDegradations: 0,
|
|
1529
|
+
valuesDroppedByMemoryBudget: 0,
|
|
1530
|
+
eventsDroppedByMemoryBudget: 0,
|
|
1531
|
+
partialErrorSnapshots: 0,
|
|
1532
|
+
measuredExecutions: 0,
|
|
1533
|
+
totalInlineWallTimeMs: 0,
|
|
1534
|
+
maxInlineWallTimeMs: 0,
|
|
1535
|
+
activeEstimatedBytes: 0,
|
|
1536
|
+
peakActiveEstimatedBytes: 0,
|
|
1537
|
+
journalPoolHits: 0,
|
|
1538
|
+
journalPoolMisses: 0,
|
|
1539
|
+
journalPoolSize: 0,
|
|
1540
|
+
journalAllocatedCapacity: 0,
|
|
1541
|
+
derivationCandidateFunctions: 0,
|
|
1542
|
+
derivationElidedFunctionCalls: 0,
|
|
1543
|
+
derivationRootsCaptured: 0,
|
|
1544
|
+
derivationControlFactsCaptured: 0,
|
|
1545
|
+
derivationValuesAvoided: 0,
|
|
1546
|
+
derivationFallbackFunctions: 0,
|
|
1547
|
+
derivationFallbackExpressions: 0,
|
|
1548
|
+
derivationFallbackReasons: {},
|
|
1549
|
+
derivationRootBytes: 0
|
|
1550
|
+
};
|
|
899
1551
|
var noOpExecution = {
|
|
900
1552
|
createScope: () => ({
|
|
901
1553
|
run: (callback) => callback(),
|
|
@@ -906,35 +1558,38 @@ var noOpExecution = {
|
|
|
906
1558
|
run: (_metadata, callback) => callback(),
|
|
907
1559
|
getErrorState: () => void 0,
|
|
908
1560
|
runFunction: (_functionId, _args, callback) => callback(),
|
|
1561
|
+
runFunctionPlans: (_plans, _planIndex, _args, callback) => callback(),
|
|
1562
|
+
prepareFunctionPlans: () => [],
|
|
1563
|
+
runPreparedFunction: (_plan, _args, callback) => callback(),
|
|
909
1564
|
trace: (_functionId, fn) => fn,
|
|
910
|
-
getStats: () => ({
|
|
911
|
-
|
|
912
|
-
successfulExecutionsDiscarded: 0,
|
|
913
|
-
truncatedEvents: 0,
|
|
914
|
-
repeatedCallsSuppressed: 0,
|
|
915
|
-
activeExecutions: 0,
|
|
916
|
-
peakActiveExecutions: 0,
|
|
917
|
-
activeEstimatedBytes: 0,
|
|
918
|
-
peakActiveEstimatedBytes: 0,
|
|
919
|
-
memoryPressureExecutions: 0,
|
|
920
|
-
memoryPressureDegradations: 0,
|
|
921
|
-
valuesDroppedByMemoryBudget: 0,
|
|
922
|
-
eventsDroppedByMemoryBudget: 0,
|
|
923
|
-
partialErrorSnapshots: 0,
|
|
924
|
-
measuredExecutions: 0,
|
|
925
|
-
totalInlineWallTimeMs: 0,
|
|
926
|
-
maxInlineWallTimeMs: 0
|
|
927
|
-
})
|
|
1565
|
+
getStats: () => ({ ...emptyStats, derivationFallbackReasons: {} }),
|
|
1566
|
+
captureDerivationRoot: (_rootId, value) => value
|
|
928
1567
|
};
|
|
929
1568
|
var mergeExecutionMetadata = (target, metadata) => {
|
|
930
1569
|
if (metadata.kind) target.kind = metadata.kind;
|
|
931
1570
|
if (metadata.name !== void 0) target.name = metadata.name;
|
|
932
1571
|
if (metadata.request) target.request = { ...target.request, ...metadata.request };
|
|
933
1572
|
};
|
|
1573
|
+
var newRepeatedGroup = (plan) => ({
|
|
1574
|
+
observedCalls: 0,
|
|
1575
|
+
functionId: plan.functionId,
|
|
1576
|
+
runtimePlanId: plan.runtimePlanId
|
|
1577
|
+
});
|
|
1578
|
+
var newSuppression = (group, parentCallId, startedAtNs, endedAtNs) => ({
|
|
1579
|
+
count: 1,
|
|
1580
|
+
firstTimestampNs: startedAtNs,
|
|
1581
|
+
lastTimestampNs: endedAtNs,
|
|
1582
|
+
totalDurationNs: endedAtNs - startedAtNs,
|
|
1583
|
+
functionId: group.functionId,
|
|
1584
|
+
runtimePlanId: group.runtimePlanId,
|
|
1585
|
+
...parentCallId === void 0 ? {} : { parentCallId },
|
|
1586
|
+
storageIndex: -1,
|
|
1587
|
+
retainedIndex: -1
|
|
1588
|
+
});
|
|
934
1589
|
var createExecutionRecorder = (options) => {
|
|
935
1590
|
if (!options?.enabled) return noOpExecution;
|
|
936
1591
|
const storage = new AsyncLocalStorage();
|
|
937
|
-
const maxEventsPerExecution =
|
|
1592
|
+
const maxEventsPerExecution = sanitizeJournalCapacity(options.maxEventsPerExecution);
|
|
938
1593
|
const maxCapturedCallsPerFunction = Math.max(
|
|
939
1594
|
1,
|
|
940
1595
|
Math.floor(options.maxCapturedCallsPerFunction ?? 3)
|
|
@@ -947,10 +1602,23 @@ var createExecutionRecorder = (options) => {
|
|
|
947
1602
|
maxActiveMemoryBytes,
|
|
948
1603
|
options.maxSerializedValueBytes ?? 8 * 1024
|
|
949
1604
|
);
|
|
1605
|
+
const serializer = createSafeSerializer(options);
|
|
950
1606
|
const excludesSource = createSourceExclusionMatcher(options.excludeSources);
|
|
1607
|
+
const journalPool = new ExecutionJournalPool(maxEventsPerExecution);
|
|
1608
|
+
const plansByRuntimeId = [];
|
|
951
1609
|
let executionCounter = 0;
|
|
1610
|
+
let nextRuntimePlanId = 1;
|
|
1611
|
+
const internedPlans = /* @__PURE__ */ new Map();
|
|
1612
|
+
const preparedModules = /* @__PURE__ */ new WeakMap();
|
|
952
1613
|
const errorExecutions = /* @__PURE__ */ new WeakMap();
|
|
1614
|
+
const phases = phaseTimingEnabled ? { alsNs: 0n, materializeNs: 0n } : void 0;
|
|
953
1615
|
const stats = {
|
|
1616
|
+
functionCallsObserved: 0,
|
|
1617
|
+
functionCallsCaptured: 0,
|
|
1618
|
+
functionCallsExcluded: 0,
|
|
1619
|
+
serializedValues: 0,
|
|
1620
|
+
serializedValueNodes: 0,
|
|
1621
|
+
serializedValueBytes: 0,
|
|
954
1622
|
errorSnapshots: 0,
|
|
955
1623
|
successfulExecutionsDiscarded: 0,
|
|
956
1624
|
truncatedEvents: 0,
|
|
@@ -960,49 +1628,185 @@ var createExecutionRecorder = (options) => {
|
|
|
960
1628
|
partialErrorSnapshots: 0,
|
|
961
1629
|
measuredExecutions: 0,
|
|
962
1630
|
totalInlineWallTimeMs: 0,
|
|
963
|
-
maxInlineWallTimeMs: 0
|
|
1631
|
+
maxInlineWallTimeMs: 0,
|
|
1632
|
+
derivationCandidateFunctions: 0,
|
|
1633
|
+
derivationElidedFunctionCalls: 0,
|
|
1634
|
+
derivationRootsCaptured: 0,
|
|
1635
|
+
derivationControlFactsCaptured: 0,
|
|
1636
|
+
derivationValuesAvoided: 0,
|
|
1637
|
+
derivationFallbackFunctions: 0,
|
|
1638
|
+
derivationFallbackExpressions: 0,
|
|
1639
|
+
derivationFallbackReasons: {},
|
|
1640
|
+
derivationRootBytes: 0
|
|
1641
|
+
};
|
|
1642
|
+
const addPhase = (key, nanoseconds) => {
|
|
1643
|
+
if (phases && nanoseconds > 0n) phases[key] += nanoseconds;
|
|
964
1644
|
};
|
|
965
1645
|
const recordInlineTiming = (recording) => {
|
|
966
|
-
const inlineWallTimeMs =
|
|
1646
|
+
const inlineWallTimeMs = roundedMilliseconds2(recording.inlineRecorderTimeNs);
|
|
967
1647
|
stats.measuredExecutions++;
|
|
968
1648
|
stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
|
|
969
1649
|
stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
|
|
970
1650
|
};
|
|
971
|
-
const
|
|
1651
|
+
const serializeAndCount = (value) => {
|
|
1652
|
+
const serialized = serializer.serializeWithBytes(value);
|
|
1653
|
+
stats.serializedValues++;
|
|
1654
|
+
stats.serializedValueNodes += serialized.visitedNodes;
|
|
1655
|
+
stats.serializedValueBytes += serialized.bytes;
|
|
1656
|
+
return serialized;
|
|
1657
|
+
};
|
|
1658
|
+
const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => serializeAndCount(value));
|
|
1659
|
+
const storePlan = (plan) => {
|
|
1660
|
+
plansByRuntimeId[plan.runtimePlanId] = plan;
|
|
1661
|
+
return plan;
|
|
1662
|
+
};
|
|
1663
|
+
const preparePlan = (definition) => {
|
|
1664
|
+
const existing = internedPlans.get(definition.functionId);
|
|
1665
|
+
if (existing) return existing;
|
|
1666
|
+
const plan = storePlan({
|
|
1667
|
+
runtimePlanId: nextRuntimePlanId++,
|
|
1668
|
+
definition,
|
|
1669
|
+
functionId: definition.functionId,
|
|
1670
|
+
excluded: excludesSource(definition),
|
|
1671
|
+
estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
|
|
1672
|
+
});
|
|
1673
|
+
internedPlans.set(definition.functionId, plan);
|
|
1674
|
+
return plan;
|
|
1675
|
+
};
|
|
1676
|
+
const preparedPlansFor = (plans) => {
|
|
1677
|
+
const cached = preparedModules.get(plans);
|
|
1678
|
+
if (cached) return cached;
|
|
1679
|
+
const prepared = plans.map((encoded) => {
|
|
1680
|
+
const definition = definitionFromEncodedPlan(encoded);
|
|
1681
|
+
return storePlan({
|
|
1682
|
+
runtimePlanId: nextRuntimePlanId++,
|
|
1683
|
+
definition,
|
|
1684
|
+
functionId: definition.functionId,
|
|
1685
|
+
excluded: excludesSource(definition),
|
|
1686
|
+
estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
|
|
1687
|
+
});
|
|
1688
|
+
});
|
|
1689
|
+
preparedModules.set(plans, prepared);
|
|
1690
|
+
return prepared;
|
|
1691
|
+
};
|
|
1692
|
+
const derivationMetrics = (recording) => {
|
|
1693
|
+
const manifest = snapshotInstrumentationManifest();
|
|
1694
|
+
const plans = manifest?.derivationPlans ?? [];
|
|
1695
|
+
const reasons = { ...stats.derivationFallbackReasons };
|
|
1696
|
+
return {
|
|
1697
|
+
derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
|
|
1698
|
+
derivationElidedFunctionCalls: stats.derivationElidedFunctionCalls,
|
|
1699
|
+
derivationRootsCaptured: recording.derivationRoots.length,
|
|
1700
|
+
derivationControlFactsCaptured: stats.derivationControlFactsCaptured,
|
|
1701
|
+
derivationValuesAvoided: stats.derivationValuesAvoided,
|
|
1702
|
+
derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
|
|
1703
|
+
derivationFallbackExpressions: recording.derivationRoots.length,
|
|
1704
|
+
derivationFallbackReasons: reasons,
|
|
1705
|
+
derivationRootBytes: recording.derivationRootBytes
|
|
1706
|
+
};
|
|
1707
|
+
};
|
|
1708
|
+
const eventsHaveOmittedValues = (events) => {
|
|
1709
|
+
for (const event of events) {
|
|
1710
|
+
if (event.type === "function_enter" && event.args.some((arg) => rasputinTagKind(arg) === "omitted")) {
|
|
1711
|
+
return true;
|
|
1712
|
+
}
|
|
1713
|
+
if (event.type === "function_exit" && rasputinTagKind(event.returnValue) === "omitted") {
|
|
1714
|
+
return true;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
return false;
|
|
1718
|
+
};
|
|
1719
|
+
const resolveCaptureProfile = (recording, events, truncated, capture, derivation) => {
|
|
1720
|
+
const source = recording.sawAutomatic ? "automatic" : recording.sawManual ? "manual" : "scope-only";
|
|
1721
|
+
if (source === "scope-only") {
|
|
1722
|
+
return {
|
|
1723
|
+
source,
|
|
1724
|
+
functionBoundaries: "none",
|
|
1725
|
+
functionValues: "none",
|
|
1726
|
+
timings: "none",
|
|
1727
|
+
derivation: derivation ? "available" : "none"
|
|
1728
|
+
};
|
|
1729
|
+
}
|
|
1730
|
+
const droppedEvents = Boolean(truncated?.eventsDropped || capture?.eventsDropped);
|
|
1731
|
+
return {
|
|
1732
|
+
source,
|
|
1733
|
+
functionBoundaries: droppedEvents ? "partial" : "full",
|
|
1734
|
+
functionValues: eventsHaveOmittedValues(events) ? "selective" : "full",
|
|
1735
|
+
timings: droppedEvents ? "partial" : "full",
|
|
1736
|
+
derivation: derivation ? "available" : "none"
|
|
1737
|
+
};
|
|
1738
|
+
};
|
|
1739
|
+
const derivationCapture = (recording, functions) => {
|
|
1740
|
+
const manifest = snapshotInstrumentationManifest();
|
|
1741
|
+
if (!manifest) return void 0;
|
|
1742
|
+
const plans = manifest.derivationPlans ?? [];
|
|
1743
|
+
const recordedIds = new Set(functions.map((fn) => fn.functionId));
|
|
1744
|
+
if (!plans.some((plan) => recordedIds.has(plan.functionId))) {
|
|
1745
|
+
return void 0;
|
|
1746
|
+
}
|
|
1747
|
+
return {
|
|
1748
|
+
manifestHash: hashInstrumentationManifest(manifest),
|
|
1749
|
+
roots: recording.derivationRoots.slice(),
|
|
1750
|
+
controlFacts: []
|
|
1751
|
+
};
|
|
1752
|
+
};
|
|
972
1753
|
const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
|
|
973
1754
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
)
|
|
1755
|
+
let events = [];
|
|
1756
|
+
let functions = [];
|
|
1757
|
+
let truncated;
|
|
1758
|
+
let capture;
|
|
1759
|
+
let derivation;
|
|
1760
|
+
if (recording.cachedState) {
|
|
1761
|
+
events = recording.cachedState.events;
|
|
1762
|
+
functions = recording.cachedState.functions;
|
|
1763
|
+
truncated = recording.cachedState.truncated;
|
|
1764
|
+
capture = recording.cachedState.capture;
|
|
1765
|
+
derivation = recording.cachedState.derivation;
|
|
1766
|
+
} else {
|
|
1767
|
+
if (recording.journal) {
|
|
1768
|
+
const materialized = recording.journal.materialize(plansByRuntimeId, recording.startedAtNs);
|
|
1769
|
+
events = materialized.events;
|
|
1770
|
+
functions = materialized.functions;
|
|
1771
|
+
truncated = recording.journal.dropped > 0 ? { eventsDropped: recording.journal.dropped } : void 0;
|
|
1772
|
+
}
|
|
1773
|
+
capture = recording.memory.underPressure ? {
|
|
1774
|
+
completeness: "partial",
|
|
1775
|
+
reason: "process_memory_budget",
|
|
1776
|
+
valuesDropped: recording.memory.valuesDropped,
|
|
1777
|
+
eventsDropped: recording.memory.eventsDropped
|
|
1778
|
+
} : void 0;
|
|
1779
|
+
derivation = derivationCapture(recording, functions);
|
|
1780
|
+
if (recording.finished && recording.inFlightCalls === 0 && recording.journal) {
|
|
1781
|
+
recording.cachedState = { events, functions, truncated, capture, derivation };
|
|
1782
|
+
journalPool.release(recording.journal);
|
|
1783
|
+
recording.journal = void 0;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
980
1786
|
const state = {
|
|
981
|
-
version:
|
|
1787
|
+
version: 4,
|
|
1788
|
+
captureProfile: resolveCaptureProfile(recording, events, truncated, capture, derivation),
|
|
982
1789
|
executionId: recording.executionId,
|
|
983
1790
|
startedAt: recording.startedAt,
|
|
984
|
-
durationMs:
|
|
985
|
-
recorder: { inlineWallTimeMs: 0 },
|
|
1791
|
+
durationMs: elapsedMs2(recording.startedAtNs, endedAtNs),
|
|
1792
|
+
recorder: { inlineWallTimeMs: 0, derivation: derivationMetrics(recording) },
|
|
986
1793
|
execution: {
|
|
987
1794
|
...recording.execution,
|
|
988
1795
|
...recording.execution.request ? { request: { ...recording.execution.request } } : {}
|
|
989
1796
|
},
|
|
990
|
-
functions:
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
...
|
|
995
|
-
...recording.memory.underPressure ? {
|
|
996
|
-
capture: {
|
|
997
|
-
completeness: "partial",
|
|
998
|
-
reason: "process_memory_budget",
|
|
999
|
-
valuesDropped: recording.memory.valuesDropped,
|
|
1000
|
-
eventsDropped: recording.memory.eventsDropped
|
|
1001
|
-
}
|
|
1002
|
-
} : {}
|
|
1797
|
+
functions: functions.slice(),
|
|
1798
|
+
events: events.slice(),
|
|
1799
|
+
...truncated ? { truncated: { ...truncated } } : {},
|
|
1800
|
+
...capture ? { capture: { ...capture } } : {},
|
|
1801
|
+
...derivation ? { derivation: { ...derivation, roots: derivation.roots.slice() } } : {}
|
|
1003
1802
|
};
|
|
1803
|
+
if (phaseTimingEnabled)
|
|
1804
|
+
addPhase("materializeNs", process.hrtime.bigint() - recorderStartedAtNs);
|
|
1004
1805
|
addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
1005
|
-
state.recorder = {
|
|
1806
|
+
state.recorder = {
|
|
1807
|
+
inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs),
|
|
1808
|
+
derivation: derivationMetrics(recording)
|
|
1809
|
+
};
|
|
1006
1810
|
return state;
|
|
1007
1811
|
};
|
|
1008
1812
|
const rememberError = (error, recording) => {
|
|
@@ -1018,25 +1822,38 @@ var createExecutionRecorder = (options) => {
|
|
|
1018
1822
|
errorExecutions.set(error, recording);
|
|
1019
1823
|
};
|
|
1020
1824
|
const countDroppedEvents = (recording, droppedBefore) => {
|
|
1021
|
-
|
|
1825
|
+
const dropped = recording.journal?.dropped ?? droppedBefore;
|
|
1826
|
+
stats.truncatedEvents += dropped - droppedBefore;
|
|
1022
1827
|
};
|
|
1023
|
-
const
|
|
1828
|
+
const appendSuppressedPlaceholder = (recording, group) => {
|
|
1829
|
+
if (!recording.journal) return;
|
|
1024
1830
|
if (!memoryBudget.reserveStandaloneEvent(recording.memory)) return;
|
|
1025
|
-
const droppedBefore = recording.
|
|
1026
|
-
recording.
|
|
1831
|
+
const droppedBefore = recording.journal.dropped;
|
|
1832
|
+
recording.journal.appendSuppressed(group);
|
|
1027
1833
|
countDroppedEvents(recording, droppedBefore);
|
|
1028
1834
|
};
|
|
1029
|
-
const repeatedCallGroup = (recording,
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1835
|
+
const repeatedCallGroup = (recording, plan, parentCallId) => {
|
|
1836
|
+
const slots = recording.repeatedCalls;
|
|
1837
|
+
let slot = slots[plan.runtimePlanId];
|
|
1838
|
+
if (!slot) {
|
|
1839
|
+
slot = {};
|
|
1840
|
+
slots[plan.runtimePlanId] = slot;
|
|
1841
|
+
}
|
|
1842
|
+
if (parentCallId === void 0) {
|
|
1843
|
+
if (!slot.root) slot.root = newRepeatedGroup(plan);
|
|
1844
|
+
return slot.root;
|
|
1845
|
+
}
|
|
1846
|
+
if (slot.lastParentGroup && slot.lastParentCallId === parentCallId) {
|
|
1847
|
+
return slot.lastParentGroup;
|
|
1034
1848
|
}
|
|
1035
|
-
|
|
1849
|
+
if (!slot.byParent) slot.byParent = /* @__PURE__ */ new Map();
|
|
1850
|
+
let group = slot.byParent.get(parentCallId);
|
|
1036
1851
|
if (!group) {
|
|
1037
|
-
group =
|
|
1038
|
-
byParent.set(parentCallId, group);
|
|
1852
|
+
group = newRepeatedGroup(plan);
|
|
1853
|
+
slot.byParent.set(parentCallId, group);
|
|
1039
1854
|
}
|
|
1855
|
+
slot.lastParentCallId = parentCallId;
|
|
1856
|
+
slot.lastParentGroup = group;
|
|
1040
1857
|
return group;
|
|
1041
1858
|
};
|
|
1042
1859
|
const serializedError = (recording, error, callId) => {
|
|
@@ -1052,60 +1869,83 @@ var createExecutionRecorder = (options) => {
|
|
|
1052
1869
|
return {
|
|
1053
1870
|
// Keep the bounded thrown value even after surrounding capture degrades. A partial
|
|
1054
1871
|
// snapshot without the exception itself would not be useful for investigation.
|
|
1055
|
-
value:
|
|
1872
|
+
value: serializeAndCount(error).value,
|
|
1056
1873
|
commit: () => {
|
|
1057
1874
|
if (key) recording.capturedErrors.set(key, callId);
|
|
1058
1875
|
}
|
|
1059
1876
|
};
|
|
1060
1877
|
};
|
|
1061
|
-
const captureCompletedThrow = (recording,
|
|
1062
|
-
if (!
|
|
1878
|
+
const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
|
|
1879
|
+
if (!recording.journal) {
|
|
1880
|
+
rememberError(error, recording);
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1883
|
+
if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
|
|
1063
1884
|
rememberError(error, recording);
|
|
1064
1885
|
return;
|
|
1065
1886
|
}
|
|
1066
1887
|
const callId = ++recording.nextCallId;
|
|
1067
1888
|
const capturedError = serializedError(recording, error, callId);
|
|
1068
|
-
const
|
|
1069
|
-
|
|
1889
|
+
const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
|
|
1890
|
+
const endedAtNs = process.hrtime.bigint();
|
|
1891
|
+
const droppedBefore = recording.journal.dropped;
|
|
1892
|
+
const retained = recording.journal.forceCompletedCall(
|
|
1893
|
+
plan.runtimePlanId,
|
|
1070
1894
|
callId,
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
}
|
|
1083
|
-
const droppedBefore = recording.events.dropped;
|
|
1084
|
-
const retained = recording.events.forceCompletedCall(enter, terminal);
|
|
1085
|
-
if (retained) capturedError.commit();
|
|
1895
|
+
parentCallId,
|
|
1896
|
+
startedAtNs - recording.startedAtNs,
|
|
1897
|
+
capturedArgs,
|
|
1898
|
+
KIND_THROW,
|
|
1899
|
+
endedAtNs - recording.startedAtNs,
|
|
1900
|
+
endedAtNs - startedAtNs,
|
|
1901
|
+
capturedError.value
|
|
1902
|
+
);
|
|
1903
|
+
if (retained) {
|
|
1904
|
+
stats.functionCallsCaptured++;
|
|
1905
|
+
capturedError.commit();
|
|
1906
|
+
}
|
|
1086
1907
|
countDroppedEvents(recording, droppedBefore);
|
|
1087
1908
|
rememberError(error, recording);
|
|
1088
1909
|
};
|
|
1089
|
-
const recordSuppressedCall = (recording, group,
|
|
1910
|
+
const recordSuppressedCall = (recording, group, parentCallId, startedAtNs, endedAtNs) => {
|
|
1090
1911
|
stats.repeatedCallsSuppressed++;
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
group.
|
|
1094
|
-
type: "function_calls_suppressed",
|
|
1095
|
-
functionId,
|
|
1096
|
-
timestampMs: startedAtMs,
|
|
1097
|
-
lastTimestampMs: endedAtMs,
|
|
1098
|
-
suppressedCallCount: 1,
|
|
1099
|
-
totalDurationMs: durationMs,
|
|
1100
|
-
...parentCallId === void 0 ? {} : { parentCallId }
|
|
1101
|
-
};
|
|
1102
|
-
appendStandaloneEvent(recording, group.summary);
|
|
1912
|
+
if (!group.suppressed) {
|
|
1913
|
+
group.suppressed = newSuppression(group, parentCallId, startedAtNs, endedAtNs);
|
|
1914
|
+
appendSuppressedPlaceholder(recording, group.suppressed);
|
|
1103
1915
|
return;
|
|
1104
1916
|
}
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1917
|
+
const suppressed = group.suppressed;
|
|
1918
|
+
suppressed.count++;
|
|
1919
|
+
suppressed.lastTimestampNs = endedAtNs;
|
|
1920
|
+
suppressed.totalDurationNs += endedAtNs - startedAtNs;
|
|
1921
|
+
if (suppressed.retainedIndex < 0) {
|
|
1922
|
+
appendSuppressedPlaceholder(recording, suppressed);
|
|
1923
|
+
}
|
|
1924
|
+
};
|
|
1925
|
+
const releaseJournalIfIdle = (recording) => {
|
|
1926
|
+
if (!recording.finished || recording.hasError || recording.inFlightCalls > 0) return;
|
|
1927
|
+
if (!recording.journal) return;
|
|
1928
|
+
journalPool.release(recording.journal);
|
|
1929
|
+
recording.journal = void 0;
|
|
1930
|
+
};
|
|
1931
|
+
const acquireJournal = (recording) => {
|
|
1932
|
+
if (recording.journal) return recording.journal;
|
|
1933
|
+
try {
|
|
1934
|
+
const journal = journalPool.acquire();
|
|
1935
|
+
if (!memoryBudget.reserveStorage(recording.memory, journal.allocatedBytes)) {
|
|
1936
|
+
journalPool.release(journal);
|
|
1937
|
+
return void 0;
|
|
1938
|
+
}
|
|
1939
|
+
journal.onGrow = (deltaBytes) => memoryBudget.reserveStorage(recording.memory, deltaBytes);
|
|
1940
|
+
recording.journal = journal;
|
|
1941
|
+
return journal;
|
|
1942
|
+
} catch {
|
|
1943
|
+
return void 0;
|
|
1944
|
+
}
|
|
1945
|
+
};
|
|
1946
|
+
const settleInFlight = (recording) => {
|
|
1947
|
+
if (recording.inFlightCalls > 0) recording.inFlightCalls--;
|
|
1948
|
+
releaseJournalIfIdle(recording);
|
|
1109
1949
|
};
|
|
1110
1950
|
const finish = (store, metadata) => {
|
|
1111
1951
|
const { recording } = store;
|
|
@@ -1115,11 +1955,22 @@ var createExecutionRecorder = (options) => {
|
|
|
1115
1955
|
if (metadata) mergeExecutionMetadata(recording.execution, metadata);
|
|
1116
1956
|
memoryBudget.release(recording.memory);
|
|
1117
1957
|
stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
|
|
1118
|
-
if (!recording.hasError)
|
|
1958
|
+
if (!recording.hasError) {
|
|
1959
|
+
stats.successfulExecutionsDiscarded++;
|
|
1960
|
+
releaseJournalIfIdle(recording);
|
|
1961
|
+
}
|
|
1119
1962
|
recording.finishedAtNs = process.hrtime.bigint();
|
|
1120
1963
|
addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
|
|
1121
1964
|
recordInlineTiming(recording);
|
|
1122
1965
|
};
|
|
1966
|
+
const runStore = (store, callback) => {
|
|
1967
|
+
if (!phaseTimingEnabled) return storage.run(store, callback);
|
|
1968
|
+
const alsStartedAtNs = process.hrtime.bigint();
|
|
1969
|
+
return storage.run(store, () => {
|
|
1970
|
+
addPhase("alsNs", process.hrtime.bigint() - alsStartedAtNs);
|
|
1971
|
+
return callback();
|
|
1972
|
+
});
|
|
1973
|
+
};
|
|
1123
1974
|
const createScope = (metadata) => {
|
|
1124
1975
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1125
1976
|
try {
|
|
@@ -1132,15 +1983,19 @@ var createExecutionRecorder = (options) => {
|
|
|
1132
1983
|
...metadata,
|
|
1133
1984
|
...metadata.request ? { request: { ...metadata.request } } : {}
|
|
1134
1985
|
},
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
repeatedCalls: /* @__PURE__ */ new Map(),
|
|
1986
|
+
journal: void 0,
|
|
1987
|
+
repeatedCalls: [],
|
|
1138
1988
|
capturedErrors: /* @__PURE__ */ new WeakMap(),
|
|
1139
1989
|
nextCallId: 0,
|
|
1990
|
+
inFlightCalls: 0,
|
|
1140
1991
|
finished: false,
|
|
1141
1992
|
hasError: false,
|
|
1142
1993
|
memory: memoryBudget.startExecution(),
|
|
1143
|
-
partialSnapshotCounted: false
|
|
1994
|
+
partialSnapshotCounted: false,
|
|
1995
|
+
derivationRoots: [],
|
|
1996
|
+
derivationRootBytes: 0,
|
|
1997
|
+
sawAutomatic: false,
|
|
1998
|
+
sawManual: false
|
|
1144
1999
|
};
|
|
1145
2000
|
stats.activeExecutions++;
|
|
1146
2001
|
stats.peakActiveExecutions = Math.max(stats.peakActiveExecutions, stats.activeExecutions);
|
|
@@ -1149,7 +2004,7 @@ var createExecutionRecorder = (options) => {
|
|
|
1149
2004
|
return {
|
|
1150
2005
|
run: (callback) => {
|
|
1151
2006
|
const runStartedAtNs = process.hrtime.bigint();
|
|
1152
|
-
return
|
|
2007
|
+
return runStore(store, () => {
|
|
1153
2008
|
addRecorderTime(recording, process.hrtime.bigint() - runStartedAtNs);
|
|
1154
2009
|
return callback();
|
|
1155
2010
|
});
|
|
@@ -1202,140 +2057,295 @@ var createExecutionRecorder = (options) => {
|
|
|
1202
2057
|
return void 0;
|
|
1203
2058
|
}
|
|
1204
2059
|
};
|
|
1205
|
-
const
|
|
2060
|
+
const runPreparedFunction = (plan, args, callback, omitValues) => {
|
|
1206
2061
|
const store = storage.getStore();
|
|
1207
2062
|
if (!store || store.recording.finished) return callback();
|
|
1208
|
-
|
|
1209
|
-
const functionId = definition.functionId;
|
|
2063
|
+
stats.functionCallsObserved++;
|
|
1210
2064
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1211
|
-
if (store.suppressCapture ||
|
|
1212
|
-
|
|
2065
|
+
if (store.suppressCapture || plan.excluded) {
|
|
2066
|
+
stats.functionCallsExcluded++;
|
|
2067
|
+
return runStore({ ...store, suppressCapture: true }, () => {
|
|
1213
2068
|
addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
1214
2069
|
return callback();
|
|
1215
2070
|
});
|
|
1216
2071
|
}
|
|
1217
|
-
store.recording
|
|
2072
|
+
const recording = store.recording;
|
|
2073
|
+
recording.inFlightCalls++;
|
|
1218
2074
|
const parentCallId = store.currentCallId;
|
|
1219
|
-
const group = repeatedCallGroup(
|
|
2075
|
+
const group = repeatedCallGroup(recording, plan, parentCallId);
|
|
1220
2076
|
group.observedCalls++;
|
|
2077
|
+
const journal = acquireJournal(recording);
|
|
2078
|
+
if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
|
|
1221
2079
|
if (group.observedCalls > maxCapturedCallsPerFunction) {
|
|
1222
2080
|
const startedAtNs2 = process.hrtime.bigint();
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
2081
|
+
try {
|
|
2082
|
+
const result = callback();
|
|
2083
|
+
if (isPromiseLike(result)) {
|
|
2084
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
2085
|
+
return result.then(
|
|
2086
|
+
(value) => {
|
|
2087
|
+
const callbackEndedAtNs2 = process.hrtime.bigint();
|
|
2088
|
+
recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs2);
|
|
2089
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
|
|
2090
|
+
settleInFlight(recording);
|
|
2091
|
+
return value;
|
|
2092
|
+
},
|
|
2093
|
+
(error) => {
|
|
2094
|
+
const callbackEndedAtNs2 = process.hrtime.bigint();
|
|
2095
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
|
|
2096
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
|
|
2097
|
+
settleInFlight(recording);
|
|
2098
|
+
throw error;
|
|
2099
|
+
}
|
|
2100
|
+
);
|
|
2101
|
+
}
|
|
2102
|
+
const callbackEndedAtNs = process.hrtime.bigint();
|
|
2103
|
+
recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs);
|
|
2104
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
2105
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
|
|
2106
|
+
settleInFlight(recording);
|
|
2107
|
+
return result;
|
|
2108
|
+
} catch (error) {
|
|
2109
|
+
const callbackEndedAtNs = process.hrtime.bigint();
|
|
2110
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
|
|
2111
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
2112
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
|
|
2113
|
+
settleInFlight(recording);
|
|
2114
|
+
throw error;
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
const startedAtNs = process.hrtime.bigint();
|
|
2118
|
+
if (!journal) {
|
|
2119
|
+
memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
|
|
2120
|
+
return runStore(
|
|
2121
|
+
store,
|
|
2122
|
+
() => observeRecordedCallback(
|
|
2123
|
+
recording,
|
|
2124
|
+
recorderStartedAtNs,
|
|
2125
|
+
callback,
|
|
2126
|
+
() => settleInFlight(recording),
|
|
2127
|
+
(error) => {
|
|
2128
|
+
rememberError(error, recording);
|
|
2129
|
+
settleInFlight(recording);
|
|
2130
|
+
}
|
|
1245
2131
|
)
|
|
1246
2132
|
);
|
|
1247
2133
|
}
|
|
1248
|
-
|
|
1249
|
-
if (!store.recording.events.canStartCall()) {
|
|
1250
|
-
const startedAtMs = elapsedMs(store.recording.startedAtNs, startedAtNs);
|
|
2134
|
+
if (!journal.canStartCall()) {
|
|
1251
2135
|
const captureSuccess = () => {
|
|
1252
|
-
const droppedBefore =
|
|
1253
|
-
|
|
1254
|
-
countDroppedEvents(
|
|
2136
|
+
const droppedBefore = recording.journal?.dropped ?? 0;
|
|
2137
|
+
recording.journal?.dropCall();
|
|
2138
|
+
countDroppedEvents(recording, droppedBefore);
|
|
2139
|
+
settleInFlight(recording);
|
|
1255
2140
|
};
|
|
1256
|
-
return
|
|
2141
|
+
return runStore(
|
|
1257
2142
|
store,
|
|
1258
2143
|
() => observeRecordedCallback(
|
|
1259
|
-
|
|
2144
|
+
recording,
|
|
1260
2145
|
recorderStartedAtNs,
|
|
1261
2146
|
callback,
|
|
1262
2147
|
captureSuccess,
|
|
1263
|
-
(error) =>
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
parentCallId,
|
|
1268
|
-
startedAtNs,
|
|
1269
|
-
startedAtMs,
|
|
1270
|
-
error
|
|
1271
|
-
)
|
|
2148
|
+
(error) => {
|
|
2149
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
|
|
2150
|
+
settleInFlight(recording);
|
|
2151
|
+
}
|
|
1272
2152
|
)
|
|
1273
2153
|
);
|
|
1274
2154
|
}
|
|
1275
|
-
if (!memoryBudget.reserveCall(
|
|
2155
|
+
if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
|
|
1276
2156
|
return observeRecordedCallback(
|
|
1277
|
-
|
|
2157
|
+
recording,
|
|
1278
2158
|
recorderStartedAtNs,
|
|
1279
2159
|
callback,
|
|
1280
|
-
() =>
|
|
1281
|
-
|
|
1282
|
-
|
|
2160
|
+
() => settleInFlight(recording),
|
|
2161
|
+
(error) => {
|
|
2162
|
+
rememberError(error, recording);
|
|
2163
|
+
settleInFlight(recording);
|
|
2164
|
+
}
|
|
1283
2165
|
);
|
|
1284
2166
|
}
|
|
1285
|
-
const callId = ++
|
|
1286
|
-
const
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
args: Array.from(args, (argument) => captureValue(store.recording, argument)),
|
|
1292
|
-
...parentCallId === void 0 ? {} : { parentCallId }
|
|
1293
|
-
};
|
|
1294
|
-
store.recording.events.startCall(enter);
|
|
1295
|
-
const callStore = { recording: store.recording, currentCallId: callId };
|
|
1296
|
-
return storage.run(
|
|
2167
|
+
const callId = ++recording.nextCallId;
|
|
2168
|
+
const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
|
|
2169
|
+
const capturedArgs = omitValues ? Array.from(args, () => rasputinOmitted()) : Array.from(args, (argument) => captureValue(recording, argument));
|
|
2170
|
+
journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
|
|
2171
|
+
const callStore = { recording, currentCallId: callId };
|
|
2172
|
+
return runStore(
|
|
1297
2173
|
callStore,
|
|
1298
2174
|
() => observeRecordedCallback(
|
|
1299
|
-
|
|
2175
|
+
recording,
|
|
1300
2176
|
recorderStartedAtNs,
|
|
1301
2177
|
callback,
|
|
1302
2178
|
(value) => {
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
}
|
|
2179
|
+
if (recording.journal) {
|
|
2180
|
+
const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
|
|
2181
|
+
const durationNs = process.hrtime.bigint() - startedAtNs;
|
|
2182
|
+
const returnValue = omitValues ? rasputinOmitted() : captureValue(recording, value);
|
|
2183
|
+
recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
|
|
2184
|
+
stats.functionCallsCaptured++;
|
|
2185
|
+
}
|
|
2186
|
+
settleInFlight(recording);
|
|
1310
2187
|
},
|
|
1311
2188
|
(error) => {
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
2189
|
+
if (!recording.journal) {
|
|
2190
|
+
rememberError(error, recording);
|
|
2191
|
+
settleInFlight(recording);
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
const capturedError = serializedError(recording, error, callId);
|
|
2195
|
+
recording.journal.finishCall(
|
|
2196
|
+
KIND_THROW,
|
|
1315
2197
|
callId,
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
2198
|
+
process.hrtime.bigint() - recording.startedAtNs,
|
|
2199
|
+
process.hrtime.bigint() - startedAtNs,
|
|
2200
|
+
capturedError.value
|
|
2201
|
+
);
|
|
2202
|
+
stats.functionCallsCaptured++;
|
|
1320
2203
|
capturedError.commit();
|
|
1321
|
-
rememberError(error,
|
|
2204
|
+
rememberError(error, recording);
|
|
2205
|
+
settleInFlight(recording);
|
|
1322
2206
|
}
|
|
1323
2207
|
)
|
|
1324
2208
|
);
|
|
1325
2209
|
};
|
|
2210
|
+
const runFunction = (input, args, callback) => {
|
|
2211
|
+
const store = storage.getStore();
|
|
2212
|
+
if (store && !store.recording.finished) store.recording.sawManual = true;
|
|
2213
|
+
return runPreparedFunction(preparePlan(normalizeFunctionDefinition(input)), args, callback);
|
|
2214
|
+
};
|
|
2215
|
+
const runFunctionPlans = (plans, planIndex, args, callback, omitValues) => {
|
|
2216
|
+
const store = storage.getStore();
|
|
2217
|
+
const plan = preparedPlansFor(plans)[planIndex];
|
|
2218
|
+
if (store && !store.recording.finished) store.recording.sawAutomatic = true;
|
|
2219
|
+
return plan ? runPreparedFunction(plan, args, callback, omitValues) : callback();
|
|
2220
|
+
};
|
|
2221
|
+
const prepareFunctionPlans = (plans) => preparedPlansFor(plans);
|
|
1326
2222
|
function trace(input, fn) {
|
|
1327
2223
|
const definition = typeof input === "string" ? manualFunctionDefinition(input) : { ...input, functionId: runtimeFunctionId2(input) };
|
|
2224
|
+
const plan = preparePlan(definition);
|
|
1328
2225
|
return function traced(...args) {
|
|
1329
|
-
|
|
2226
|
+
const store = storage.getStore();
|
|
2227
|
+
if (store && !store.recording.finished) store.recording.sawManual = true;
|
|
2228
|
+
return runPreparedFunction(plan, args, () => fn.apply(this, args));
|
|
1330
2229
|
};
|
|
1331
2230
|
}
|
|
2231
|
+
const captureDerivationRoot = (rootId, value) => {
|
|
2232
|
+
const store = storage.getStore();
|
|
2233
|
+
if (!store || store.recording.finished || store.suppressCapture) return value;
|
|
2234
|
+
const recording = store.recording;
|
|
2235
|
+
if (recording.memory.mode !== "full") return value;
|
|
2236
|
+
if (recording.derivationRoots.length >= maxEventsPerExecution) return value;
|
|
2237
|
+
const recorderStartedAtNs = process.hrtime.bigint();
|
|
2238
|
+
try {
|
|
2239
|
+
const serialized = captureValue(recording, value);
|
|
2240
|
+
if (recording.memory.mode !== "full") return value;
|
|
2241
|
+
if (!memoryBudget.reserveStorage(recording.memory, DERIVATION_ROOT_RECORD_BYTES)) {
|
|
2242
|
+
return value;
|
|
2243
|
+
}
|
|
2244
|
+
const completeness = capturedValueCompleteness(serialized);
|
|
2245
|
+
const bytes = jsonLiteralUtf8Bytes(serialized);
|
|
2246
|
+
recording.derivationRoots.push({
|
|
2247
|
+
rootId,
|
|
2248
|
+
callId: store.currentCallId ?? 0,
|
|
2249
|
+
value: serialized,
|
|
2250
|
+
completeness
|
|
2251
|
+
});
|
|
2252
|
+
recording.derivationRootBytes += bytes;
|
|
2253
|
+
stats.derivationRootsCaptured++;
|
|
2254
|
+
stats.derivationRootBytes += bytes;
|
|
2255
|
+
stats.derivationFallbackExpressions++;
|
|
2256
|
+
return value;
|
|
2257
|
+
} finally {
|
|
2258
|
+
addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
2259
|
+
}
|
|
2260
|
+
};
|
|
1332
2261
|
return {
|
|
1333
2262
|
createScope,
|
|
1334
2263
|
run,
|
|
1335
2264
|
getErrorState,
|
|
1336
2265
|
runFunction,
|
|
2266
|
+
runFunctionPlans,
|
|
2267
|
+
prepareFunctionPlans,
|
|
2268
|
+
runPreparedFunction,
|
|
1337
2269
|
trace,
|
|
1338
|
-
|
|
2270
|
+
captureDerivationRoot,
|
|
2271
|
+
getStats: () => {
|
|
2272
|
+
const manifest = snapshotInstrumentationManifest();
|
|
2273
|
+
const plans = manifest?.derivationPlans ?? [];
|
|
2274
|
+
return {
|
|
2275
|
+
...stats,
|
|
2276
|
+
...memoryBudget.getStats(),
|
|
2277
|
+
...journalPool.stats(),
|
|
2278
|
+
derivationCandidateFunctions: plans.filter((plan) => !plan.fallbackReason).length,
|
|
2279
|
+
derivationFallbackFunctions: plans.filter((plan) => plan.fallbackReason).length,
|
|
2280
|
+
derivationFallbackReasons: { ...stats.derivationFallbackReasons },
|
|
2281
|
+
...phases ? {
|
|
2282
|
+
phaseAlsNs: Number(phases.alsNs),
|
|
2283
|
+
phaseMaterializeNs: Number(phases.materializeNs)
|
|
2284
|
+
} : {}
|
|
2285
|
+
};
|
|
2286
|
+
}
|
|
2287
|
+
};
|
|
2288
|
+
};
|
|
2289
|
+
|
|
2290
|
+
// src/execution-recorder/automatic-runtime.ts
|
|
2291
|
+
var AUTOMATIC_RUNTIME_SYMBOL = "rasputin.execution.runtime.v2";
|
|
2292
|
+
var runtimeSymbol = Symbol.for(AUTOMATIC_RUNTIME_SYMBOL);
|
|
2293
|
+
var passthroughCapture = (_rootId, value) => value;
|
|
2294
|
+
var passthrough = (_planIndex, _args, callback) => callback();
|
|
2295
|
+
var bindPassthrough = (module) => {
|
|
2296
|
+
module.cell.run = passthrough;
|
|
2297
|
+
};
|
|
2298
|
+
var isRegistry = (value) => Array.isArray(Reflect.get(value, "runtimes")) && Array.isArray(Reflect.get(value, "modules")) && typeof Reflect.get(value, "register") === "function";
|
|
2299
|
+
var registerModule = (registry, plans) => {
|
|
2300
|
+
const cell = { run: passthrough };
|
|
2301
|
+
const module = { plans, cell };
|
|
2302
|
+
registry.modules.push(module);
|
|
2303
|
+
registry.runtimes.at(-1)?.bind(module);
|
|
2304
|
+
return (planIndex, args, callback, omitValues) => cell.run(planIndex, args, callback, omitValues);
|
|
2305
|
+
};
|
|
2306
|
+
var createRegistry = () => {
|
|
2307
|
+
const registry = {
|
|
2308
|
+
runtimes: [],
|
|
2309
|
+
modules: [],
|
|
2310
|
+
captureRoot: passthroughCapture,
|
|
2311
|
+
register(plans) {
|
|
2312
|
+
return registerModule(registry, plans);
|
|
2313
|
+
}
|
|
2314
|
+
};
|
|
2315
|
+
return registry;
|
|
2316
|
+
};
|
|
2317
|
+
var getAutomaticRuntimeRegistry = () => {
|
|
2318
|
+
const existing = Reflect.get(globalThis, runtimeSymbol);
|
|
2319
|
+
if (existing && typeof existing === "object" && isRegistry(existing)) {
|
|
2320
|
+
if (typeof existing.captureRoot !== "function") {
|
|
2321
|
+
existing.captureRoot = passthroughCapture;
|
|
2322
|
+
}
|
|
2323
|
+
return existing;
|
|
2324
|
+
}
|
|
2325
|
+
const registry = createRegistry();
|
|
2326
|
+
Reflect.set(globalThis, runtimeSymbol, registry);
|
|
2327
|
+
return registry;
|
|
2328
|
+
};
|
|
2329
|
+
var installAutomaticExecutionRuntime = (execution) => {
|
|
2330
|
+
const registry = getAutomaticRuntimeRegistry();
|
|
2331
|
+
const runtime = {
|
|
2332
|
+
bind(module) {
|
|
2333
|
+
module.cell.run = (planIndex, args, callback, omitValues) => execution.runFunctionPlans(module.plans, planIndex, args, callback, omitValues);
|
|
2334
|
+
},
|
|
2335
|
+
captureRoot: (rootId, value) => execution.captureDerivationRoot(rootId, value)
|
|
2336
|
+
};
|
|
2337
|
+
registry.runtimes.push(runtime);
|
|
2338
|
+
registry.captureRoot = runtime.captureRoot;
|
|
2339
|
+
for (const module of registry.modules) runtime.bind(module);
|
|
2340
|
+
return () => {
|
|
2341
|
+
const index = registry.runtimes.lastIndexOf(runtime);
|
|
2342
|
+
if (index >= 0) registry.runtimes.splice(index, 1);
|
|
2343
|
+
const current = registry.runtimes.at(-1);
|
|
2344
|
+
registry.captureRoot = current?.captureRoot ?? passthroughCapture;
|
|
2345
|
+
for (const module of registry.modules) {
|
|
2346
|
+
if (current) current.bind(module);
|
|
2347
|
+
else bindPassthrough(module);
|
|
2348
|
+
}
|
|
1339
2349
|
};
|
|
1340
2350
|
};
|
|
1341
2351
|
|
|
@@ -1388,6 +2398,7 @@ var installGlobalHandlers = (client, options = {}) => {
|
|
|
1388
2398
|
};
|
|
1389
2399
|
|
|
1390
2400
|
// src/rasputin-init.ts
|
|
2401
|
+
import { join } from "node:path";
|
|
1391
2402
|
import {
|
|
1392
2403
|
createClient,
|
|
1393
2404
|
isClientEnabled
|
|
@@ -1395,7 +2406,7 @@ import {
|
|
|
1395
2406
|
|
|
1396
2407
|
// src/sdk-meta.ts
|
|
1397
2408
|
var SDK_NAME = "@rasputin-ai/node";
|
|
1398
|
-
var SDK_VERSION = "0.
|
|
2409
|
+
var SDK_VERSION = "0.5.0-alpha.10";
|
|
1399
2410
|
|
|
1400
2411
|
// src/rasputin-init.ts
|
|
1401
2412
|
var withExecution = (client, execution, installRuntime, manifest) => {
|
|
@@ -1436,6 +2447,9 @@ var RasputinInit = (options) => {
|
|
|
1436
2447
|
...options.executionRecorder,
|
|
1437
2448
|
enabled: recorderEnabled
|
|
1438
2449
|
});
|
|
2450
|
+
loadInstrumentationManifestIfPresent(
|
|
2451
|
+
options.instrumentationManifestPath ?? process.env.RASPUTIN_INSTRUMENTATION_MANIFEST ?? join(process.cwd(), ".rasputin", "instrumentation-manifest.json")
|
|
2452
|
+
);
|
|
1439
2453
|
const wrappedClient = withExecution(client, execution, recorderEnabled, {
|
|
1440
2454
|
projectApiKey: options.projectApiKey,
|
|
1441
2455
|
release: options.release,
|