@autter/runtime-node 1.3.4 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/dist/index.cjs +515 -107
- package/dist/index.d.cts +39 -1
- package/dist/index.d.ts +39 -1
- package/dist/index.js +481 -78
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -17,8 +17,8 @@ var IpWindow = class {
|
|
|
17
17
|
return entry.count <= this.limitPerMinute;
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
-
function firstForwardedFor(
|
|
21
|
-
const raw = Array.isArray(
|
|
20
|
+
function firstForwardedFor(value2) {
|
|
21
|
+
const raw = Array.isArray(value2) ? value2[0] : value2;
|
|
22
22
|
return raw ? (raw.split(",")[0] ?? "").trim() : "";
|
|
23
23
|
}
|
|
24
24
|
var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
|
|
@@ -204,10 +204,10 @@ function createBrowserRelayHandler(opts) {
|
|
|
204
204
|
|
|
205
205
|
// src/server.ts
|
|
206
206
|
import { ServerResponse } from "http";
|
|
207
|
-
import { randomUUID } from "crypto";
|
|
207
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
208
208
|
import {
|
|
209
209
|
context,
|
|
210
|
-
trace,
|
|
210
|
+
trace as trace2,
|
|
211
211
|
SpanKind,
|
|
212
212
|
SpanStatusCode,
|
|
213
213
|
TraceFlags
|
|
@@ -310,13 +310,13 @@ function installAutterAutoFlush(options = {}) {
|
|
|
310
310
|
const signals = options.signals ?? DEFAULT_SIGNALS;
|
|
311
311
|
const flushOnUncaughtException = options.flushOnUncaughtException !== false;
|
|
312
312
|
let disposed = false;
|
|
313
|
-
let
|
|
313
|
+
let inFlight2 = null;
|
|
314
314
|
const doFlush = async () => {
|
|
315
315
|
const targets = options.targets ?? activeFlushTargets();
|
|
316
316
|
if (targets.length === 0) return true;
|
|
317
|
-
let
|
|
317
|
+
let timer2;
|
|
318
318
|
const timedOut = new Promise((resolve) => {
|
|
319
|
-
|
|
319
|
+
timer2 = setTimeout(() => resolve(false), timeoutMs);
|
|
320
320
|
});
|
|
321
321
|
const drained = Promise.allSettled(
|
|
322
322
|
targets.map(
|
|
@@ -329,7 +329,7 @@ function installAutterAutoFlush(options = {}) {
|
|
|
329
329
|
try {
|
|
330
330
|
ok = await Promise.race([drained, timedOut]);
|
|
331
331
|
} finally {
|
|
332
|
-
clearTimeout(
|
|
332
|
+
clearTimeout(timer2);
|
|
333
333
|
}
|
|
334
334
|
if (ok) {
|
|
335
335
|
telemetryStats.markAllFlushed();
|
|
@@ -345,13 +345,13 @@ function installAutterAutoFlush(options = {}) {
|
|
|
345
345
|
};
|
|
346
346
|
const flush = (reason = "exit") => {
|
|
347
347
|
if (disposed) return Promise.resolve(false);
|
|
348
|
-
if (!
|
|
349
|
-
|
|
350
|
-
|
|
348
|
+
if (!inFlight2) {
|
|
349
|
+
inFlight2 = doFlush().finally(() => {
|
|
350
|
+
inFlight2 = null;
|
|
351
351
|
});
|
|
352
352
|
}
|
|
353
353
|
if (isDebugEnabled()) debugLog(`auto-flush requested on ${reason}`);
|
|
354
|
-
return
|
|
354
|
+
return inFlight2;
|
|
355
355
|
};
|
|
356
356
|
const signalCounts = /* @__PURE__ */ new Map();
|
|
357
357
|
let handlingUncaughtException = false;
|
|
@@ -490,8 +490,8 @@ function compile(options) {
|
|
|
490
490
|
scrubEmailValues: options?.scrubEmailValues !== false
|
|
491
491
|
};
|
|
492
492
|
}
|
|
493
|
-
function redactString(
|
|
494
|
-
let out =
|
|
493
|
+
function redactString(value2, r) {
|
|
494
|
+
let out = value2.replace(r.privateKeyBlock, r.mask);
|
|
495
495
|
for (const re of r.valuePatterns) {
|
|
496
496
|
out = out.replace(re, r.mask);
|
|
497
497
|
}
|
|
@@ -509,40 +509,40 @@ function canTraverse(depth, state) {
|
|
|
509
509
|
state.remainingWork -= 1;
|
|
510
510
|
return true;
|
|
511
511
|
}
|
|
512
|
-
function redactValue(
|
|
513
|
-
if (typeof
|
|
512
|
+
function redactValue(value2, r, state, depth) {
|
|
513
|
+
if (typeof value2 === "string") return redactString(value2, r);
|
|
514
514
|
let isArray = false;
|
|
515
515
|
try {
|
|
516
|
-
isArray = Array.isArray(
|
|
516
|
+
isArray = Array.isArray(value2);
|
|
517
517
|
} catch {
|
|
518
518
|
return r.mask;
|
|
519
519
|
}
|
|
520
520
|
if (isArray) {
|
|
521
|
-
return redactArray(
|
|
521
|
+
return redactArray(value2, r, state, depth);
|
|
522
522
|
}
|
|
523
|
-
if (typeof
|
|
524
|
-
return redactObject(
|
|
523
|
+
if (typeof value2 === "object" && value2 !== null) {
|
|
524
|
+
return redactObject(value2, r, state, depth);
|
|
525
525
|
}
|
|
526
|
-
return
|
|
526
|
+
return value2;
|
|
527
527
|
}
|
|
528
|
-
function redactArray(
|
|
529
|
-
const existing = state.ancestors.get(
|
|
528
|
+
function redactArray(value2, r, state, depth) {
|
|
529
|
+
const existing = state.ancestors.get(value2);
|
|
530
530
|
if (existing) return r.mask;
|
|
531
531
|
if (!canTraverse(depth, state)) return r.mask;
|
|
532
532
|
const out = [];
|
|
533
|
-
state.ancestors.set(
|
|
533
|
+
state.ancestors.set(value2, out);
|
|
534
534
|
let length;
|
|
535
535
|
try {
|
|
536
|
-
length =
|
|
536
|
+
length = value2.length;
|
|
537
537
|
} catch {
|
|
538
|
-
state.ancestors.delete(
|
|
538
|
+
state.ancestors.delete(value2);
|
|
539
539
|
return r.mask;
|
|
540
540
|
}
|
|
541
541
|
const limit = Math.min(length, MAX_COLLECTION_ENTRIES);
|
|
542
542
|
for (let i = 0; i < limit; i += 1) {
|
|
543
543
|
let item;
|
|
544
544
|
try {
|
|
545
|
-
item =
|
|
545
|
+
item = value2[i];
|
|
546
546
|
} catch {
|
|
547
547
|
out.push(r.mask);
|
|
548
548
|
continue;
|
|
@@ -552,21 +552,21 @@ function redactArray(value, r, state, depth) {
|
|
|
552
552
|
if (length > limit) {
|
|
553
553
|
out.push(r.mask);
|
|
554
554
|
}
|
|
555
|
-
state.ancestors.delete(
|
|
555
|
+
state.ancestors.delete(value2);
|
|
556
556
|
return out;
|
|
557
557
|
}
|
|
558
|
-
function redactObject(
|
|
559
|
-
const existing = state.ancestors.get(
|
|
558
|
+
function redactObject(value2, r, state, depth) {
|
|
559
|
+
const existing = state.ancestors.get(value2);
|
|
560
560
|
if (existing) return r.mask;
|
|
561
561
|
if (!canTraverse(depth, state)) return r.mask;
|
|
562
562
|
const out = {};
|
|
563
|
-
state.ancestors.set(
|
|
563
|
+
state.ancestors.set(value2, out);
|
|
564
564
|
let count = 0;
|
|
565
565
|
let truncated = false;
|
|
566
566
|
try {
|
|
567
|
-
for (const key in
|
|
567
|
+
for (const key in value2) {
|
|
568
568
|
if (!Object.prototype.propertyIsEnumerable.call(
|
|
569
|
-
|
|
569
|
+
value2,
|
|
570
570
|
key
|
|
571
571
|
)) {
|
|
572
572
|
continue;
|
|
@@ -577,7 +577,7 @@ function redactObject(value, r, state, depth) {
|
|
|
577
577
|
}
|
|
578
578
|
let nestedValue;
|
|
579
579
|
try {
|
|
580
|
-
nestedValue =
|
|
580
|
+
nestedValue = value2[key];
|
|
581
581
|
} catch {
|
|
582
582
|
out[key] = r.mask;
|
|
583
583
|
count += 1;
|
|
@@ -597,7 +597,7 @@ function redactObject(value, r, state, depth) {
|
|
|
597
597
|
if (truncated) {
|
|
598
598
|
out.__redaction_truncated__ = r.mask;
|
|
599
599
|
}
|
|
600
|
-
state.ancestors.delete(
|
|
600
|
+
state.ancestors.delete(value2);
|
|
601
601
|
return out;
|
|
602
602
|
}
|
|
603
603
|
var USAGE_TOKEN_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -614,10 +614,10 @@ var USAGE_TOKEN_KEYS = /* @__PURE__ */ new Set([
|
|
|
614
614
|
"gen_ai.usage.total_tokens",
|
|
615
615
|
"gen_ai.usage.token_count"
|
|
616
616
|
]);
|
|
617
|
-
function isSensitiveKey(key,
|
|
617
|
+
function isSensitiveKey(key, value2, r) {
|
|
618
618
|
const lowered = key.toLowerCase();
|
|
619
619
|
if (USAGE_TOKEN_KEYS.has(lowered)) {
|
|
620
|
-
return !(typeof
|
|
620
|
+
return !(typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0);
|
|
621
621
|
}
|
|
622
622
|
return r.keyPatterns.some((re) => re.test(lowered));
|
|
623
623
|
}
|
|
@@ -646,9 +646,9 @@ function redactWith(attributes, r) {
|
|
|
646
646
|
truncated = true;
|
|
647
647
|
break;
|
|
648
648
|
}
|
|
649
|
-
let
|
|
649
|
+
let value2;
|
|
650
650
|
try {
|
|
651
|
-
|
|
651
|
+
value2 = attributes[key];
|
|
652
652
|
} catch {
|
|
653
653
|
out[key] = r.mask;
|
|
654
654
|
count += 1;
|
|
@@ -657,8 +657,8 @@ function redactWith(attributes, r) {
|
|
|
657
657
|
}
|
|
658
658
|
count += 1;
|
|
659
659
|
state.remainingWork -= 1;
|
|
660
|
-
if (
|
|
661
|
-
out[key] = isSensitiveKey(key,
|
|
660
|
+
if (value2 === void 0) continue;
|
|
661
|
+
out[key] = isSensitiveKey(key, value2, r) ? r.mask : redactValue(value2, r, state, 0);
|
|
662
662
|
}
|
|
663
663
|
} catch {
|
|
664
664
|
truncated = true;
|
|
@@ -721,6 +721,390 @@ function startMemoryMetrics() {
|
|
|
721
721
|
};
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
+
// src/logger.ts
|
|
725
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
726
|
+
import { randomUUID } from "crypto";
|
|
727
|
+
import { trace } from "@opentelemetry/api";
|
|
728
|
+
var local = new AsyncLocalStorage();
|
|
729
|
+
var config = null;
|
|
730
|
+
var queue = [];
|
|
731
|
+
var queueBytes = 0;
|
|
732
|
+
var inFlightBytes = 0;
|
|
733
|
+
var timer;
|
|
734
|
+
var flushing = null;
|
|
735
|
+
var dropped = 0;
|
|
736
|
+
var inFlight = 0;
|
|
737
|
+
var stopping = false;
|
|
738
|
+
var failureStreak = 0;
|
|
739
|
+
var severity = { debug: 5, info: 9, warning: 13, error: 17 };
|
|
740
|
+
function safe(attributes = {}) {
|
|
741
|
+
const redacted = config?.redact(attributes) ?? redactAttributes(attributes);
|
|
742
|
+
let budget = 512;
|
|
743
|
+
let characters = 16384;
|
|
744
|
+
let truncated = false;
|
|
745
|
+
const visit = (input, depth) => {
|
|
746
|
+
if (--budget < 0 || depth > 6) {
|
|
747
|
+
truncated = true;
|
|
748
|
+
return "[truncated]";
|
|
749
|
+
}
|
|
750
|
+
if (typeof input === "string") {
|
|
751
|
+
const text = input.replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/gi, "$1");
|
|
752
|
+
const kept = text.slice(0, Math.max(0, characters));
|
|
753
|
+
truncated ||= kept.length < text.length;
|
|
754
|
+
characters -= kept.length;
|
|
755
|
+
return kept;
|
|
756
|
+
}
|
|
757
|
+
if (typeof input === "number")
|
|
758
|
+
return Number.isFinite(input) ? input : void 0;
|
|
759
|
+
if (typeof input === "boolean" || input === null) return input;
|
|
760
|
+
if (Array.isArray(input)) {
|
|
761
|
+
truncated ||= input.length > 64;
|
|
762
|
+
return input.slice(0, 64).map((item) => visit(item, depth + 1));
|
|
763
|
+
}
|
|
764
|
+
if (input && typeof input === "object") {
|
|
765
|
+
const entries = Object.entries(input);
|
|
766
|
+
if (depth === 0) {
|
|
767
|
+
const priority = (key) => /^autter\.(?:operation|event)\./.test(key) ? 2 : /^exception\./.test(key) ? 1 : 0;
|
|
768
|
+
entries.sort(([a], [b]) => priority(b) - priority(a));
|
|
769
|
+
}
|
|
770
|
+
truncated ||= entries.length > 100;
|
|
771
|
+
return Object.fromEntries(
|
|
772
|
+
entries.slice(0, 100).filter(([key]) => !/^(?:__proto__|constructor|prototype)$/.test(key)).map(([key, item]) => [key.slice(0, 200), visit(item, depth + 1)])
|
|
773
|
+
);
|
|
774
|
+
}
|
|
775
|
+
return void 0;
|
|
776
|
+
};
|
|
777
|
+
const result = visit(redacted, 0);
|
|
778
|
+
if (truncated) result["autter.context.truncated"] = true;
|
|
779
|
+
return result;
|
|
780
|
+
}
|
|
781
|
+
function operationAttributes(state) {
|
|
782
|
+
return state ? {
|
|
783
|
+
"autter.operation.id": state.id,
|
|
784
|
+
"autter.operation.name": state.name,
|
|
785
|
+
...state.parentId ? { "autter.operation.parent_id": state.parentId } : {},
|
|
786
|
+
...state.attributes
|
|
787
|
+
} : {};
|
|
788
|
+
}
|
|
789
|
+
function userAttributes(attributes = {}) {
|
|
790
|
+
return Object.fromEntries(
|
|
791
|
+
Object.entries(safe(attributes)).filter(
|
|
792
|
+
([key]) => !/^autter\.(?:operation|event)\./.test(key)
|
|
793
|
+
)
|
|
794
|
+
);
|
|
795
|
+
}
|
|
796
|
+
function mergeContext(current, next = {}) {
|
|
797
|
+
const merge = (left, right, depth) => {
|
|
798
|
+
const result = { ...left };
|
|
799
|
+
for (const [key, value2] of Object.entries(right)) {
|
|
800
|
+
const prior = result[key];
|
|
801
|
+
result[key] = depth < 6 && value2 && typeof value2 === "object" && !Array.isArray(value2) && prior && typeof prior === "object" && !Array.isArray(prior) ? merge(prior, value2, depth + 1) : value2;
|
|
802
|
+
}
|
|
803
|
+
return result;
|
|
804
|
+
};
|
|
805
|
+
return userAttributes(merge(current, userAttributes(next), 0));
|
|
806
|
+
}
|
|
807
|
+
function traceAttributes(state) {
|
|
808
|
+
return Object.fromEntries(
|
|
809
|
+
Object.entries(operationAttributes(state)).filter(([, item]) => item !== null && item !== void 0).map(([key, item]) => [
|
|
810
|
+
key,
|
|
811
|
+
typeof item === "object" ? JSON.stringify(item) : item
|
|
812
|
+
])
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
function scheduleFlush() {
|
|
816
|
+
if (!timer && config && !stopping && queue.length) {
|
|
817
|
+
timer = setTimeout(
|
|
818
|
+
() => {
|
|
819
|
+
timer = void 0;
|
|
820
|
+
void flushRuntimeLogs().catch(() => {
|
|
821
|
+
});
|
|
822
|
+
},
|
|
823
|
+
Math.min(3e4, 2e3 * 2 ** Math.min(failureStreak, 4))
|
|
824
|
+
);
|
|
825
|
+
timer.unref();
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
function value(input) {
|
|
829
|
+
if (typeof input === "number") return { doubleValue: input };
|
|
830
|
+
if (typeof input === "boolean") return { boolValue: input };
|
|
831
|
+
if (Array.isArray(input))
|
|
832
|
+
return { arrayValue: { values: input.slice(0, 64).map(value) } };
|
|
833
|
+
if (input && typeof input === "object")
|
|
834
|
+
return {
|
|
835
|
+
kvlistValue: {
|
|
836
|
+
values: Object.entries(input).slice(0, 128).map(([key, item]) => ({ key, value: value(item) }))
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
return { stringValue: String(input ?? "").slice(0, 32e3) };
|
|
840
|
+
}
|
|
841
|
+
function emit(level, message, attributes, extra = {}) {
|
|
842
|
+
const state = local.getStore();
|
|
843
|
+
if (state?.sealed) return;
|
|
844
|
+
if (extra["autter.event.type"] !== "operation" && severity[level] < severity[config?.options?.minLevel ?? "debug"])
|
|
845
|
+
return;
|
|
846
|
+
const span = trace.getActiveSpan()?.spanContext();
|
|
847
|
+
const user = mergeContext(state?.attributes ?? {}, attributes);
|
|
848
|
+
const exceptions = Object.fromEntries(
|
|
849
|
+
Object.entries(user).filter(([key]) => key.startsWith("exception."))
|
|
850
|
+
);
|
|
851
|
+
const attrs = safe({
|
|
852
|
+
"autter.event.id": randomUUID(),
|
|
853
|
+
...extra,
|
|
854
|
+
...exceptions,
|
|
855
|
+
...operationAttributes(state),
|
|
856
|
+
...user
|
|
857
|
+
});
|
|
858
|
+
const record = {
|
|
859
|
+
timeUnixNano: String(BigInt(Date.now()) * 1000000n),
|
|
860
|
+
severityNumber: severity[level],
|
|
861
|
+
severityText: level.toUpperCase(),
|
|
862
|
+
body: value(String(safe({ message }).message ?? "").slice(0, 4e3)),
|
|
863
|
+
attributes: Object.entries(attrs).map(([key, item]) => ({
|
|
864
|
+
key,
|
|
865
|
+
value: value(item)
|
|
866
|
+
})),
|
|
867
|
+
...span && /^[a-f0-9]{32}$/.test(span.traceId) && !/^0+$/.test(span.traceId) ? { traceId: span.traceId, spanId: span.spanId } : {}
|
|
868
|
+
};
|
|
869
|
+
if (config?.options?.console !== false)
|
|
870
|
+
console.log(
|
|
871
|
+
JSON.stringify({ ...attrs, level, message: record.body.stringValue })
|
|
872
|
+
);
|
|
873
|
+
if (!config) return;
|
|
874
|
+
if (stopping) {
|
|
875
|
+
dropped++;
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
const bytes = Buffer.byteLength(JSON.stringify(record));
|
|
879
|
+
if (bytes > 256 * 1024 || queue.length + inFlight >= 1e3 || queueBytes + inFlightBytes + bytes > 4 * 1024 * 1024) {
|
|
880
|
+
dropped++;
|
|
881
|
+
console.warn(
|
|
882
|
+
"[autter-runtime] log buffer or record limit reached; record dropped"
|
|
883
|
+
);
|
|
884
|
+
return;
|
|
885
|
+
}
|
|
886
|
+
queue.push({ record, bytes });
|
|
887
|
+
queueBytes += bytes;
|
|
888
|
+
scheduleFlush();
|
|
889
|
+
}
|
|
890
|
+
function configureRuntimeLogger(next) {
|
|
891
|
+
config = next;
|
|
892
|
+
stopping = false;
|
|
893
|
+
failureStreak = 0;
|
|
894
|
+
}
|
|
895
|
+
function runtimeLogStats() {
|
|
896
|
+
return { buffered: queue.length + inFlight, dropped };
|
|
897
|
+
}
|
|
898
|
+
async function flushRuntimeLogs() {
|
|
899
|
+
if (flushing) return flushing;
|
|
900
|
+
if (!config || !queue.length) return;
|
|
901
|
+
if (timer) {
|
|
902
|
+
clearTimeout(timer);
|
|
903
|
+
timer = void 0;
|
|
904
|
+
}
|
|
905
|
+
const activeConfig = config;
|
|
906
|
+
const deadline = Date.now() + 1e4;
|
|
907
|
+
flushing = (async () => {
|
|
908
|
+
const count = queue.length;
|
|
909
|
+
for (let remaining = count; remaining > 0; ) {
|
|
910
|
+
const batch = [];
|
|
911
|
+
inFlightBytes = 0;
|
|
912
|
+
while (batch.length < Math.min(50, remaining) && queue.length) {
|
|
913
|
+
const next = queue[0];
|
|
914
|
+
if (batch.length && inFlightBytes + next.bytes > 512 * 1024) break;
|
|
915
|
+
batch.push(queue.shift());
|
|
916
|
+
inFlightBytes += next.bytes;
|
|
917
|
+
queueBytes -= next.bytes;
|
|
918
|
+
}
|
|
919
|
+
remaining -= batch.length;
|
|
920
|
+
inFlight = batch.length;
|
|
921
|
+
const body = JSON.stringify({
|
|
922
|
+
resourceLogs: [
|
|
923
|
+
{
|
|
924
|
+
resource: {
|
|
925
|
+
attributes: Object.entries({
|
|
926
|
+
"service.name": activeConfig.service,
|
|
927
|
+
"deployment.environment.name": activeConfig.environment,
|
|
928
|
+
...activeConfig.release ? { "service.version": activeConfig.release } : {}
|
|
929
|
+
}).map(([key, item]) => ({ key, value: value(item) }))
|
|
930
|
+
},
|
|
931
|
+
scopeLogs: [
|
|
932
|
+
{
|
|
933
|
+
scope: { name: "autter-runtime" },
|
|
934
|
+
logRecords: batch.map((entry) => entry.record)
|
|
935
|
+
}
|
|
936
|
+
]
|
|
937
|
+
}
|
|
938
|
+
]
|
|
939
|
+
});
|
|
940
|
+
let failure;
|
|
941
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
942
|
+
try {
|
|
943
|
+
if (Date.now() >= deadline)
|
|
944
|
+
throw new Error("Runtime log flush exceeded 10 seconds");
|
|
945
|
+
const response = await fetch(`${activeConfig.endpoint}/v1/logs`, {
|
|
946
|
+
method: "POST",
|
|
947
|
+
headers: {
|
|
948
|
+
"content-type": "application/json",
|
|
949
|
+
authorization: `Bearer ${activeConfig.apiKey}`
|
|
950
|
+
},
|
|
951
|
+
body,
|
|
952
|
+
signal: AbortSignal.timeout(
|
|
953
|
+
Math.max(1, Math.min(3e3, deadline - Date.now()))
|
|
954
|
+
)
|
|
955
|
+
});
|
|
956
|
+
if (!response.ok)
|
|
957
|
+
throw new Error(`Runtime log export failed (${response.status})`);
|
|
958
|
+
failure = void 0;
|
|
959
|
+
break;
|
|
960
|
+
} catch (error) {
|
|
961
|
+
failure = error;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
inFlight = 0;
|
|
965
|
+
if (failure) {
|
|
966
|
+
failureStreak++;
|
|
967
|
+
queue = [...batch, ...queue];
|
|
968
|
+
queueBytes += inFlightBytes;
|
|
969
|
+
inFlightBytes = 0;
|
|
970
|
+
throw failure;
|
|
971
|
+
}
|
|
972
|
+
inFlightBytes = 0;
|
|
973
|
+
failureStreak = 0;
|
|
974
|
+
}
|
|
975
|
+
})().finally(() => {
|
|
976
|
+
flushing = null;
|
|
977
|
+
scheduleFlush();
|
|
978
|
+
});
|
|
979
|
+
return flushing;
|
|
980
|
+
}
|
|
981
|
+
async function shutdownRuntimeLogger() {
|
|
982
|
+
stopping = true;
|
|
983
|
+
try {
|
|
984
|
+
await flushRuntimeLogs();
|
|
985
|
+
} finally {
|
|
986
|
+
if (queue.length) {
|
|
987
|
+
dropped += queue.length;
|
|
988
|
+
console.warn(
|
|
989
|
+
`[autter-runtime] ${queue.length} log records could not be delivered before shutdown`
|
|
990
|
+
);
|
|
991
|
+
}
|
|
992
|
+
queue = [];
|
|
993
|
+
queueBytes = 0;
|
|
994
|
+
config = null;
|
|
995
|
+
if (timer) clearTimeout(timer);
|
|
996
|
+
timer = void 0;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
function createRuntimeLogger(attributes = {}) {
|
|
1000
|
+
const attrs = userAttributes(attributes);
|
|
1001
|
+
return {
|
|
1002
|
+
debug: (message, extra) => emit("debug", message, mergeContext(attrs, extra)),
|
|
1003
|
+
info: (message, extra) => emit("info", message, mergeContext(attrs, extra)),
|
|
1004
|
+
warn: (message, extra) => emit("warning", message, mergeContext(attrs, extra)),
|
|
1005
|
+
error: (error, extra) => emit("error", error instanceof Error ? error.message : String(error), {
|
|
1006
|
+
...attrs,
|
|
1007
|
+
...extra,
|
|
1008
|
+
...error instanceof Error ? {
|
|
1009
|
+
"exception.type": error.name,
|
|
1010
|
+
"exception.stacktrace": error.stack ?? ""
|
|
1011
|
+
} : {}
|
|
1012
|
+
})
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
var runtimeLogger = createRuntimeLogger();
|
|
1016
|
+
function withRuntimeOperation(name, fn, attributes = {}) {
|
|
1017
|
+
const parent = local.getStore();
|
|
1018
|
+
const state = {
|
|
1019
|
+
id: randomUUID(),
|
|
1020
|
+
name: String(safe({ name }).name).slice(0, 200),
|
|
1021
|
+
parentId: parent?.sealed ? void 0 : parent?.id,
|
|
1022
|
+
attributes: mergeContext(
|
|
1023
|
+
parent?.sealed ? {} : parent?.attributes ?? {},
|
|
1024
|
+
attributes
|
|
1025
|
+
),
|
|
1026
|
+
startedAt: Date.now(),
|
|
1027
|
+
outcome: "succeeded",
|
|
1028
|
+
steps: []
|
|
1029
|
+
};
|
|
1030
|
+
const operation = {
|
|
1031
|
+
id: state.id,
|
|
1032
|
+
setContext: (attrs) => {
|
|
1033
|
+
if (!state.sealed) {
|
|
1034
|
+
state.attributes = mergeContext(state.attributes, attrs);
|
|
1035
|
+
trace.getActiveSpan()?.setAttributes(traceAttributes(state));
|
|
1036
|
+
}
|
|
1037
|
+
},
|
|
1038
|
+
outcome: (status, message) => {
|
|
1039
|
+
if (state.sealed) return;
|
|
1040
|
+
state.outcome = status;
|
|
1041
|
+
state.message = message;
|
|
1042
|
+
if (status === "failed")
|
|
1043
|
+
state.reportingStack = new Error("Operation outcome reported here").stack ?? "";
|
|
1044
|
+
},
|
|
1045
|
+
step: async (stepName, stepFn) => {
|
|
1046
|
+
const started = Date.now();
|
|
1047
|
+
let status = "succeeded";
|
|
1048
|
+
try {
|
|
1049
|
+
return await stepFn();
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
status = "failed";
|
|
1052
|
+
throw error;
|
|
1053
|
+
} finally {
|
|
1054
|
+
if (!state.sealed && state.steps.length < 64)
|
|
1055
|
+
state.steps.push({
|
|
1056
|
+
name: String(safe({ name: stepName }).name).slice(0, 200),
|
|
1057
|
+
status,
|
|
1058
|
+
durationMs: Date.now() - started
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
};
|
|
1063
|
+
const run = () => local.run(state, async () => {
|
|
1064
|
+
let thrown;
|
|
1065
|
+
try {
|
|
1066
|
+
return await fn(operation);
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
state.outcome = "failed";
|
|
1069
|
+
thrown = error;
|
|
1070
|
+
throw error;
|
|
1071
|
+
} finally {
|
|
1072
|
+
trace.getActiveSpan()?.setAttributes({
|
|
1073
|
+
...traceAttributes(state),
|
|
1074
|
+
"autter.operation.outcome": state.outcome
|
|
1075
|
+
});
|
|
1076
|
+
if (state.outcome === "failed" && !thrown)
|
|
1077
|
+
config?.reportOutcome(
|
|
1078
|
+
state.name,
|
|
1079
|
+
state.message ?? "Operation failed",
|
|
1080
|
+
{
|
|
1081
|
+
...traceAttributes(state),
|
|
1082
|
+
"autter.outcome.stack": state.reportingStack ?? ""
|
|
1083
|
+
}
|
|
1084
|
+
);
|
|
1085
|
+
emit(
|
|
1086
|
+
state.outcome === "failed" ? "error" : "info",
|
|
1087
|
+
state.message ?? `${state.name}: ${state.outcome}`,
|
|
1088
|
+
{
|
|
1089
|
+
...operationAttributes(state),
|
|
1090
|
+
...thrown instanceof Error ? {
|
|
1091
|
+
"exception.type": thrown.name,
|
|
1092
|
+
"exception.stacktrace": thrown.stack ?? ""
|
|
1093
|
+
} : {}
|
|
1094
|
+
},
|
|
1095
|
+
{
|
|
1096
|
+
"autter.event.type": "operation",
|
|
1097
|
+
"autter.operation.outcome": state.outcome,
|
|
1098
|
+
"autter.operation.duration_ms": Date.now() - state.startedAt,
|
|
1099
|
+
"autter.operation.steps": state.steps
|
|
1100
|
+
}
|
|
1101
|
+
);
|
|
1102
|
+
state.sealed = true;
|
|
1103
|
+
}
|
|
1104
|
+
});
|
|
1105
|
+
return config ? config.run(state.name, run, traceAttributes(state)) : run();
|
|
1106
|
+
}
|
|
1107
|
+
|
|
724
1108
|
// src/server.ts
|
|
725
1109
|
var LLM_MARKER_ATTRIBUTES = [
|
|
726
1110
|
"gen_ai.operation.name",
|
|
@@ -849,7 +1233,7 @@ var ErrorTraceRetentionProcessor = class {
|
|
|
849
1233
|
}
|
|
850
1234
|
/** Promote the active trace, if any — called on captured errors. */
|
|
851
1235
|
retainActiveTrace() {
|
|
852
|
-
const active2 =
|
|
1236
|
+
const active2 = trace2.getActiveSpan()?.spanContext();
|
|
853
1237
|
if (!active2 || (active2.traceFlags & TraceFlags.SAMPLED) !== 0) return;
|
|
854
1238
|
const entry = this.entryFor(active2.traceId);
|
|
855
1239
|
if (entry.retained) return;
|
|
@@ -952,7 +1336,7 @@ async function runLlmSpan(tracer, info, fn) {
|
|
|
952
1336
|
};
|
|
953
1337
|
try {
|
|
954
1338
|
const result = await context.with(
|
|
955
|
-
|
|
1339
|
+
trace2.setSpan(context.active(), span),
|
|
956
1340
|
() => fn(handle)
|
|
957
1341
|
);
|
|
958
1342
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -1001,7 +1385,7 @@ async function runWithSpan(tracer, name, fn, attributes) {
|
|
|
1001
1385
|
const span = tracer.startSpan(name, { attributes });
|
|
1002
1386
|
try {
|
|
1003
1387
|
const result = await context.with(
|
|
1004
|
-
|
|
1388
|
+
trace2.setSpan(context.active(), span),
|
|
1005
1389
|
fn
|
|
1006
1390
|
);
|
|
1007
1391
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -1053,7 +1437,7 @@ function initAutterServer(options) {
|
|
|
1053
1437
|
activeRedactor = makeRedactor(options.redactAttributes ?? true);
|
|
1054
1438
|
const resource = new Resource({
|
|
1055
1439
|
[ATTR_SERVICE_NAME]: options.service,
|
|
1056
|
-
"service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID ||
|
|
1440
|
+
"service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || randomUUID2()).slice(0, 128),
|
|
1057
1441
|
...options.release ? { [ATTR_SERVICE_VERSION]: options.release } : {},
|
|
1058
1442
|
"deployment.environment": environment,
|
|
1059
1443
|
// Tells the ingester request metrics arrive on the metrics pipe, so
|
|
@@ -1140,7 +1524,7 @@ function initAutterServer(options) {
|
|
|
1140
1524
|
const isError = error instanceof Error;
|
|
1141
1525
|
const message = isError ? error.message : String(error);
|
|
1142
1526
|
const redacted = activeRedactor(attributes);
|
|
1143
|
-
const activeSpan =
|
|
1527
|
+
const activeSpan = trace2.getActiveSpan();
|
|
1144
1528
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1145
1529
|
const span = reuseActive ? activeSpan : errorTracer.startSpan(isError ? error.name : "Error");
|
|
1146
1530
|
span.setAttributes({ "autter.severity": "error", ...redacted });
|
|
@@ -1168,20 +1552,20 @@ function initAutterServer(options) {
|
|
|
1168
1552
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
1169
1553
|
if (!reuseActive) span.end();
|
|
1170
1554
|
}
|
|
1171
|
-
function captureMessage2(message,
|
|
1172
|
-
if (
|
|
1555
|
+
function captureMessage2(message, severity2 = "warning", attributes) {
|
|
1556
|
+
if (severity2 === "error" || severity2 === "fatal") {
|
|
1173
1557
|
errorTraceBuffer?.retainActiveTrace();
|
|
1174
1558
|
}
|
|
1175
1559
|
telemetryStats.markCaptured();
|
|
1176
1560
|
const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
|
|
1177
1561
|
const span = errorTracer.startSpan("Message", {
|
|
1178
|
-
attributes: { "autter.severity":
|
|
1562
|
+
attributes: { "autter.severity": severity2, ...activeRedactor(attributes) }
|
|
1179
1563
|
});
|
|
1180
1564
|
span.addEvent("exception", {
|
|
1181
1565
|
"exception.type": "Message",
|
|
1182
1566
|
"exception.message": message,
|
|
1183
1567
|
...stack ? { "exception.stacktrace": stack } : {},
|
|
1184
|
-
"autter.severity":
|
|
1568
|
+
"autter.severity": severity2
|
|
1185
1569
|
});
|
|
1186
1570
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
1187
1571
|
span.end();
|
|
@@ -1189,7 +1573,7 @@ function initAutterServer(options) {
|
|
|
1189
1573
|
function reportOutcome2(name, message, attributes) {
|
|
1190
1574
|
errorTraceBuffer?.retainActiveTrace();
|
|
1191
1575
|
telemetryStats.markCaptured();
|
|
1192
|
-
const activeSpan =
|
|
1576
|
+
const activeSpan = trace2.getActiveSpan();
|
|
1193
1577
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1194
1578
|
const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
|
|
1195
1579
|
const safeOutcome = activeRedactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
@@ -1204,6 +1588,17 @@ function initAutterServer(options) {
|
|
|
1204
1588
|
span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
|
|
1205
1589
|
if (!reuseActive) span.end();
|
|
1206
1590
|
}
|
|
1591
|
+
configureRuntimeLogger({
|
|
1592
|
+
endpoint,
|
|
1593
|
+
apiKey: options.apiKey,
|
|
1594
|
+
service: options.service,
|
|
1595
|
+
environment,
|
|
1596
|
+
release: options.release,
|
|
1597
|
+
options: options.logging,
|
|
1598
|
+
redact: activeRedactor,
|
|
1599
|
+
run: (name, fn, attributes) => runWithSpan(processTracer, name, fn, activeRedactor(attributes)),
|
|
1600
|
+
reportOutcome: reportOutcome2
|
|
1601
|
+
});
|
|
1207
1602
|
if (options.captureGlobalErrors !== false) {
|
|
1208
1603
|
process.on("uncaughtExceptionMonitor", (err) => {
|
|
1209
1604
|
captureException2(err, { "autter.unhandled": true });
|
|
@@ -1214,6 +1609,7 @@ function initAutterServer(options) {
|
|
|
1214
1609
|
const flushTarget = {
|
|
1215
1610
|
forceFlush: async () => {
|
|
1216
1611
|
const results = await Promise.allSettled([
|
|
1612
|
+
flushRuntimeLogs(),
|
|
1217
1613
|
Promise.resolve().then(() => alwaysOnProvider.forceFlush()),
|
|
1218
1614
|
Promise.resolve().then(() => mainSpanProcessor.forceFlush()),
|
|
1219
1615
|
...errorTraceBuffer ? [Promise.resolve().then(() => errorTraceBuffer.forceFlush())] : [],
|
|
@@ -1240,6 +1636,7 @@ function initAutterServer(options) {
|
|
|
1240
1636
|
withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
|
|
1241
1637
|
trackLlmCall: (call) => recordLlmCall(llmTracer, call),
|
|
1242
1638
|
shutdown: async () => {
|
|
1639
|
+
const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
|
|
1243
1640
|
stopMemoryMetrics?.();
|
|
1244
1641
|
active = null;
|
|
1245
1642
|
activeAlwaysOnProvider = null;
|
|
@@ -1248,6 +1645,7 @@ function initAutterServer(options) {
|
|
|
1248
1645
|
unregisterFlushTargets();
|
|
1249
1646
|
telemetryStats.markAllFlushed();
|
|
1250
1647
|
await Promise.allSettled([alwaysOnProvider.shutdown(), sdk.shutdown()]);
|
|
1648
|
+
if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
|
|
1251
1649
|
}
|
|
1252
1650
|
};
|
|
1253
1651
|
active = server;
|
|
@@ -1259,7 +1657,7 @@ function captureException(error, attributes) {
|
|
|
1259
1657
|
active.captureException(error, attributes);
|
|
1260
1658
|
return;
|
|
1261
1659
|
}
|
|
1262
|
-
const span =
|
|
1660
|
+
const span = trace2.getTracer("autter-errors").startSpan(error instanceof Error ? error.name : "Error", { attributes });
|
|
1263
1661
|
if (error instanceof Error) span.recordException(error);
|
|
1264
1662
|
span.setStatus({
|
|
1265
1663
|
code: SpanStatusCode.ERROR,
|
|
@@ -1269,38 +1667,38 @@ function captureException(error, attributes) {
|
|
|
1269
1667
|
}
|
|
1270
1668
|
function withProcessSpan(name, fn, attributes) {
|
|
1271
1669
|
if (active) return active.withProcessSpan(name, fn, attributes);
|
|
1272
|
-
return runWithSpan(
|
|
1670
|
+
return runWithSpan(trace2.getTracer("autter-processes"), name, fn, attributes);
|
|
1273
1671
|
}
|
|
1274
1672
|
function withLlmCall(info, fn) {
|
|
1275
1673
|
if (active) return active.withLlmCall(info, fn);
|
|
1276
|
-
return runLlmSpan(
|
|
1674
|
+
return runLlmSpan(trace2.getTracer("autter-llm"), info, fn);
|
|
1277
1675
|
}
|
|
1278
1676
|
function trackLlmCall(call) {
|
|
1279
1677
|
if (active) {
|
|
1280
1678
|
active.trackLlmCall(call);
|
|
1281
1679
|
return;
|
|
1282
1680
|
}
|
|
1283
|
-
recordLlmCall(
|
|
1681
|
+
recordLlmCall(trace2.getTracer("autter-llm"), call);
|
|
1284
1682
|
}
|
|
1285
|
-
function captureMessage(message,
|
|
1683
|
+
function captureMessage(message, severity2 = "warning", attributes) {
|
|
1286
1684
|
if (active) {
|
|
1287
|
-
active.captureMessage(message,
|
|
1685
|
+
active.captureMessage(message, severity2, attributes);
|
|
1288
1686
|
return;
|
|
1289
1687
|
}
|
|
1290
|
-
const span =
|
|
1291
|
-
attributes: { "autter.severity":
|
|
1688
|
+
const span = trace2.getTracer("autter-errors").startSpan("Message", {
|
|
1689
|
+
attributes: { "autter.severity": severity2, ...attributes }
|
|
1292
1690
|
});
|
|
1293
1691
|
span.addEvent("exception", {
|
|
1294
1692
|
"exception.type": "Message",
|
|
1295
1693
|
"exception.message": message,
|
|
1296
|
-
"autter.severity":
|
|
1694
|
+
"autter.severity": severity2
|
|
1297
1695
|
});
|
|
1298
1696
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
1299
1697
|
span.end();
|
|
1300
1698
|
}
|
|
1301
1699
|
function reportOutcome(name, message, attributes) {
|
|
1302
1700
|
if (active) return active.reportOutcome(name, message, attributes);
|
|
1303
|
-
const span =
|
|
1701
|
+
const span = trace2.getTracer("autter-outcomes").startSpan("OutcomeFailure");
|
|
1304
1702
|
const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
1305
1703
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
1306
1704
|
const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
|
|
@@ -1317,11 +1715,11 @@ function makeSafeCapture(options) {
|
|
|
1317
1715
|
const clean = (attributes) => attributes ? { ...redactAttributes(attributes, options) } : void 0;
|
|
1318
1716
|
return {
|
|
1319
1717
|
captureException: (error, attributes) => captureException(error, clean(attributes)),
|
|
1320
|
-
captureMessage: (message,
|
|
1718
|
+
captureMessage: (message, severity2, attributes) => captureMessage(message, severity2 ?? "warning", clean(attributes))
|
|
1321
1719
|
};
|
|
1322
1720
|
}
|
|
1323
1721
|
function alwaysOnTracer(name) {
|
|
1324
|
-
return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) :
|
|
1722
|
+
return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : trace2.getTracer(name);
|
|
1325
1723
|
}
|
|
1326
1724
|
function autterLlmTracer() {
|
|
1327
1725
|
return alwaysOnTracer("autter-llm");
|
|
@@ -1341,7 +1739,7 @@ async function emitLlmSelftestTrace() {
|
|
|
1341
1739
|
attributes: { "autter.selftest": true }
|
|
1342
1740
|
},
|
|
1343
1741
|
(llm) => {
|
|
1344
|
-
traceId =
|
|
1742
|
+
traceId = trace2.getActiveSpan()?.spanContext().traceId ?? "";
|
|
1345
1743
|
llm.setUsage({ inputTokens: 1, outputTokens: 1 });
|
|
1346
1744
|
llm.setCost(0);
|
|
1347
1745
|
}
|
|
@@ -1459,9 +1857,9 @@ function wrapStream(stream, span) {
|
|
|
1459
1857
|
throw err;
|
|
1460
1858
|
}
|
|
1461
1859
|
},
|
|
1462
|
-
async return(
|
|
1860
|
+
async return(value3) {
|
|
1463
1861
|
finish();
|
|
1464
|
-
return inner.return ? inner.return(
|
|
1862
|
+
return inner.return ? inner.return(value3) : { done: true, value: void 0 };
|
|
1465
1863
|
},
|
|
1466
1864
|
async throw(err) {
|
|
1467
1865
|
finish(err);
|
|
@@ -1471,8 +1869,8 @@ function wrapStream(stream, span) {
|
|
|
1471
1869
|
};
|
|
1472
1870
|
};
|
|
1473
1871
|
}
|
|
1474
|
-
const
|
|
1475
|
-
return typeof
|
|
1872
|
+
const value2 = Reflect.get(target, prop, receiver);
|
|
1873
|
+
return typeof value2 === "function" ? value2.bind(target) : value2;
|
|
1476
1874
|
}
|
|
1477
1875
|
});
|
|
1478
1876
|
}
|
|
@@ -1534,30 +1932,30 @@ function instrumentLlmClient(client, options) {
|
|
|
1534
1932
|
if (cached) return cached;
|
|
1535
1933
|
const proxy = new Proxy(target, {
|
|
1536
1934
|
get(t, prop, receiver) {
|
|
1537
|
-
const
|
|
1538
|
-
if (typeof prop === "symbol") return
|
|
1935
|
+
const value2 = Reflect.get(t, prop, receiver);
|
|
1936
|
+
if (typeof prop === "symbol") return value2;
|
|
1539
1937
|
const propPath = path ? `${path}.${prop}` : prop;
|
|
1540
|
-
if (typeof
|
|
1938
|
+
if (typeof value2 === "function") {
|
|
1541
1939
|
if (CALL_METHODS.has(prop)) {
|
|
1542
1940
|
return (...args) => {
|
|
1543
1941
|
const first = args[0];
|
|
1544
1942
|
if (first && typeof first === "object" && typeof first.model === "string") {
|
|
1545
1943
|
return traceCall(
|
|
1546
|
-
|
|
1944
|
+
value2,
|
|
1547
1945
|
t,
|
|
1548
1946
|
propPath,
|
|
1549
1947
|
args
|
|
1550
1948
|
);
|
|
1551
1949
|
}
|
|
1552
|
-
return
|
|
1950
|
+
return value2.apply(t, args);
|
|
1553
1951
|
};
|
|
1554
1952
|
}
|
|
1555
|
-
return
|
|
1953
|
+
return value2.bind(t);
|
|
1556
1954
|
}
|
|
1557
|
-
if (
|
|
1558
|
-
return deepProxy(
|
|
1955
|
+
if (value2 !== null && typeof value2 === "object" && !(value2 instanceof Promise)) {
|
|
1956
|
+
return deepProxy(value2, propPath);
|
|
1559
1957
|
}
|
|
1560
|
-
return
|
|
1958
|
+
return value2;
|
|
1561
1959
|
}
|
|
1562
1960
|
});
|
|
1563
1961
|
proxied.set(target, proxy);
|
|
@@ -1614,16 +2012,21 @@ export {
|
|
|
1614
2012
|
captureMessage,
|
|
1615
2013
|
createBrowserRelayFetchHandler,
|
|
1616
2014
|
createBrowserRelayHandler,
|
|
2015
|
+
createRuntimeLogger,
|
|
1617
2016
|
emitLlmSelftestTrace,
|
|
2017
|
+
flushRuntimeLogs,
|
|
1618
2018
|
initAutterServer,
|
|
1619
2019
|
installAutterAutoFlush,
|
|
1620
2020
|
instrumentLlmClient,
|
|
1621
2021
|
makeSafeCapture,
|
|
1622
2022
|
redactAttributes,
|
|
1623
2023
|
reportOutcome,
|
|
2024
|
+
runtimeLogStats,
|
|
2025
|
+
runtimeLogger,
|
|
1624
2026
|
sanitizeBrowserPayload,
|
|
1625
2027
|
startCaughtExceptionSampler,
|
|
1626
2028
|
trackLlmCall,
|
|
1627
2029
|
withLlmCall,
|
|
1628
|
-
withProcessSpan
|
|
2030
|
+
withProcessSpan,
|
|
2031
|
+
withRuntimeOperation
|
|
1629
2032
|
};
|