@rasputin-ai/node 0.5.0-alpha.5 → 0.5.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +6 -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/recorder-memory-budget.d.ts +1 -0
- package/dist/execution-recorder/recorder-memory-budget.d.ts.map +1 -1
- package/dist/execution-recorder/safe-serialize.d.ts +1 -0
- package/dist/execution-recorder/safe-serialize.d.ts.map +1 -1
- package/dist/index.js +905 -297
- package/dist/sdk-meta.d.ts +1 -1
- package/package.json +2 -2
- package/dist/execution-recorder/call-aware-event-buffer.d.ts +0 -37
- package/dist/execution-recorder/call-aware-event-buffer.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -386,83 +386,385 @@ var scheduleInstrumentationManifestUpload = (options) => {
|
|
|
386
386
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
387
387
|
import { runtimeFunctionId as runtimeFunctionId2 } from "@rasputin-ai/core";
|
|
388
388
|
|
|
389
|
-
// src/execution-recorder/
|
|
390
|
-
var
|
|
391
|
-
var
|
|
389
|
+
// src/execution-recorder/execution-journal.ts
|
|
390
|
+
var KIND_ENTER = 1;
|
|
391
|
+
var KIND_EXIT = 2;
|
|
392
|
+
var KIND_THROW = 3;
|
|
393
|
+
var KIND_SUPPRESSED = 4;
|
|
394
|
+
var NO_PARENT = 4294967295;
|
|
395
|
+
var NO_SUPPRESSION = 4294967295;
|
|
396
|
+
var MAX_POOLED_JOURNALS = 8;
|
|
397
|
+
var MAX_POOLED_JOURNAL_CAPACITY = 4096;
|
|
398
|
+
var INITIAL_JOURNAL_STORAGE = 32;
|
|
399
|
+
var BYTES_PER_EVENT = Uint8Array.BYTES_PER_ELEMENT + Uint32Array.BYTES_PER_ELEMENT * 4 + BigInt64Array.BYTES_PER_ELEMENT * 2;
|
|
400
|
+
var DEFAULT_MAX_EVENTS_PER_EXECUTION = 500;
|
|
401
|
+
var MAX_JOURNAL_EVENTS = 16384;
|
|
402
|
+
var elapsedMs = (startedAtNs, endedAtNs) => Number(endedAtNs - startedAtNs) / 1e6;
|
|
403
|
+
var roundedMilliseconds = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
|
|
404
|
+
var relativeMs = (relativeNs) => Number(relativeNs) / 1e6;
|
|
405
|
+
var sanitizeJournalCapacity = (value) => {
|
|
406
|
+
const requested = value ?? DEFAULT_MAX_EVENTS_PER_EXECUTION;
|
|
407
|
+
if (!Number.isFinite(requested)) return DEFAULT_MAX_EVENTS_PER_EXECUTION;
|
|
408
|
+
return Math.min(MAX_JOURNAL_EVENTS, Math.max(2, Math.floor(requested)));
|
|
409
|
+
};
|
|
410
|
+
var ExecutionJournal = class {
|
|
411
|
+
dropped = 0;
|
|
412
|
+
allocatedBytes = 0;
|
|
413
|
+
onGrow;
|
|
414
|
+
length = 0;
|
|
415
|
+
kind = new Uint8Array(0);
|
|
416
|
+
planId = new Uint32Array(0);
|
|
417
|
+
callId = new Uint32Array(0);
|
|
418
|
+
parentCallId = new Uint32Array(0);
|
|
419
|
+
timestampNs = new BigInt64Array(0);
|
|
420
|
+
durationNs = new BigInt64Array(0);
|
|
421
|
+
suppressionIndex = new Uint32Array(0);
|
|
422
|
+
payloads = [];
|
|
423
|
+
suppressions = [];
|
|
424
|
+
openCallIds = /* @__PURE__ */ new Set();
|
|
425
|
+
notedPlanIds = [];
|
|
426
|
+
notedPlanSet = /* @__PURE__ */ new Set();
|
|
427
|
+
maxCapacity;
|
|
392
428
|
constructor(capacity) {
|
|
393
|
-
this.
|
|
429
|
+
this.maxCapacity = sanitizeJournalCapacity(capacity);
|
|
430
|
+
this.reallocate(Math.min(this.maxCapacity, INITIAL_JOURNAL_STORAGE));
|
|
431
|
+
}
|
|
432
|
+
get capacity() {
|
|
433
|
+
return this.maxCapacity;
|
|
434
|
+
}
|
|
435
|
+
get hasOpenCalls() {
|
|
436
|
+
return this.openCallIds.size > 0;
|
|
437
|
+
}
|
|
438
|
+
get eventCount() {
|
|
439
|
+
return this.length;
|
|
440
|
+
}
|
|
441
|
+
get payloadSlotCount() {
|
|
442
|
+
return this.payloads.length;
|
|
394
443
|
}
|
|
395
|
-
items = [];
|
|
396
|
-
openCallIds = /* @__PURE__ */ new Set();
|
|
397
|
-
dropped = 0;
|
|
398
444
|
canStartCall() {
|
|
399
|
-
|
|
445
|
+
if (this.length + this.openCallIds.size + 2 > this.maxCapacity) return false;
|
|
446
|
+
return this.ensureCapacity(this.length + 2);
|
|
400
447
|
}
|
|
401
|
-
|
|
402
|
-
this.
|
|
403
|
-
this.
|
|
448
|
+
notePlan(runtimePlanId) {
|
|
449
|
+
if (this.notedPlanSet.has(runtimePlanId)) return;
|
|
450
|
+
this.notedPlanSet.add(runtimePlanId);
|
|
451
|
+
this.notedPlanIds.push(runtimePlanId);
|
|
404
452
|
}
|
|
405
|
-
|
|
406
|
-
if (
|
|
407
|
-
|
|
408
|
-
this.
|
|
453
|
+
registerSuppression(group) {
|
|
454
|
+
if (group.storageIndex >= 0) return group;
|
|
455
|
+
group.storageIndex = this.suppressions.length;
|
|
456
|
+
this.suppressions.push(group);
|
|
457
|
+
return group;
|
|
458
|
+
}
|
|
459
|
+
startCall(runtimePlanId, callId, parentCallId, timestampNs, args) {
|
|
460
|
+
if (!this.write(
|
|
461
|
+
KIND_ENTER,
|
|
462
|
+
runtimePlanId,
|
|
463
|
+
callId,
|
|
464
|
+
parentCallId,
|
|
465
|
+
timestampNs,
|
|
466
|
+
0n,
|
|
467
|
+
args,
|
|
468
|
+
NO_SUPPRESSION
|
|
469
|
+
)) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
this.openCallIds.add(callId);
|
|
473
|
+
}
|
|
474
|
+
finishCall(kind, callId, timestampNs, durationNs, payload) {
|
|
475
|
+
if (!this.openCallIds.delete(callId)) return;
|
|
476
|
+
this.write(kind, 0, callId, void 0, timestampNs, durationNs, payload, NO_SUPPRESSION);
|
|
409
477
|
}
|
|
410
478
|
dropCall() {
|
|
411
479
|
this.dropped += 2;
|
|
412
480
|
}
|
|
413
481
|
appendSuppressed(group) {
|
|
414
|
-
if (this.
|
|
482
|
+
if (this.length + this.openCallIds.size + 1 > this.maxCapacity) {
|
|
483
|
+
this.dropped++;
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
this.registerSuppression(group);
|
|
487
|
+
group.retainedIndex = this.length;
|
|
488
|
+
if (!this.write(
|
|
489
|
+
KIND_SUPPRESSED,
|
|
490
|
+
group.runtimePlanId,
|
|
491
|
+
0,
|
|
492
|
+
group.parentCallId,
|
|
493
|
+
0n,
|
|
494
|
+
0n,
|
|
495
|
+
void 0,
|
|
496
|
+
group.storageIndex
|
|
497
|
+
)) {
|
|
498
|
+
group.retainedIndex = -1;
|
|
415
499
|
this.dropped++;
|
|
416
500
|
return false;
|
|
417
501
|
}
|
|
418
|
-
const placeholder = { kind: "suppressed", group };
|
|
419
|
-
this.items.push(placeholder);
|
|
420
|
-
group.retainedSlot = placeholder;
|
|
421
502
|
return true;
|
|
422
503
|
}
|
|
423
|
-
forceCompletedCall(
|
|
424
|
-
while (this.
|
|
504
|
+
forceCompletedCall(runtimePlanId, callId, parentCallId, enterTimestampNs, args, terminalKind, terminalTimestampNs, durationNs, payload) {
|
|
505
|
+
while (this.length + this.openCallIds.size + 2 > this.maxCapacity) {
|
|
425
506
|
if (!this.evictCompletedLeafOrSummary()) {
|
|
426
507
|
this.dropCall();
|
|
427
508
|
return false;
|
|
428
509
|
}
|
|
429
510
|
}
|
|
430
|
-
this.
|
|
511
|
+
if (!this.ensureCapacity(this.length + 2)) {
|
|
512
|
+
this.dropCall();
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
this.write(
|
|
516
|
+
KIND_ENTER,
|
|
517
|
+
runtimePlanId,
|
|
518
|
+
callId,
|
|
519
|
+
parentCallId,
|
|
520
|
+
enterTimestampNs,
|
|
521
|
+
0n,
|
|
522
|
+
args,
|
|
523
|
+
NO_SUPPRESSION
|
|
524
|
+
);
|
|
525
|
+
this.write(
|
|
526
|
+
terminalKind,
|
|
527
|
+
0,
|
|
528
|
+
callId,
|
|
529
|
+
void 0,
|
|
530
|
+
terminalTimestampNs,
|
|
531
|
+
durationNs,
|
|
532
|
+
payload,
|
|
533
|
+
NO_SUPPRESSION
|
|
534
|
+
);
|
|
431
535
|
return true;
|
|
432
536
|
}
|
|
433
|
-
|
|
434
|
-
|
|
537
|
+
materialize(plansByRuntimeId, executionStartedAtNs) {
|
|
538
|
+
const events = [];
|
|
539
|
+
const referencedFunctionIds = /* @__PURE__ */ new Set();
|
|
540
|
+
for (let index = 0; index < this.length; index++) {
|
|
541
|
+
const event = this.eventAt(index, plansByRuntimeId, executionStartedAtNs);
|
|
542
|
+
if (!event) continue;
|
|
543
|
+
events.push(event);
|
|
544
|
+
if (event.type === "function_enter" || event.type === "function_calls_suppressed") {
|
|
545
|
+
referencedFunctionIds.add(event.functionId);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
const functions = [];
|
|
549
|
+
const seenFunctionIds = /* @__PURE__ */ new Set();
|
|
550
|
+
for (const runtimePlanId of this.notedPlanIds) {
|
|
551
|
+
const definition = plansByRuntimeId[runtimePlanId]?.definition;
|
|
552
|
+
if (!definition || !referencedFunctionIds.has(definition.functionId)) continue;
|
|
553
|
+
if (seenFunctionIds.has(definition.functionId)) continue;
|
|
554
|
+
seenFunctionIds.add(definition.functionId);
|
|
555
|
+
functions.push(definition);
|
|
556
|
+
}
|
|
557
|
+
return { events, functions };
|
|
558
|
+
}
|
|
559
|
+
clear() {
|
|
560
|
+
this.length = 0;
|
|
561
|
+
this.dropped = 0;
|
|
562
|
+
this.onGrow = void 0;
|
|
563
|
+
this.openCallIds.clear();
|
|
564
|
+
this.notedPlanIds.length = 0;
|
|
565
|
+
this.notedPlanSet.clear();
|
|
566
|
+
for (let index = 0; index < this.payloads.length; index++) this.payloads[index] = void 0;
|
|
567
|
+
this.payloads.length = 0;
|
|
568
|
+
for (const group of this.suppressions) {
|
|
569
|
+
group.retainedIndex = -1;
|
|
570
|
+
group.storageIndex = -1;
|
|
571
|
+
}
|
|
572
|
+
this.suppressions.length = 0;
|
|
573
|
+
}
|
|
574
|
+
eventAt(index, plansByRuntimeId, executionStartedAtNs) {
|
|
575
|
+
const kind = this.kind[index];
|
|
576
|
+
if (kind === KIND_ENTER) {
|
|
577
|
+
const functionId = plansByRuntimeId[this.planId[index] ?? 0]?.functionId;
|
|
578
|
+
if (!functionId) return void 0;
|
|
579
|
+
const parentCallId = this.parentCallId[index] ?? NO_PARENT;
|
|
580
|
+
const payload = this.payloads[index];
|
|
581
|
+
return {
|
|
582
|
+
type: "function_enter",
|
|
583
|
+
callId: this.callId[index] ?? 0,
|
|
584
|
+
functionId,
|
|
585
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
586
|
+
args: Array.isArray(payload) ? payload : [],
|
|
587
|
+
...parentCallId === NO_PARENT ? {} : { parentCallId }
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
if (kind === KIND_EXIT) {
|
|
591
|
+
return {
|
|
592
|
+
type: "function_exit",
|
|
593
|
+
callId: this.callId[index] ?? 0,
|
|
594
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
595
|
+
durationMs: relativeMs(this.durationNs[index] ?? 0n),
|
|
596
|
+
returnValue: this.payloads[index]
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
if (kind === KIND_THROW) {
|
|
600
|
+
return {
|
|
601
|
+
type: "function_throw",
|
|
602
|
+
callId: this.callId[index] ?? 0,
|
|
603
|
+
timestampMs: relativeMs(this.timestampNs[index] ?? 0n),
|
|
604
|
+
durationMs: relativeMs(this.durationNs[index] ?? 0n),
|
|
605
|
+
error: this.payloads[index]
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
if (kind === KIND_SUPPRESSED) {
|
|
609
|
+
const group = this.suppressions[this.suppressionIndex[index] ?? 0];
|
|
610
|
+
if (!group) return void 0;
|
|
611
|
+
return {
|
|
612
|
+
type: "function_calls_suppressed",
|
|
613
|
+
functionId: group.functionId,
|
|
614
|
+
timestampMs: elapsedMs(executionStartedAtNs, group.firstTimestampNs),
|
|
615
|
+
lastTimestampMs: elapsedMs(executionStartedAtNs, group.lastTimestampNs),
|
|
616
|
+
suppressedCallCount: group.count,
|
|
617
|
+
totalDurationMs: roundedMilliseconds(group.totalDurationNs),
|
|
618
|
+
...group.parentCallId === void 0 ? {} : { parentCallId: group.parentCallId }
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
return void 0;
|
|
622
|
+
}
|
|
623
|
+
write(kind, runtimePlanId, callId, parentCallId, timestampNs, durationNs, payload, suppressionIndex) {
|
|
624
|
+
if (!this.ensureCapacity(this.length + 1)) return false;
|
|
625
|
+
const index = this.length;
|
|
626
|
+
this.kind[index] = kind;
|
|
627
|
+
this.planId[index] = runtimePlanId;
|
|
628
|
+
this.callId[index] = callId;
|
|
629
|
+
this.parentCallId[index] = parentCallId === void 0 ? NO_PARENT : parentCallId;
|
|
630
|
+
this.timestampNs[index] = timestampNs;
|
|
631
|
+
this.durationNs[index] = durationNs;
|
|
632
|
+
this.payloads[index] = payload;
|
|
633
|
+
this.suppressionIndex[index] = suppressionIndex;
|
|
634
|
+
this.length++;
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
ensureCapacity(needed) {
|
|
638
|
+
if (needed <= this.kind.length) return true;
|
|
639
|
+
if (needed > this.maxCapacity) return false;
|
|
640
|
+
let next = this.kind.length === 0 ? Math.min(INITIAL_JOURNAL_STORAGE, this.maxCapacity) : this.kind.length;
|
|
641
|
+
while (next < needed) {
|
|
642
|
+
const grown = Math.min(this.maxCapacity, next * 2);
|
|
643
|
+
if (grown <= next) return false;
|
|
644
|
+
next = grown;
|
|
645
|
+
}
|
|
646
|
+
const extraBytes = (next - this.kind.length) * BYTES_PER_EVENT;
|
|
647
|
+
if (this.onGrow && extraBytes > 0 && !this.onGrow(extraBytes)) return false;
|
|
648
|
+
this.reallocate(next);
|
|
649
|
+
return true;
|
|
650
|
+
}
|
|
651
|
+
reallocate(size) {
|
|
652
|
+
const nextKind = new Uint8Array(size);
|
|
653
|
+
const nextPlanId = new Uint32Array(size);
|
|
654
|
+
const nextCallId = new Uint32Array(size);
|
|
655
|
+
const nextParentCallId = new Uint32Array(size);
|
|
656
|
+
const nextTimestampNs = new BigInt64Array(size);
|
|
657
|
+
const nextDurationNs = new BigInt64Array(size);
|
|
658
|
+
const nextSuppressionIndex = new Uint32Array(size);
|
|
659
|
+
if (this.length > 0) {
|
|
660
|
+
nextKind.set(this.kind.subarray(0, this.length));
|
|
661
|
+
nextPlanId.set(this.planId.subarray(0, this.length));
|
|
662
|
+
nextCallId.set(this.callId.subarray(0, this.length));
|
|
663
|
+
nextParentCallId.set(this.parentCallId.subarray(0, this.length));
|
|
664
|
+
nextTimestampNs.set(this.timestampNs.subarray(0, this.length));
|
|
665
|
+
nextDurationNs.set(this.durationNs.subarray(0, this.length));
|
|
666
|
+
nextSuppressionIndex.set(this.suppressionIndex.subarray(0, this.length));
|
|
667
|
+
}
|
|
668
|
+
this.kind = nextKind;
|
|
669
|
+
this.planId = nextPlanId;
|
|
670
|
+
this.callId = nextCallId;
|
|
671
|
+
this.parentCallId = nextParentCallId;
|
|
672
|
+
this.timestampNs = nextTimestampNs;
|
|
673
|
+
this.durationNs = nextDurationNs;
|
|
674
|
+
this.suppressionIndex = nextSuppressionIndex;
|
|
675
|
+
this.allocatedBytes = size * BYTES_PER_EVENT;
|
|
435
676
|
}
|
|
436
677
|
evictCompletedLeafOrSummary() {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
const
|
|
440
|
-
if (
|
|
441
|
-
this.
|
|
678
|
+
for (let index = 0; index < this.length; index++) {
|
|
679
|
+
if (this.kind[index] !== KIND_SUPPRESSED) continue;
|
|
680
|
+
const group = this.suppressions[this.suppressionIndex[index] ?? 0];
|
|
681
|
+
if (group) group.retainedIndex = -1;
|
|
682
|
+
this.removeAt(index);
|
|
442
683
|
this.dropped++;
|
|
443
684
|
return true;
|
|
444
685
|
}
|
|
445
686
|
const parentCallIds = /* @__PURE__ */ new Set();
|
|
446
|
-
for (
|
|
447
|
-
const
|
|
448
|
-
if (
|
|
687
|
+
for (let index = 0; index < this.length; index++) {
|
|
688
|
+
const kind = this.kind[index];
|
|
689
|
+
if (kind !== KIND_ENTER && kind !== KIND_SUPPRESSED) continue;
|
|
690
|
+
const parentCallId = this.parentCallId[index] ?? NO_PARENT;
|
|
691
|
+
if (parentCallId !== NO_PARENT) parentCallIds.add(parentCallId);
|
|
449
692
|
}
|
|
450
|
-
for (let index = 0; index < this.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
693
|
+
for (let index = 0; index < this.length; index++) {
|
|
694
|
+
if (this.kind[index] !== KIND_ENTER) continue;
|
|
695
|
+
const eventCallId = this.callId[index] ?? 0;
|
|
696
|
+
if (this.openCallIds.has(eventCallId) || parentCallIds.has(eventCallId)) continue;
|
|
697
|
+
let terminalIndex = -1;
|
|
698
|
+
for (let candidate = 0; candidate < this.length; candidate++) {
|
|
699
|
+
const kind = this.kind[candidate];
|
|
700
|
+
if ((kind === KIND_EXIT || kind === KIND_THROW) && this.callId[candidate] === eventCallId) {
|
|
701
|
+
terminalIndex = candidate;
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
454
704
|
}
|
|
455
|
-
const terminalIndex = this.items.findIndex(
|
|
456
|
-
(candidate) => !isSuppressionPlaceholder(candidate) && (candidate.type === "function_exit" || candidate.type === "function_throw") && candidate.callId === event.callId
|
|
457
|
-
);
|
|
458
705
|
if (terminalIndex < 0) continue;
|
|
459
|
-
|
|
460
|
-
|
|
706
|
+
const later = Math.max(index, terminalIndex);
|
|
707
|
+
const earlier = Math.min(index, terminalIndex);
|
|
708
|
+
this.removeAt(later);
|
|
709
|
+
this.removeAt(earlier);
|
|
461
710
|
this.dropped += 2;
|
|
462
711
|
return true;
|
|
463
712
|
}
|
|
464
713
|
return false;
|
|
465
714
|
}
|
|
715
|
+
removeAt(index) {
|
|
716
|
+
this.payloads[index] = void 0;
|
|
717
|
+
const next = index + 1;
|
|
718
|
+
if (next < this.length) {
|
|
719
|
+
this.kind.copyWithin(index, next, this.length);
|
|
720
|
+
this.planId.copyWithin(index, next, this.length);
|
|
721
|
+
this.callId.copyWithin(index, next, this.length);
|
|
722
|
+
this.parentCallId.copyWithin(index, next, this.length);
|
|
723
|
+
this.timestampNs.copyWithin(index, next, this.length);
|
|
724
|
+
this.durationNs.copyWithin(index, next, this.length);
|
|
725
|
+
this.suppressionIndex.copyWithin(index, next, this.length);
|
|
726
|
+
this.payloads.copyWithin(index, next, this.length);
|
|
727
|
+
}
|
|
728
|
+
this.payloads[this.length - 1] = void 0;
|
|
729
|
+
this.length--;
|
|
730
|
+
this.payloads.length = this.length;
|
|
731
|
+
for (const group of this.suppressions) {
|
|
732
|
+
if (group.retainedIndex > index) group.retainedIndex--;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
var ExecutionJournalPool = class {
|
|
737
|
+
constructor(capacity, maxPooled = MAX_POOLED_JOURNALS) {
|
|
738
|
+
this.capacity = capacity;
|
|
739
|
+
this.maxPooled = maxPooled;
|
|
740
|
+
}
|
|
741
|
+
hits = 0;
|
|
742
|
+
misses = 0;
|
|
743
|
+
available = [];
|
|
744
|
+
acquire() {
|
|
745
|
+
const pooled = this.available.pop();
|
|
746
|
+
if (pooled) {
|
|
747
|
+
this.hits++;
|
|
748
|
+
return pooled;
|
|
749
|
+
}
|
|
750
|
+
this.misses++;
|
|
751
|
+
return new ExecutionJournal(this.capacity);
|
|
752
|
+
}
|
|
753
|
+
release(journal) {
|
|
754
|
+
journal.clear();
|
|
755
|
+
if (this.available.length >= this.maxPooled || journal.capacity > MAX_POOLED_JOURNAL_CAPACITY || journal.capacity !== this.capacity) {
|
|
756
|
+
return;
|
|
757
|
+
}
|
|
758
|
+
this.available.push(journal);
|
|
759
|
+
}
|
|
760
|
+
stats() {
|
|
761
|
+
return {
|
|
762
|
+
journalPoolHits: this.hits,
|
|
763
|
+
journalPoolMisses: this.misses,
|
|
764
|
+
journalPoolSize: this.available.length,
|
|
765
|
+
journalAllocatedCapacity: this.capacity
|
|
766
|
+
};
|
|
767
|
+
}
|
|
466
768
|
};
|
|
467
769
|
|
|
468
770
|
// src/execution-recorder/recorder-memory-budget.ts
|
|
@@ -540,6 +842,12 @@ var RecorderMemoryBudget = class {
|
|
|
540
842
|
this.dropEvents(allocation, 1);
|
|
541
843
|
return false;
|
|
542
844
|
}
|
|
845
|
+
reserveStorage(allocation, bytes) {
|
|
846
|
+
if (allocation.released || allocation.mode === "metadata-only") return false;
|
|
847
|
+
if (this.reserve(allocation, bytes)) return true;
|
|
848
|
+
this.markPressure(allocation, "metadata-only");
|
|
849
|
+
return false;
|
|
850
|
+
}
|
|
543
851
|
release(allocation) {
|
|
544
852
|
if (allocation.released) return;
|
|
545
853
|
allocation.released = true;
|
|
@@ -600,10 +908,7 @@ var defaults = {
|
|
|
600
908
|
maxStringLength: 500,
|
|
601
909
|
maxSerializedValueBytes: 8 * 1024
|
|
602
910
|
};
|
|
603
|
-
var
|
|
604
|
-
var TYPE_MARKER_VALUE_MID = '","value":"';
|
|
605
|
-
var TYPE_MARKER_CLOSE = '"}';
|
|
606
|
-
var UNDEFINED_MARKER_BYTES = TYPE_MARKER_OPEN.length + "undefined".length + TYPE_MARKER_CLOSE.length;
|
|
911
|
+
var REDACTED = "[RASPUTIN_REDACTED]";
|
|
607
912
|
var truncation = (reason, extra = {}) => ({
|
|
608
913
|
__rasputin_truncated: true,
|
|
609
914
|
__reason: reason,
|
|
@@ -613,7 +918,83 @@ var typeMarker = (type, value) => ({
|
|
|
613
918
|
__rasputin_type: type,
|
|
614
919
|
...value === void 0 ? {} : { value }
|
|
615
920
|
});
|
|
616
|
-
var
|
|
921
|
+
var jsonStringUtf8Bytes = (value) => {
|
|
922
|
+
let bytes = 2;
|
|
923
|
+
for (let index = 0; index < value.length; index++) {
|
|
924
|
+
const code = value.charCodeAt(index);
|
|
925
|
+
if (code === 34 || code === 92) {
|
|
926
|
+
bytes += 2;
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
if (code === 8 || code === 9 || code === 10 || code === 12 || code === 13) {
|
|
930
|
+
bytes += 2;
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
if (code < 32) {
|
|
934
|
+
bytes += 6;
|
|
935
|
+
continue;
|
|
936
|
+
}
|
|
937
|
+
if (code < 128) {
|
|
938
|
+
bytes += 1;
|
|
939
|
+
continue;
|
|
940
|
+
}
|
|
941
|
+
if (code < 2048) {
|
|
942
|
+
bytes += 2;
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
if (code >= 55296 && code <= 56319) {
|
|
946
|
+
const next = value.charCodeAt(index + 1);
|
|
947
|
+
if (index + 1 < value.length && next >= 56320 && next <= 57343) {
|
|
948
|
+
bytes += 4;
|
|
949
|
+
index++;
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
bytes += 6;
|
|
953
|
+
continue;
|
|
954
|
+
}
|
|
955
|
+
if (code >= 56320 && code <= 57343) {
|
|
956
|
+
bytes += 6;
|
|
957
|
+
continue;
|
|
958
|
+
}
|
|
959
|
+
bytes += 3;
|
|
960
|
+
}
|
|
961
|
+
return bytes;
|
|
962
|
+
};
|
|
963
|
+
var jsonLiteralUtf8Bytes = (value) => {
|
|
964
|
+
if (value === null) return 4;
|
|
965
|
+
switch (typeof value) {
|
|
966
|
+
case "boolean":
|
|
967
|
+
return value ? 4 : 5;
|
|
968
|
+
case "number":
|
|
969
|
+
if (!Number.isFinite(value)) return 4;
|
|
970
|
+
if (Object.is(value, -0)) return 1;
|
|
971
|
+
return String(value).length;
|
|
972
|
+
case "string":
|
|
973
|
+
return jsonStringUtf8Bytes(value);
|
|
974
|
+
case "object": {
|
|
975
|
+
if (Array.isArray(value)) {
|
|
976
|
+
let bytes2 = 2;
|
|
977
|
+
for (let index = 0; index < value.length; index++) {
|
|
978
|
+
if (index > 0) bytes2 += 1;
|
|
979
|
+
bytes2 += jsonLiteralUtf8Bytes(value[index]);
|
|
980
|
+
}
|
|
981
|
+
return bytes2;
|
|
982
|
+
}
|
|
983
|
+
const record = value;
|
|
984
|
+
let bytes = 2;
|
|
985
|
+
let first = true;
|
|
986
|
+
for (const key of Object.keys(record)) {
|
|
987
|
+
if (!first) bytes += 1;
|
|
988
|
+
first = false;
|
|
989
|
+
bytes += jsonStringUtf8Bytes(key) + 1;
|
|
990
|
+
bytes += jsonLiteralUtf8Bytes(record[key]);
|
|
991
|
+
}
|
|
992
|
+
return bytes;
|
|
993
|
+
}
|
|
994
|
+
default:
|
|
995
|
+
return Buffer2.byteLength(JSON.stringify(value) ?? "null", "utf8");
|
|
996
|
+
}
|
|
997
|
+
};
|
|
617
998
|
var compileLimits = (options) => ({
|
|
618
999
|
maxDepth: options.maxDepth ?? defaults.maxDepth,
|
|
619
1000
|
maxObjectKeys: options.maxObjectKeys ?? defaults.maxObjectKeys,
|
|
@@ -625,6 +1006,13 @@ var compileRedactKeys = (options) => {
|
|
|
625
1006
|
if (!options.redactKeys?.length) return new Set(DEFAULT_REDACT_KEYS);
|
|
626
1007
|
return /* @__PURE__ */ new Set([...DEFAULT_REDACT_KEYS, ...options.redactKeys.map((key) => key.toLowerCase())]);
|
|
627
1008
|
};
|
|
1009
|
+
var keyNeedsCaseFold = (key) => {
|
|
1010
|
+
for (let index = 0; index < key.length; index++) {
|
|
1011
|
+
const code = key.charCodeAt(index);
|
|
1012
|
+
if (code > 127 || code >= 65 && code <= 90) return true;
|
|
1013
|
+
}
|
|
1014
|
+
return false;
|
|
1015
|
+
};
|
|
628
1016
|
var isJsonSafeString = (value) => {
|
|
629
1017
|
for (let index = 0; index < value.length; index++) {
|
|
630
1018
|
const code = value.charCodeAt(index);
|
|
@@ -639,7 +1027,6 @@ var isJsonSafeString = (value) => {
|
|
|
639
1027
|
}
|
|
640
1028
|
return true;
|
|
641
1029
|
};
|
|
642
|
-
var typeMarkerWithValueBytes = (type, jsonSafeValue) => TYPE_MARKER_OPEN.length + type.length + TYPE_MARKER_VALUE_MID.length + Buffer2.byteLength(jsonSafeValue, "utf8") + TYPE_MARKER_CLOSE.length;
|
|
643
1030
|
var primitiveFastPath = (value, maxStringLength) => {
|
|
644
1031
|
if (value === null) return { value: null, bytes: 4, visitedNodes: 1 };
|
|
645
1032
|
if (typeof value === "boolean") return { value, bytes: value ? 4 : 5, visitedNodes: 1 };
|
|
@@ -653,176 +1040,306 @@ var primitiveFastPath = (value, maxStringLength) => {
|
|
|
653
1040
|
return { value, bytes: 2 + Buffer2.byteLength(value, "utf8"), visitedNodes: 1 };
|
|
654
1041
|
}
|
|
655
1042
|
if (typeof value === "undefined") {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
bytes: UNDEFINED_MARKER_BYTES,
|
|
659
|
-
visitedNodes: 1
|
|
660
|
-
};
|
|
1043
|
+
const serialized = typeMarker("undefined");
|
|
1044
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
661
1045
|
}
|
|
662
1046
|
if (typeof value === "bigint") {
|
|
663
|
-
const
|
|
664
|
-
return {
|
|
665
|
-
value: { __rasputin_type: "bigint", value: digits },
|
|
666
|
-
bytes: typeMarkerWithValueBytes("bigint", digits),
|
|
667
|
-
visitedNodes: 1
|
|
668
|
-
};
|
|
1047
|
+
const serialized = typeMarker("bigint", value.toString());
|
|
1048
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
669
1049
|
}
|
|
670
1050
|
if (typeof value === "symbol") {
|
|
671
1051
|
const text = String(value);
|
|
672
1052
|
if (!isJsonSafeString(text)) return void 0;
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
bytes: typeMarkerWithValueBytes("symbol", text),
|
|
676
|
-
visitedNodes: 1
|
|
677
|
-
};
|
|
1053
|
+
const serialized = typeMarker("symbol", text);
|
|
1054
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
678
1055
|
}
|
|
679
1056
|
if (typeof value === "function") {
|
|
680
1057
|
const name = value.name || "anonymous";
|
|
681
1058
|
if (!isJsonSafeString(name)) return void 0;
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
bytes: typeMarkerWithValueBytes("function", name),
|
|
685
|
-
visitedNodes: 1
|
|
686
|
-
};
|
|
1059
|
+
const serialized = typeMarker("function", name);
|
|
1060
|
+
return { value: serialized, bytes: jsonLiteralUtf8Bytes(serialized), visitedNodes: 1 };
|
|
687
1061
|
}
|
|
688
1062
|
return void 0;
|
|
689
1063
|
};
|
|
690
1064
|
var createSafeSerializer = (options = {}) => {
|
|
691
1065
|
const limits = compileLimits(options);
|
|
692
1066
|
const redactKeys = compileRedactKeys(options);
|
|
693
|
-
const
|
|
1067
|
+
const sharedPath = /* @__PURE__ */ new Set();
|
|
1068
|
+
let serializing = false;
|
|
1069
|
+
const isRedactedKey = (key) => {
|
|
1070
|
+
if (redactKeys.has(key)) return true;
|
|
1071
|
+
if (!keyNeedsCaseFold(key)) return false;
|
|
1072
|
+
return redactKeys.has(key.toLowerCase());
|
|
1073
|
+
};
|
|
1074
|
+
const addBytes = (metrics, count) => {
|
|
1075
|
+
metrics.bytes += count;
|
|
1076
|
+
if (metrics.bytes > limits.maxSerializedValueBytes) metrics.oversize = true;
|
|
1077
|
+
};
|
|
1078
|
+
const boundedOversize = (bytes, visitedNodes) => {
|
|
1079
|
+
const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
|
|
1080
|
+
return { value: bounded, bytes: jsonLiteralUtf8Bytes(bounded), visitedNodes };
|
|
1081
|
+
};
|
|
1082
|
+
const openObject = (metrics, allocate) => {
|
|
1083
|
+
addBytes(metrics, 2);
|
|
1084
|
+
return {
|
|
1085
|
+
target: allocate && !metrics.oversize ? {} : void 0,
|
|
1086
|
+
first: true
|
|
1087
|
+
};
|
|
1088
|
+
};
|
|
1089
|
+
const openArray = (metrics, allocate) => {
|
|
1090
|
+
addBytes(metrics, 2);
|
|
1091
|
+
return {
|
|
1092
|
+
items: allocate && !metrics.oversize ? [] : void 0,
|
|
1093
|
+
first: true
|
|
1094
|
+
};
|
|
1095
|
+
};
|
|
1096
|
+
const beginField = (metrics, object, key) => {
|
|
1097
|
+
if (!object.first) addBytes(metrics, 1);
|
|
1098
|
+
object.first = false;
|
|
1099
|
+
addBytes(metrics, jsonStringUtf8Bytes(key) + 1);
|
|
1100
|
+
};
|
|
1101
|
+
const assignField = (object, key, fieldValue) => {
|
|
1102
|
+
if (object.target) object.target[key] = fieldValue;
|
|
1103
|
+
};
|
|
1104
|
+
const writeLiteralField = (metrics, object, key, jsonValue) => {
|
|
1105
|
+
beginField(metrics, object, key);
|
|
1106
|
+
addBytes(metrics, jsonLiteralUtf8Bytes(jsonValue));
|
|
1107
|
+
assignField(object, key, jsonValue);
|
|
1108
|
+
};
|
|
1109
|
+
const writeTypeMarker = (metrics, allocate, type, nestedValue) => {
|
|
1110
|
+
const object = openObject(metrics, allocate);
|
|
1111
|
+
writeLiteralField(metrics, object, "__rasputin_type", type);
|
|
1112
|
+
if (nestedValue !== void 0) writeLiteralField(metrics, object, "value", nestedValue);
|
|
1113
|
+
return object.target;
|
|
1114
|
+
};
|
|
1115
|
+
const writeTruncation = (metrics, allocate, reason, extra = {}) => {
|
|
1116
|
+
const object = openObject(metrics, allocate);
|
|
1117
|
+
writeLiteralField(metrics, object, "__rasputin_truncated", true);
|
|
1118
|
+
writeLiteralField(metrics, object, "__reason", reason);
|
|
1119
|
+
for (const key of Object.keys(extra)) writeLiteralField(metrics, object, key, extra[key]);
|
|
1120
|
+
return object.target;
|
|
1121
|
+
};
|
|
1122
|
+
const serializeInner = (value, depth, path, allocate, metrics) => {
|
|
694
1123
|
metrics.visitedNodes++;
|
|
695
|
-
|
|
1124
|
+
const store = allocate && !metrics.oversize;
|
|
1125
|
+
if (value === null) {
|
|
1126
|
+
addBytes(metrics, 4);
|
|
1127
|
+
return store ? null : void 0;
|
|
1128
|
+
}
|
|
1129
|
+
if (typeof value === "boolean") {
|
|
1130
|
+
addBytes(metrics, value ? 4 : 5);
|
|
1131
|
+
return store ? value : void 0;
|
|
1132
|
+
}
|
|
1133
|
+
if (typeof value === "number") {
|
|
1134
|
+
if (!Number.isFinite(value)) addBytes(metrics, 4);
|
|
1135
|
+
else if (Object.is(value, -0)) addBytes(metrics, 1);
|
|
1136
|
+
else addBytes(metrics, String(value).length);
|
|
1137
|
+
return store ? value : void 0;
|
|
1138
|
+
}
|
|
696
1139
|
if (typeof value === "string") {
|
|
697
|
-
if (value.length <= limits.maxStringLength)
|
|
698
|
-
|
|
1140
|
+
if (value.length <= limits.maxStringLength) {
|
|
1141
|
+
addBytes(metrics, jsonStringUtf8Bytes(value));
|
|
1142
|
+
return store ? value : void 0;
|
|
1143
|
+
}
|
|
1144
|
+
return writeTruncation(metrics, store, "max_string_length", {
|
|
699
1145
|
__original_length: value.length,
|
|
700
1146
|
value: value.slice(0, limits.maxStringLength)
|
|
701
1147
|
});
|
|
702
1148
|
}
|
|
703
|
-
if (typeof value === "undefined") return
|
|
704
|
-
if (typeof value === "bigint")
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
if (
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
if (
|
|
711
|
-
|
|
1149
|
+
if (typeof value === "undefined") return writeTypeMarker(metrics, store, "undefined");
|
|
1150
|
+
if (typeof value === "bigint") {
|
|
1151
|
+
return writeTypeMarker(metrics, store, "bigint", value.toString());
|
|
1152
|
+
}
|
|
1153
|
+
if (typeof value === "symbol") {
|
|
1154
|
+
return writeTypeMarker(metrics, store, "symbol", String(value));
|
|
1155
|
+
}
|
|
1156
|
+
if (typeof value === "function") {
|
|
1157
|
+
return writeTypeMarker(metrics, store, "function", value.name || "anonymous");
|
|
1158
|
+
}
|
|
1159
|
+
if (depth >= limits.maxDepth) return writeTruncation(metrics, store, "max_depth");
|
|
1160
|
+
if (typeof value !== "object") return writeTypeMarker(metrics, store, typeof value);
|
|
1161
|
+
if (path.has(value)) return writeTypeMarker(metrics, store, "circular");
|
|
1162
|
+
path.add(value);
|
|
1163
|
+
const bytesBefore = metrics.bytes;
|
|
1164
|
+
const oversizeBefore = metrics.oversize;
|
|
712
1165
|
try {
|
|
1166
|
+
const childAllocate = allocate && !metrics.oversize;
|
|
713
1167
|
if (value instanceof Error) {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
1168
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1169
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Error");
|
|
1170
|
+
writeLiteralField(metrics, object2, "name", value.name);
|
|
1171
|
+
beginField(metrics, object2, "message");
|
|
1172
|
+
assignField(
|
|
1173
|
+
object2,
|
|
1174
|
+
"message",
|
|
1175
|
+
serializeInner(value.message, depth + 1, path, childAllocate, metrics)
|
|
1176
|
+
);
|
|
1177
|
+
if (value.stack) {
|
|
1178
|
+
beginField(metrics, object2, "stack");
|
|
1179
|
+
assignField(
|
|
1180
|
+
object2,
|
|
1181
|
+
"stack",
|
|
1182
|
+
serializeInner(value.stack, depth + 1, path, childAllocate, metrics)
|
|
1183
|
+
);
|
|
1184
|
+
}
|
|
1185
|
+
return object2.target;
|
|
1186
|
+
}
|
|
1187
|
+
if (value instanceof Date) {
|
|
1188
|
+
return writeTypeMarker(metrics, childAllocate, "Date", value.toISOString());
|
|
720
1189
|
}
|
|
721
|
-
if (value instanceof Date) return typeMarker("Date", value.toISOString());
|
|
722
1190
|
if (Buffer2.isBuffer(value)) {
|
|
723
|
-
return
|
|
1191
|
+
return writeTypeMarker(metrics, childAllocate, "Buffer", {
|
|
724
1192
|
byteLength: value.byteLength,
|
|
725
1193
|
base64: value.subarray(0, limits.maxStringLength).toString("base64"),
|
|
726
1194
|
...value.byteLength > limits.maxStringLength ? { __rasputin_truncated: true } : {}
|
|
727
1195
|
});
|
|
728
1196
|
}
|
|
729
|
-
if (value instanceof Promise) return
|
|
1197
|
+
if (value instanceof Promise) return writeTypeMarker(metrics, childAllocate, "Promise");
|
|
730
1198
|
if (value instanceof Map) {
|
|
731
|
-
const
|
|
1199
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1200
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Map");
|
|
1201
|
+
beginField(metrics, object2, "entries");
|
|
1202
|
+
const entries = openArray(metrics, childAllocate);
|
|
1203
|
+
let counted2 = 0;
|
|
732
1204
|
for (const entry of value.entries()) {
|
|
733
|
-
if (
|
|
734
|
-
entries.
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
]);
|
|
1205
|
+
if (counted2 >= limits.maxArrayElements) break;
|
|
1206
|
+
if (!entries.first) addBytes(metrics, 1);
|
|
1207
|
+
entries.first = false;
|
|
1208
|
+
addBytes(metrics, 2);
|
|
1209
|
+
const key = serializeInner(entry[0], depth + 1, path, childAllocate, metrics);
|
|
1210
|
+
addBytes(metrics, 1);
|
|
1211
|
+
const mapped = serializeInner(entry[1], depth + 1, path, childAllocate, metrics);
|
|
1212
|
+
entries.items?.push([key, mapped]);
|
|
1213
|
+
counted2++;
|
|
1214
|
+
}
|
|
1215
|
+
assignField(object2, "entries", entries.items ?? []);
|
|
1216
|
+
if (value.size > limits.maxArrayElements) {
|
|
1217
|
+
writeLiteralField(metrics, object2, "__rasputin_truncated", true);
|
|
1218
|
+
writeLiteralField(metrics, object2, "__reason", "max_array_elements");
|
|
1219
|
+
writeLiteralField(metrics, object2, "__original_length", value.size);
|
|
738
1220
|
}
|
|
739
|
-
return
|
|
740
|
-
__rasputin_type: "Map",
|
|
741
|
-
entries,
|
|
742
|
-
...value.size > limits.maxArrayElements ? truncation("max_array_elements", { __original_length: value.size }) : {}
|
|
743
|
-
};
|
|
1221
|
+
return object2.target;
|
|
744
1222
|
}
|
|
745
1223
|
if (value instanceof Set) {
|
|
746
|
-
const
|
|
1224
|
+
const object2 = openObject(metrics, childAllocate);
|
|
1225
|
+
writeLiteralField(metrics, object2, "__rasputin_type", "Set");
|
|
1226
|
+
beginField(metrics, object2, "values");
|
|
1227
|
+
const items = openArray(metrics, childAllocate);
|
|
1228
|
+
let counted2 = 0;
|
|
747
1229
|
for (const item of value.values()) {
|
|
748
|
-
if (
|
|
749
|
-
items.
|
|
1230
|
+
if (counted2 >= limits.maxArrayElements) break;
|
|
1231
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1232
|
+
items.first = false;
|
|
1233
|
+
const serializedItem = serializeInner(item, depth + 1, path, childAllocate, metrics);
|
|
1234
|
+
items.items?.push(serializedItem);
|
|
1235
|
+
counted2++;
|
|
750
1236
|
}
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1237
|
+
assignField(object2, "values", items.items ?? []);
|
|
1238
|
+
if (value.size > limits.maxArrayElements) {
|
|
1239
|
+
writeLiteralField(metrics, object2, "__rasputin_truncated", true);
|
|
1240
|
+
writeLiteralField(metrics, object2, "__reason", "max_array_elements");
|
|
1241
|
+
writeLiteralField(metrics, object2, "__original_length", value.size);
|
|
1242
|
+
}
|
|
1243
|
+
return object2.target;
|
|
756
1244
|
}
|
|
757
1245
|
if (Array.isArray(value)) {
|
|
1246
|
+
const items = openArray(metrics, childAllocate);
|
|
758
1247
|
const maxItems = value.length > limits.maxArrayElements ? limits.maxArrayElements - 1 : value.length;
|
|
759
|
-
const items = [];
|
|
760
1248
|
for (let index = 0; index < maxItems; index++) {
|
|
761
|
-
items.
|
|
1249
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1250
|
+
items.first = false;
|
|
1251
|
+
items.items?.push(serializeInner(value[index], depth + 1, path, childAllocate, metrics));
|
|
762
1252
|
}
|
|
763
1253
|
if (value.length > limits.maxArrayElements) {
|
|
764
|
-
items.
|
|
1254
|
+
if (!items.first) addBytes(metrics, 1);
|
|
1255
|
+
items.first = false;
|
|
1256
|
+
items.items?.push(
|
|
1257
|
+
writeTruncation(metrics, childAllocate, "max_array_elements", {
|
|
1258
|
+
__original_length: value.length
|
|
1259
|
+
})
|
|
1260
|
+
);
|
|
765
1261
|
}
|
|
766
|
-
return items;
|
|
1262
|
+
return items.items;
|
|
767
1263
|
}
|
|
1264
|
+
const object = openObject(metrics, childAllocate);
|
|
768
1265
|
const prototype = Object.getPrototypeOf(value);
|
|
769
|
-
const serialized = {};
|
|
770
1266
|
if (prototype && prototype !== Object.prototype) {
|
|
771
|
-
|
|
1267
|
+
writeLiteralField(
|
|
1268
|
+
metrics,
|
|
1269
|
+
object,
|
|
1270
|
+
"__rasputin_type",
|
|
1271
|
+
prototype.constructor?.name ?? "instance"
|
|
1272
|
+
);
|
|
772
1273
|
}
|
|
773
1274
|
const keys = Object.keys(value);
|
|
774
1275
|
const maxKeys = keys.length > limits.maxObjectKeys ? limits.maxObjectKeys - 1 : keys.length;
|
|
775
1276
|
for (let index = 0; index < maxKeys; index++) {
|
|
776
1277
|
const key = keys[index];
|
|
777
1278
|
if (key === void 0) continue;
|
|
778
|
-
if (
|
|
779
|
-
|
|
1279
|
+
if (isRedactedKey(key)) {
|
|
1280
|
+
writeLiteralField(metrics, object, key, REDACTED);
|
|
780
1281
|
continue;
|
|
781
1282
|
}
|
|
782
1283
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
783
|
-
|
|
1284
|
+
if (descriptor && "value" in descriptor) {
|
|
1285
|
+
beginField(metrics, object, key);
|
|
1286
|
+
assignField(
|
|
1287
|
+
object,
|
|
1288
|
+
key,
|
|
1289
|
+
serializeInner(descriptor.value, depth + 1, path, childAllocate, metrics)
|
|
1290
|
+
);
|
|
1291
|
+
} else {
|
|
1292
|
+
beginField(metrics, object, key);
|
|
1293
|
+
assignField(object, key, writeTypeMarker(metrics, childAllocate, "accessor"));
|
|
1294
|
+
}
|
|
784
1295
|
}
|
|
785
1296
|
if (keys.length > limits.maxObjectKeys) {
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
);
|
|
1297
|
+
writeLiteralField(metrics, object, "__rasputin_truncated", true);
|
|
1298
|
+
writeLiteralField(metrics, object, "__reason", "max_object_keys");
|
|
1299
|
+
writeLiteralField(metrics, object, "__original_length", keys.length);
|
|
790
1300
|
}
|
|
791
|
-
return
|
|
1301
|
+
return object.target;
|
|
792
1302
|
} catch (error) {
|
|
793
|
-
|
|
1303
|
+
metrics.bytes = bytesBefore;
|
|
1304
|
+
metrics.oversize = oversizeBefore;
|
|
1305
|
+
return writeTypeMarker(
|
|
1306
|
+
metrics,
|
|
1307
|
+
allocate && !metrics.oversize,
|
|
1308
|
+
"unserializable",
|
|
1309
|
+
error instanceof Error ? error.message : void 0
|
|
1310
|
+
);
|
|
794
1311
|
} finally {
|
|
795
|
-
|
|
1312
|
+
path.delete(value);
|
|
796
1313
|
}
|
|
797
1314
|
};
|
|
798
|
-
const boundedOversize = (bytes, visitedNodes) => {
|
|
799
|
-
const bounded = truncation("max_serialized_value_bytes", { __serialized_bytes: bytes });
|
|
800
|
-
return {
|
|
801
|
-
value: bounded,
|
|
802
|
-
bytes: Buffer2.byteLength(JSON.stringify(bounded), "utf8"),
|
|
803
|
-
visitedNodes
|
|
804
|
-
};
|
|
805
|
-
};
|
|
806
1315
|
const serializeWithBytes = (value) => {
|
|
807
1316
|
const fast = primitiveFastPath(value, limits.maxStringLength);
|
|
808
1317
|
if (fast) {
|
|
809
1318
|
return fast.bytes <= limits.maxSerializedValueBytes ? fast : boundedOversize(fast.bytes, fast.visitedNodes);
|
|
810
1319
|
}
|
|
811
|
-
const metrics = { visitedNodes: 0 };
|
|
1320
|
+
const metrics = { visitedNodes: 0, bytes: 0, oversize: false };
|
|
1321
|
+
const reentrant = serializing;
|
|
1322
|
+
const path = reentrant ? /* @__PURE__ */ new Set() : sharedPath;
|
|
1323
|
+
if (!reentrant) {
|
|
1324
|
+
serializing = true;
|
|
1325
|
+
sharedPath.clear();
|
|
1326
|
+
}
|
|
812
1327
|
try {
|
|
813
|
-
const serialized = serializeInner(value, 0,
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
return { value: serialized, bytes, visitedNodes: metrics.visitedNodes };
|
|
1328
|
+
const serialized = serializeInner(value, 0, path, true, metrics);
|
|
1329
|
+
if (metrics.bytes > limits.maxSerializedValueBytes) {
|
|
1330
|
+
return boundedOversize(metrics.bytes, metrics.visitedNodes);
|
|
817
1331
|
}
|
|
818
|
-
return
|
|
1332
|
+
return { value: serialized, bytes: metrics.bytes, visitedNodes: metrics.visitedNodes };
|
|
819
1333
|
} catch {
|
|
820
1334
|
const failed = typeMarker("unserializable");
|
|
821
1335
|
return {
|
|
822
1336
|
value: failed,
|
|
823
|
-
bytes:
|
|
1337
|
+
bytes: jsonLiteralUtf8Bytes(failed),
|
|
824
1338
|
visitedNodes: metrics.visitedNodes
|
|
825
1339
|
};
|
|
1340
|
+
} finally {
|
|
1341
|
+
path.clear();
|
|
1342
|
+
if (!reentrant) serializing = false;
|
|
826
1343
|
}
|
|
827
1344
|
};
|
|
828
1345
|
return {
|
|
@@ -898,6 +1415,7 @@ var createSourceExclusionMatcher = (exclusions) => {
|
|
|
898
1415
|
|
|
899
1416
|
// src/execution-recorder/execution-recorder.ts
|
|
900
1417
|
var DEFAULT_MAX_ACTIVE_MEMORY_BYTES = 64 * 1024 * 1024;
|
|
1418
|
+
var phaseTimingEnabled = process.env.RASPUTIN_RECORDER_PHASE_TIMING === "1";
|
|
901
1419
|
var manualFunctionDefinition = (value) => {
|
|
902
1420
|
const located = /^(.+):([^:@]+)@(\d+):(\d+)$/.exec(value);
|
|
903
1421
|
const named = located ? void 0 : /^(.+):([^:@]+)$/.exec(value);
|
|
@@ -912,8 +1430,8 @@ var manualFunctionDefinition = (value) => {
|
|
|
912
1430
|
return { ...definition, functionId: runtimeFunctionId2(definition) };
|
|
913
1431
|
};
|
|
914
1432
|
var normalizeFunctionDefinition = (value) => typeof value === "string" ? manualFunctionDefinition(value) : value;
|
|
915
|
-
var
|
|
916
|
-
var
|
|
1433
|
+
var elapsedMs2 = (startedAtNs, endedAtNs = process.hrtime.bigint()) => Number(endedAtNs - startedAtNs) / 1e6;
|
|
1434
|
+
var roundedMilliseconds2 = (nanoseconds) => Math.round(Number(nanoseconds) / 1e6 * 1e4) / 1e4;
|
|
917
1435
|
var addRecorderTime = (recording, nanoseconds) => {
|
|
918
1436
|
if (nanoseconds > 0n) recording.inlineRecorderTimeNs += nanoseconds;
|
|
919
1437
|
};
|
|
@@ -1005,7 +1523,11 @@ var emptyStats = {
|
|
|
1005
1523
|
totalInlineWallTimeMs: 0,
|
|
1006
1524
|
maxInlineWallTimeMs: 0,
|
|
1007
1525
|
activeEstimatedBytes: 0,
|
|
1008
|
-
peakActiveEstimatedBytes: 0
|
|
1526
|
+
peakActiveEstimatedBytes: 0,
|
|
1527
|
+
journalPoolHits: 0,
|
|
1528
|
+
journalPoolMisses: 0,
|
|
1529
|
+
journalPoolSize: 0,
|
|
1530
|
+
journalAllocatedCapacity: 0
|
|
1009
1531
|
};
|
|
1010
1532
|
var noOpExecution = {
|
|
1011
1533
|
createScope: () => ({
|
|
@@ -1028,10 +1550,26 @@ var mergeExecutionMetadata = (target, metadata) => {
|
|
|
1028
1550
|
if (metadata.name !== void 0) target.name = metadata.name;
|
|
1029
1551
|
if (metadata.request) target.request = { ...target.request, ...metadata.request };
|
|
1030
1552
|
};
|
|
1553
|
+
var newRepeatedGroup = (plan) => ({
|
|
1554
|
+
observedCalls: 0,
|
|
1555
|
+
functionId: plan.functionId,
|
|
1556
|
+
runtimePlanId: plan.runtimePlanId
|
|
1557
|
+
});
|
|
1558
|
+
var newSuppression = (group, parentCallId, startedAtNs, endedAtNs) => ({
|
|
1559
|
+
count: 1,
|
|
1560
|
+
firstTimestampNs: startedAtNs,
|
|
1561
|
+
lastTimestampNs: endedAtNs,
|
|
1562
|
+
totalDurationNs: endedAtNs - startedAtNs,
|
|
1563
|
+
functionId: group.functionId,
|
|
1564
|
+
runtimePlanId: group.runtimePlanId,
|
|
1565
|
+
...parentCallId === void 0 ? {} : { parentCallId },
|
|
1566
|
+
storageIndex: -1,
|
|
1567
|
+
retainedIndex: -1
|
|
1568
|
+
});
|
|
1031
1569
|
var createExecutionRecorder = (options) => {
|
|
1032
1570
|
if (!options?.enabled) return noOpExecution;
|
|
1033
1571
|
const storage = new AsyncLocalStorage();
|
|
1034
|
-
const maxEventsPerExecution =
|
|
1572
|
+
const maxEventsPerExecution = sanitizeJournalCapacity(options.maxEventsPerExecution);
|
|
1035
1573
|
const maxCapturedCallsPerFunction = Math.max(
|
|
1036
1574
|
1,
|
|
1037
1575
|
Math.floor(options.maxCapturedCallsPerFunction ?? 3)
|
|
@@ -1046,11 +1584,14 @@ var createExecutionRecorder = (options) => {
|
|
|
1046
1584
|
);
|
|
1047
1585
|
const serializer = createSafeSerializer(options);
|
|
1048
1586
|
const excludesSource = createSourceExclusionMatcher(options.excludeSources);
|
|
1587
|
+
const journalPool = new ExecutionJournalPool(maxEventsPerExecution);
|
|
1588
|
+
const plansByRuntimeId = [];
|
|
1049
1589
|
let executionCounter = 0;
|
|
1050
1590
|
let nextRuntimePlanId = 1;
|
|
1051
1591
|
const internedPlans = /* @__PURE__ */ new Map();
|
|
1052
1592
|
const preparedModules = /* @__PURE__ */ new WeakMap();
|
|
1053
1593
|
const errorExecutions = /* @__PURE__ */ new WeakMap();
|
|
1594
|
+
const phases = phaseTimingEnabled ? { alsNs: 0n, materializeNs: 0n } : void 0;
|
|
1054
1595
|
const stats = {
|
|
1055
1596
|
functionCallsObserved: 0,
|
|
1056
1597
|
functionCallsCaptured: 0,
|
|
@@ -1069,8 +1610,11 @@ var createExecutionRecorder = (options) => {
|
|
|
1069
1610
|
totalInlineWallTimeMs: 0,
|
|
1070
1611
|
maxInlineWallTimeMs: 0
|
|
1071
1612
|
};
|
|
1613
|
+
const addPhase = (key, nanoseconds) => {
|
|
1614
|
+
if (phases && nanoseconds > 0n) phases[key] += nanoseconds;
|
|
1615
|
+
};
|
|
1072
1616
|
const recordInlineTiming = (recording) => {
|
|
1073
|
-
const inlineWallTimeMs =
|
|
1617
|
+
const inlineWallTimeMs = roundedMilliseconds2(recording.inlineRecorderTimeNs);
|
|
1074
1618
|
stats.measuredExecutions++;
|
|
1075
1619
|
stats.totalInlineWallTimeMs = Math.round((stats.totalInlineWallTimeMs + inlineWallTimeMs) * 1e4) / 1e4;
|
|
1076
1620
|
stats.maxInlineWallTimeMs = Math.max(stats.maxInlineWallTimeMs, inlineWallTimeMs);
|
|
@@ -1083,16 +1627,20 @@ var createExecutionRecorder = (options) => {
|
|
|
1083
1627
|
return serialized;
|
|
1084
1628
|
};
|
|
1085
1629
|
const captureValue = (recording, value) => memoryBudget.captureValue(recording.memory, () => serializeAndCount(value));
|
|
1630
|
+
const storePlan = (plan) => {
|
|
1631
|
+
plansByRuntimeId[plan.runtimePlanId] = plan;
|
|
1632
|
+
return plan;
|
|
1633
|
+
};
|
|
1086
1634
|
const preparePlan = (definition) => {
|
|
1087
1635
|
const existing = internedPlans.get(definition.functionId);
|
|
1088
1636
|
if (existing) return existing;
|
|
1089
|
-
const plan = {
|
|
1637
|
+
const plan = storePlan({
|
|
1090
1638
|
runtimePlanId: nextRuntimePlanId++,
|
|
1091
1639
|
definition,
|
|
1092
1640
|
functionId: definition.functionId,
|
|
1093
1641
|
excluded: excludesSource(definition),
|
|
1094
1642
|
estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
|
|
1095
|
-
};
|
|
1643
|
+
});
|
|
1096
1644
|
internedPlans.set(definition.functionId, plan);
|
|
1097
1645
|
return plan;
|
|
1098
1646
|
};
|
|
@@ -1101,62 +1649,66 @@ var createExecutionRecorder = (options) => {
|
|
|
1101
1649
|
if (cached) return cached;
|
|
1102
1650
|
const prepared = plans.map((encoded) => {
|
|
1103
1651
|
const definition = definitionFromEncodedPlan(encoded);
|
|
1104
|
-
return {
|
|
1652
|
+
return storePlan({
|
|
1105
1653
|
runtimePlanId: nextRuntimePlanId++,
|
|
1106
1654
|
definition,
|
|
1107
1655
|
functionId: definition.functionId,
|
|
1108
1656
|
excluded: excludesSource(definition),
|
|
1109
1657
|
estimatedCallBytes: estimatedCallBytesFor(definition.functionId)
|
|
1110
|
-
};
|
|
1658
|
+
});
|
|
1111
1659
|
});
|
|
1112
1660
|
preparedModules.set(plans, prepared);
|
|
1113
1661
|
return prepared;
|
|
1114
1662
|
};
|
|
1115
|
-
const snapshotSuppressed = (group, startedAtNs) => ({
|
|
1116
|
-
type: "function_calls_suppressed",
|
|
1117
|
-
functionId: group.functionId,
|
|
1118
|
-
timestampMs: elapsedMs(startedAtNs, group.firstTimestampNs),
|
|
1119
|
-
lastTimestampMs: elapsedMs(startedAtNs, group.lastTimestampNs),
|
|
1120
|
-
suppressedCallCount: group.count,
|
|
1121
|
-
totalDurationMs: roundedMilliseconds(group.totalDurationNs),
|
|
1122
|
-
...group.parentCallId === void 0 ? {} : { parentCallId: group.parentCallId }
|
|
1123
|
-
});
|
|
1124
1663
|
const stateFrom = (recording, endedAtNs = process.hrtime.bigint()) => {
|
|
1125
1664
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1665
|
+
let events = [];
|
|
1666
|
+
let functions = [];
|
|
1667
|
+
let truncated;
|
|
1668
|
+
let capture;
|
|
1669
|
+
if (recording.cachedState) {
|
|
1670
|
+
events = recording.cachedState.events;
|
|
1671
|
+
functions = recording.cachedState.functions;
|
|
1672
|
+
truncated = recording.cachedState.truncated;
|
|
1673
|
+
capture = recording.cachedState.capture;
|
|
1674
|
+
} else {
|
|
1675
|
+
if (recording.journal) {
|
|
1676
|
+
const materialized = recording.journal.materialize(plansByRuntimeId, recording.startedAtNs);
|
|
1677
|
+
events = materialized.events;
|
|
1678
|
+
functions = materialized.functions;
|
|
1679
|
+
truncated = recording.journal.dropped > 0 ? { eventsDropped: recording.journal.dropped } : void 0;
|
|
1680
|
+
}
|
|
1681
|
+
capture = recording.memory.underPressure ? {
|
|
1682
|
+
completeness: "partial",
|
|
1683
|
+
reason: "process_memory_budget",
|
|
1684
|
+
valuesDropped: recording.memory.valuesDropped,
|
|
1685
|
+
eventsDropped: recording.memory.eventsDropped
|
|
1686
|
+
} : void 0;
|
|
1687
|
+
if (recording.finished && recording.inFlightCalls === 0 && recording.journal) {
|
|
1688
|
+
recording.cachedState = { events, functions, truncated, capture };
|
|
1689
|
+
journalPool.release(recording.journal);
|
|
1690
|
+
recording.journal = void 0;
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1134
1693
|
const state = {
|
|
1135
1694
|
version: 2,
|
|
1136
1695
|
executionId: recording.executionId,
|
|
1137
1696
|
startedAt: recording.startedAt,
|
|
1138
|
-
durationMs:
|
|
1697
|
+
durationMs: elapsedMs2(recording.startedAtNs, endedAtNs),
|
|
1139
1698
|
recorder: { inlineWallTimeMs: 0 },
|
|
1140
1699
|
execution: {
|
|
1141
1700
|
...recording.execution,
|
|
1142
1701
|
...recording.execution.request ? { request: { ...recording.execution.request } } : {}
|
|
1143
1702
|
},
|
|
1144
|
-
functions:
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
...recording.events.dropped > 0 ? { truncated: { eventsDropped: recording.events.dropped } } : {},
|
|
1149
|
-
...recording.memory.underPressure ? {
|
|
1150
|
-
capture: {
|
|
1151
|
-
completeness: "partial",
|
|
1152
|
-
reason: "process_memory_budget",
|
|
1153
|
-
valuesDropped: recording.memory.valuesDropped,
|
|
1154
|
-
eventsDropped: recording.memory.eventsDropped
|
|
1155
|
-
}
|
|
1156
|
-
} : {}
|
|
1703
|
+
functions: functions.slice(),
|
|
1704
|
+
events: events.slice(),
|
|
1705
|
+
...truncated ? { truncated: { ...truncated } } : {},
|
|
1706
|
+
...capture ? { capture: { ...capture } } : {}
|
|
1157
1707
|
};
|
|
1708
|
+
if (phaseTimingEnabled)
|
|
1709
|
+
addPhase("materializeNs", process.hrtime.bigint() - recorderStartedAtNs);
|
|
1158
1710
|
addRecorderTime(recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
1159
|
-
state.recorder = { inlineWallTimeMs:
|
|
1711
|
+
state.recorder = { inlineWallTimeMs: roundedMilliseconds2(recording.inlineRecorderTimeNs) };
|
|
1160
1712
|
return state;
|
|
1161
1713
|
};
|
|
1162
1714
|
const rememberError = (error, recording) => {
|
|
@@ -1172,32 +1724,38 @@ var createExecutionRecorder = (options) => {
|
|
|
1172
1724
|
errorExecutions.set(error, recording);
|
|
1173
1725
|
};
|
|
1174
1726
|
const countDroppedEvents = (recording, droppedBefore) => {
|
|
1175
|
-
|
|
1727
|
+
const dropped = recording.journal?.dropped ?? droppedBefore;
|
|
1728
|
+
stats.truncatedEvents += dropped - droppedBefore;
|
|
1176
1729
|
};
|
|
1177
1730
|
const appendSuppressedPlaceholder = (recording, group) => {
|
|
1731
|
+
if (!recording.journal) return;
|
|
1178
1732
|
if (!memoryBudget.reserveStandaloneEvent(recording.memory)) return;
|
|
1179
|
-
const droppedBefore = recording.
|
|
1180
|
-
recording.
|
|
1733
|
+
const droppedBefore = recording.journal.dropped;
|
|
1734
|
+
recording.journal.appendSuppressed(group);
|
|
1181
1735
|
countDroppedEvents(recording, droppedBefore);
|
|
1182
1736
|
};
|
|
1183
|
-
const repeatedCallGroup = (recording,
|
|
1737
|
+
const repeatedCallGroup = (recording, plan, parentCallId) => {
|
|
1184
1738
|
const slots = recording.repeatedCalls;
|
|
1185
|
-
let slot = slots[runtimePlanId];
|
|
1739
|
+
let slot = slots[plan.runtimePlanId];
|
|
1186
1740
|
if (!slot) {
|
|
1187
1741
|
slot = {};
|
|
1188
|
-
slots[runtimePlanId] = slot;
|
|
1742
|
+
slots[plan.runtimePlanId] = slot;
|
|
1189
1743
|
}
|
|
1190
1744
|
if (parentCallId === void 0) {
|
|
1191
|
-
if (!slot.root) slot.root =
|
|
1745
|
+
if (!slot.root) slot.root = newRepeatedGroup(plan);
|
|
1192
1746
|
return slot.root;
|
|
1193
1747
|
}
|
|
1748
|
+
if (slot.lastParentGroup && slot.lastParentCallId === parentCallId) {
|
|
1749
|
+
return slot.lastParentGroup;
|
|
1750
|
+
}
|
|
1194
1751
|
if (!slot.byParent) slot.byParent = /* @__PURE__ */ new Map();
|
|
1195
|
-
|
|
1196
|
-
let group = byParent.get(parentCallId);
|
|
1752
|
+
let group = slot.byParent.get(parentCallId);
|
|
1197
1753
|
if (!group) {
|
|
1198
|
-
group =
|
|
1199
|
-
byParent.set(parentCallId, group);
|
|
1754
|
+
group = newRepeatedGroup(plan);
|
|
1755
|
+
slot.byParent.set(parentCallId, group);
|
|
1200
1756
|
}
|
|
1757
|
+
slot.lastParentCallId = parentCallId;
|
|
1758
|
+
slot.lastParentGroup = group;
|
|
1201
1759
|
return group;
|
|
1202
1760
|
};
|
|
1203
1761
|
const serializedError = (recording, error, callId) => {
|
|
@@ -1220,29 +1778,30 @@ var createExecutionRecorder = (options) => {
|
|
|
1220
1778
|
};
|
|
1221
1779
|
};
|
|
1222
1780
|
const captureCompletedThrow = (recording, plan, args, parentCallId, startedAtNs, error) => {
|
|
1781
|
+
if (!recording.journal) {
|
|
1782
|
+
rememberError(error, recording);
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1223
1785
|
if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
|
|
1224
1786
|
rememberError(error, recording);
|
|
1225
1787
|
return;
|
|
1226
1788
|
}
|
|
1227
1789
|
const callId = ++recording.nextCallId;
|
|
1228
1790
|
const capturedError = serializedError(recording, error, callId);
|
|
1229
|
-
const
|
|
1230
|
-
|
|
1791
|
+
const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
|
|
1792
|
+
const endedAtNs = process.hrtime.bigint();
|
|
1793
|
+
const droppedBefore = recording.journal.dropped;
|
|
1794
|
+
const retained = recording.journal.forceCompletedCall(
|
|
1795
|
+
plan.runtimePlanId,
|
|
1231
1796
|
callId,
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
timestampMs: elapsedMs(recording.startedAtNs),
|
|
1241
|
-
durationMs: elapsedMs(startedAtNs),
|
|
1242
|
-
error: capturedError.value
|
|
1243
|
-
};
|
|
1244
|
-
const droppedBefore = recording.events.dropped;
|
|
1245
|
-
const retained = recording.events.forceCompletedCall(enter, terminal);
|
|
1797
|
+
parentCallId,
|
|
1798
|
+
startedAtNs - recording.startedAtNs,
|
|
1799
|
+
capturedArgs,
|
|
1800
|
+
KIND_THROW,
|
|
1801
|
+
endedAtNs - recording.startedAtNs,
|
|
1802
|
+
endedAtNs - startedAtNs,
|
|
1803
|
+
capturedError.value
|
|
1804
|
+
);
|
|
1246
1805
|
if (retained) {
|
|
1247
1806
|
stats.functionCallsCaptured++;
|
|
1248
1807
|
capturedError.commit();
|
|
@@ -1250,29 +1809,46 @@ var createExecutionRecorder = (options) => {
|
|
|
1250
1809
|
countDroppedEvents(recording, droppedBefore);
|
|
1251
1810
|
rememberError(error, recording);
|
|
1252
1811
|
};
|
|
1253
|
-
const recordSuppressedCall = (recording, group,
|
|
1812
|
+
const recordSuppressedCall = (recording, group, parentCallId, startedAtNs, endedAtNs) => {
|
|
1254
1813
|
stats.repeatedCallsSuppressed++;
|
|
1255
|
-
const durationNs = endedAtNs - startedAtNs;
|
|
1256
1814
|
if (!group.suppressed) {
|
|
1257
|
-
group.suppressed =
|
|
1258
|
-
count: 1,
|
|
1259
|
-
firstTimestampNs: startedAtNs,
|
|
1260
|
-
lastTimestampNs: endedAtNs,
|
|
1261
|
-
totalDurationNs: durationNs,
|
|
1262
|
-
functionId,
|
|
1263
|
-
...parentCallId === void 0 ? {} : { parentCallId }
|
|
1264
|
-
};
|
|
1815
|
+
group.suppressed = newSuppression(group, parentCallId, startedAtNs, endedAtNs);
|
|
1265
1816
|
appendSuppressedPlaceholder(recording, group.suppressed);
|
|
1266
1817
|
return;
|
|
1267
1818
|
}
|
|
1268
1819
|
const suppressed = group.suppressed;
|
|
1269
1820
|
suppressed.count++;
|
|
1270
1821
|
suppressed.lastTimestampNs = endedAtNs;
|
|
1271
|
-
suppressed.totalDurationNs +=
|
|
1272
|
-
if (
|
|
1822
|
+
suppressed.totalDurationNs += endedAtNs - startedAtNs;
|
|
1823
|
+
if (suppressed.retainedIndex < 0) {
|
|
1273
1824
|
appendSuppressedPlaceholder(recording, suppressed);
|
|
1274
1825
|
}
|
|
1275
1826
|
};
|
|
1827
|
+
const releaseJournalIfIdle = (recording) => {
|
|
1828
|
+
if (!recording.finished || recording.hasError || recording.inFlightCalls > 0) return;
|
|
1829
|
+
if (!recording.journal) return;
|
|
1830
|
+
journalPool.release(recording.journal);
|
|
1831
|
+
recording.journal = void 0;
|
|
1832
|
+
};
|
|
1833
|
+
const acquireJournal = (recording) => {
|
|
1834
|
+
if (recording.journal) return recording.journal;
|
|
1835
|
+
try {
|
|
1836
|
+
const journal = journalPool.acquire();
|
|
1837
|
+
if (!memoryBudget.reserveStorage(recording.memory, journal.allocatedBytes)) {
|
|
1838
|
+
journalPool.release(journal);
|
|
1839
|
+
return void 0;
|
|
1840
|
+
}
|
|
1841
|
+
journal.onGrow = (deltaBytes) => memoryBudget.reserveStorage(recording.memory, deltaBytes);
|
|
1842
|
+
recording.journal = journal;
|
|
1843
|
+
return journal;
|
|
1844
|
+
} catch {
|
|
1845
|
+
return void 0;
|
|
1846
|
+
}
|
|
1847
|
+
};
|
|
1848
|
+
const settleInFlight = (recording) => {
|
|
1849
|
+
if (recording.inFlightCalls > 0) recording.inFlightCalls--;
|
|
1850
|
+
releaseJournalIfIdle(recording);
|
|
1851
|
+
};
|
|
1276
1852
|
const finish = (store, metadata) => {
|
|
1277
1853
|
const { recording } = store;
|
|
1278
1854
|
if (recording.finished) return;
|
|
@@ -1281,11 +1857,22 @@ var createExecutionRecorder = (options) => {
|
|
|
1281
1857
|
if (metadata) mergeExecutionMetadata(recording.execution, metadata);
|
|
1282
1858
|
memoryBudget.release(recording.memory);
|
|
1283
1859
|
stats.activeExecutions = Math.max(0, stats.activeExecutions - 1);
|
|
1284
|
-
if (!recording.hasError)
|
|
1860
|
+
if (!recording.hasError) {
|
|
1861
|
+
stats.successfulExecutionsDiscarded++;
|
|
1862
|
+
releaseJournalIfIdle(recording);
|
|
1863
|
+
}
|
|
1285
1864
|
recording.finishedAtNs = process.hrtime.bigint();
|
|
1286
1865
|
addRecorderTime(recording, recording.finishedAtNs - recorderStartedAtNs);
|
|
1287
1866
|
recordInlineTiming(recording);
|
|
1288
1867
|
};
|
|
1868
|
+
const runStore = (store, callback) => {
|
|
1869
|
+
if (!phaseTimingEnabled) return storage.run(store, callback);
|
|
1870
|
+
const alsStartedAtNs = process.hrtime.bigint();
|
|
1871
|
+
return storage.run(store, () => {
|
|
1872
|
+
addPhase("alsNs", process.hrtime.bigint() - alsStartedAtNs);
|
|
1873
|
+
return callback();
|
|
1874
|
+
});
|
|
1875
|
+
};
|
|
1289
1876
|
const createScope = (metadata) => {
|
|
1290
1877
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1291
1878
|
try {
|
|
@@ -1298,11 +1885,11 @@ var createExecutionRecorder = (options) => {
|
|
|
1298
1885
|
...metadata,
|
|
1299
1886
|
...metadata.request ? { request: { ...metadata.request } } : {}
|
|
1300
1887
|
},
|
|
1301
|
-
|
|
1302
|
-
functions: /* @__PURE__ */ new Map(),
|
|
1888
|
+
journal: void 0,
|
|
1303
1889
|
repeatedCalls: [],
|
|
1304
1890
|
capturedErrors: /* @__PURE__ */ new WeakMap(),
|
|
1305
1891
|
nextCallId: 0,
|
|
1892
|
+
inFlightCalls: 0,
|
|
1306
1893
|
finished: false,
|
|
1307
1894
|
hasError: false,
|
|
1308
1895
|
memory: memoryBudget.startExecution(),
|
|
@@ -1315,7 +1902,7 @@ var createExecutionRecorder = (options) => {
|
|
|
1315
1902
|
return {
|
|
1316
1903
|
run: (callback) => {
|
|
1317
1904
|
const runStartedAtNs = process.hrtime.bigint();
|
|
1318
|
-
return
|
|
1905
|
+
return runStore(store, () => {
|
|
1319
1906
|
addRecorderTime(recording, process.hrtime.bigint() - runStartedAtNs);
|
|
1320
1907
|
return callback();
|
|
1321
1908
|
});
|
|
@@ -1375,132 +1962,145 @@ var createExecutionRecorder = (options) => {
|
|
|
1375
1962
|
const recorderStartedAtNs = process.hrtime.bigint();
|
|
1376
1963
|
if (store.suppressCapture || plan.excluded) {
|
|
1377
1964
|
stats.functionCallsExcluded++;
|
|
1378
|
-
return
|
|
1965
|
+
return runStore({ ...store, suppressCapture: true }, () => {
|
|
1379
1966
|
addRecorderTime(store.recording, process.hrtime.bigint() - recorderStartedAtNs);
|
|
1380
1967
|
return callback();
|
|
1381
1968
|
});
|
|
1382
1969
|
}
|
|
1970
|
+
const recording = store.recording;
|
|
1971
|
+
recording.inFlightCalls++;
|
|
1383
1972
|
const parentCallId = store.currentCallId;
|
|
1384
|
-
const group = repeatedCallGroup(
|
|
1973
|
+
const group = repeatedCallGroup(recording, plan, parentCallId);
|
|
1385
1974
|
group.observedCalls++;
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
}
|
|
1975
|
+
const journal = acquireJournal(recording);
|
|
1976
|
+
if (group.observedCalls === 1) journal?.notePlan(plan.runtimePlanId);
|
|
1389
1977
|
if (group.observedCalls > maxCapturedCallsPerFunction) {
|
|
1390
1978
|
const startedAtNs2 = process.hrtime.bigint();
|
|
1391
1979
|
try {
|
|
1392
1980
|
const result = callback();
|
|
1393
1981
|
if (isPromiseLike(result)) {
|
|
1394
|
-
addRecorderTime(
|
|
1982
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
1395
1983
|
return result.then(
|
|
1396
1984
|
(value) => {
|
|
1397
1985
|
const callbackEndedAtNs2 = process.hrtime.bigint();
|
|
1398
|
-
recordSuppressedCall(
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
plan.functionId,
|
|
1402
|
-
parentCallId,
|
|
1403
|
-
startedAtNs2,
|
|
1404
|
-
callbackEndedAtNs2
|
|
1405
|
-
);
|
|
1406
|
-
addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs2);
|
|
1986
|
+
recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs2);
|
|
1987
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
|
|
1988
|
+
settleInFlight(recording);
|
|
1407
1989
|
return value;
|
|
1408
1990
|
},
|
|
1409
1991
|
(error) => {
|
|
1410
1992
|
const callbackEndedAtNs2 = process.hrtime.bigint();
|
|
1411
|
-
captureCompletedThrow(
|
|
1412
|
-
addRecorderTime(
|
|
1993
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
|
|
1994
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs2);
|
|
1995
|
+
settleInFlight(recording);
|
|
1413
1996
|
throw error;
|
|
1414
1997
|
}
|
|
1415
1998
|
);
|
|
1416
1999
|
}
|
|
1417
2000
|
const callbackEndedAtNs = process.hrtime.bigint();
|
|
1418
|
-
recordSuppressedCall(
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
parentCallId,
|
|
1423
|
-
startedAtNs2,
|
|
1424
|
-
callbackEndedAtNs
|
|
1425
|
-
);
|
|
1426
|
-
addRecorderTime(store.recording, startedAtNs2 - recorderStartedAtNs);
|
|
1427
|
-
addRecorderTime(store.recording, process.hrtime.bigint() - callbackEndedAtNs);
|
|
2001
|
+
recordSuppressedCall(recording, group, parentCallId, startedAtNs2, callbackEndedAtNs);
|
|
2002
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
2003
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
|
|
2004
|
+
settleInFlight(recording);
|
|
1428
2005
|
return result;
|
|
1429
2006
|
} catch (error) {
|
|
1430
2007
|
const callbackEndedAtNs = process.hrtime.bigint();
|
|
1431
|
-
captureCompletedThrow(
|
|
1432
|
-
addRecorderTime(
|
|
1433
|
-
addRecorderTime(
|
|
2008
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs2, error);
|
|
2009
|
+
addRecorderTime(recording, startedAtNs2 - recorderStartedAtNs);
|
|
2010
|
+
addRecorderTime(recording, process.hrtime.bigint() - callbackEndedAtNs);
|
|
2011
|
+
settleInFlight(recording);
|
|
1434
2012
|
throw error;
|
|
1435
2013
|
}
|
|
1436
2014
|
}
|
|
1437
2015
|
const startedAtNs = process.hrtime.bigint();
|
|
1438
|
-
if (!
|
|
2016
|
+
if (!journal) {
|
|
2017
|
+
memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes);
|
|
2018
|
+
return runStore(
|
|
2019
|
+
store,
|
|
2020
|
+
() => observeRecordedCallback(
|
|
2021
|
+
recording,
|
|
2022
|
+
recorderStartedAtNs,
|
|
2023
|
+
callback,
|
|
2024
|
+
() => settleInFlight(recording),
|
|
2025
|
+
(error) => {
|
|
2026
|
+
rememberError(error, recording);
|
|
2027
|
+
settleInFlight(recording);
|
|
2028
|
+
}
|
|
2029
|
+
)
|
|
2030
|
+
);
|
|
2031
|
+
}
|
|
2032
|
+
if (!journal.canStartCall()) {
|
|
1439
2033
|
const captureSuccess = () => {
|
|
1440
|
-
const droppedBefore =
|
|
1441
|
-
|
|
1442
|
-
countDroppedEvents(
|
|
2034
|
+
const droppedBefore = recording.journal?.dropped ?? 0;
|
|
2035
|
+
recording.journal?.dropCall();
|
|
2036
|
+
countDroppedEvents(recording, droppedBefore);
|
|
2037
|
+
settleInFlight(recording);
|
|
1443
2038
|
};
|
|
1444
|
-
return
|
|
2039
|
+
return runStore(
|
|
1445
2040
|
store,
|
|
1446
2041
|
() => observeRecordedCallback(
|
|
1447
|
-
|
|
2042
|
+
recording,
|
|
1448
2043
|
recorderStartedAtNs,
|
|
1449
2044
|
callback,
|
|
1450
2045
|
captureSuccess,
|
|
1451
|
-
(error) =>
|
|
2046
|
+
(error) => {
|
|
2047
|
+
captureCompletedThrow(recording, plan, args, parentCallId, startedAtNs, error);
|
|
2048
|
+
settleInFlight(recording);
|
|
2049
|
+
}
|
|
1452
2050
|
)
|
|
1453
2051
|
);
|
|
1454
2052
|
}
|
|
1455
|
-
if (!memoryBudget.reserveCall(
|
|
2053
|
+
if (!memoryBudget.reserveCall(recording.memory, plan.estimatedCallBytes)) {
|
|
1456
2054
|
return observeRecordedCallback(
|
|
1457
|
-
|
|
2055
|
+
recording,
|
|
1458
2056
|
recorderStartedAtNs,
|
|
1459
2057
|
callback,
|
|
1460
|
-
() =>
|
|
1461
|
-
|
|
1462
|
-
|
|
2058
|
+
() => settleInFlight(recording),
|
|
2059
|
+
(error) => {
|
|
2060
|
+
rememberError(error, recording);
|
|
2061
|
+
settleInFlight(recording);
|
|
2062
|
+
}
|
|
1463
2063
|
);
|
|
1464
2064
|
}
|
|
1465
|
-
const callId = ++
|
|
1466
|
-
const
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
args: Array.from(args, (argument) => captureValue(store.recording, argument)),
|
|
1472
|
-
...parentCallId === void 0 ? {} : { parentCallId }
|
|
1473
|
-
};
|
|
1474
|
-
store.recording.events.startCall(enter);
|
|
1475
|
-
const callStore = { recording: store.recording, currentCallId: callId };
|
|
1476
|
-
return storage.run(
|
|
2065
|
+
const callId = ++recording.nextCallId;
|
|
2066
|
+
const enterTimestampNs = process.hrtime.bigint() - recording.startedAtNs;
|
|
2067
|
+
const capturedArgs = Array.from(args, (argument) => captureValue(recording, argument));
|
|
2068
|
+
journal.startCall(plan.runtimePlanId, callId, parentCallId, enterTimestampNs, capturedArgs);
|
|
2069
|
+
const callStore = { recording, currentCallId: callId };
|
|
2070
|
+
return runStore(
|
|
1477
2071
|
callStore,
|
|
1478
2072
|
() => observeRecordedCallback(
|
|
1479
|
-
|
|
2073
|
+
recording,
|
|
1480
2074
|
recorderStartedAtNs,
|
|
1481
2075
|
callback,
|
|
1482
2076
|
(value) => {
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
}
|
|
1490
|
-
|
|
2077
|
+
if (recording.journal) {
|
|
2078
|
+
const timestampNs = process.hrtime.bigint() - recording.startedAtNs;
|
|
2079
|
+
const durationNs = process.hrtime.bigint() - startedAtNs;
|
|
2080
|
+
const returnValue = captureValue(recording, value);
|
|
2081
|
+
recording.journal.finishCall(KIND_EXIT, callId, timestampNs, durationNs, returnValue);
|
|
2082
|
+
stats.functionCallsCaptured++;
|
|
2083
|
+
}
|
|
2084
|
+
settleInFlight(recording);
|
|
1491
2085
|
},
|
|
1492
2086
|
(error) => {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
2087
|
+
if (!recording.journal) {
|
|
2088
|
+
rememberError(error, recording);
|
|
2089
|
+
settleInFlight(recording);
|
|
2090
|
+
return;
|
|
2091
|
+
}
|
|
2092
|
+
const capturedError = serializedError(recording, error, callId);
|
|
2093
|
+
recording.journal.finishCall(
|
|
2094
|
+
KIND_THROW,
|
|
1496
2095
|
callId,
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
2096
|
+
process.hrtime.bigint() - recording.startedAtNs,
|
|
2097
|
+
process.hrtime.bigint() - startedAtNs,
|
|
2098
|
+
capturedError.value
|
|
2099
|
+
);
|
|
1501
2100
|
stats.functionCallsCaptured++;
|
|
1502
2101
|
capturedError.commit();
|
|
1503
|
-
rememberError(error,
|
|
2102
|
+
rememberError(error, recording);
|
|
2103
|
+
settleInFlight(recording);
|
|
1504
2104
|
}
|
|
1505
2105
|
)
|
|
1506
2106
|
);
|
|
@@ -1527,7 +2127,15 @@ var createExecutionRecorder = (options) => {
|
|
|
1527
2127
|
prepareFunctionPlans,
|
|
1528
2128
|
runPreparedFunction,
|
|
1529
2129
|
trace,
|
|
1530
|
-
getStats: () => ({
|
|
2130
|
+
getStats: () => ({
|
|
2131
|
+
...stats,
|
|
2132
|
+
...memoryBudget.getStats(),
|
|
2133
|
+
...journalPool.stats(),
|
|
2134
|
+
...phases ? {
|
|
2135
|
+
phaseAlsNs: Number(phases.alsNs),
|
|
2136
|
+
phaseMaterializeNs: Number(phases.materializeNs)
|
|
2137
|
+
} : {}
|
|
2138
|
+
})
|
|
1531
2139
|
};
|
|
1532
2140
|
};
|
|
1533
2141
|
|
|
@@ -1644,7 +2252,7 @@ import {
|
|
|
1644
2252
|
|
|
1645
2253
|
// src/sdk-meta.ts
|
|
1646
2254
|
var SDK_NAME = "@rasputin-ai/node";
|
|
1647
|
-
var SDK_VERSION = "0.5.0-alpha.
|
|
2255
|
+
var SDK_VERSION = "0.5.0-alpha.6";
|
|
1648
2256
|
|
|
1649
2257
|
// src/rasputin-init.ts
|
|
1650
2258
|
var withExecution = (client, execution, installRuntime, manifest) => {
|