@autter/runtime-node 1.6.0 → 1.6.1
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 +43 -0
- package/dist/{chunk-ARN26OK6.cjs → chunk-4MVWIRBI.cjs} +89 -39
- package/dist/{chunk-FBKYOHU2.js → chunk-5KISVAVB.js} +41 -31
- package/dist/{chunk-UGNPCOIW.cjs → chunk-7OTD2YPT.cjs} +11 -11
- package/dist/{chunk-OY2HTUWY.js → chunk-HRDELHZP.js} +81 -31
- package/dist/{chunk-Y4T7SQMO.js → chunk-L5ENELB2.js} +1 -1
- package/dist/{chunk-UKYTXZOQ.cjs → chunk-UXTIMS3G.cjs} +65 -55
- package/dist/cli.cjs +8 -8
- package/dist/cli.js +2 -2
- package/dist/index.cjs +399 -290
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +215 -106
- package/dist/testing.cjs +8 -8
- package/dist/testing.js +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -45,10 +45,10 @@ import {
|
|
|
45
45
|
splitFingerprint,
|
|
46
46
|
toClientError,
|
|
47
47
|
withRuntimeOperation
|
|
48
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-5KISVAVB.js";
|
|
49
49
|
import {
|
|
50
50
|
runDoctor
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-L5ENELB2.js";
|
|
52
52
|
import {
|
|
53
53
|
COMPAT_MANIFEST,
|
|
54
54
|
CountingExporter,
|
|
@@ -67,9 +67,10 @@ import {
|
|
|
67
67
|
observeIngesterResponse,
|
|
68
68
|
registerFlushTarget,
|
|
69
69
|
setDebugMode,
|
|
70
|
+
sharedSlot,
|
|
70
71
|
telemetryStats,
|
|
71
72
|
unregisterFlushTargets
|
|
72
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-HRDELHZP.js";
|
|
73
74
|
|
|
74
75
|
// src/relay.ts
|
|
75
76
|
var IpWindow = class {
|
|
@@ -478,6 +479,89 @@ import { Resource } from "@opentelemetry/resources";
|
|
|
478
479
|
import {
|
|
479
480
|
AggregationTemporality
|
|
480
481
|
} from "@opentelemetry/sdk-metrics";
|
|
482
|
+
|
|
483
|
+
// src/url-query.ts
|
|
484
|
+
var URL_KEYS = ["http.target", "http.url", "url.full", "url.original", "url.path"];
|
|
485
|
+
var QUERY_KEY = "url.query";
|
|
486
|
+
var NAME_KEYS = ["next.span_name"];
|
|
487
|
+
var MASK = "[redacted]";
|
|
488
|
+
var SCHEME = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
489
|
+
function splitUrl(value) {
|
|
490
|
+
const from = SCHEME.test(value) ? value.indexOf("://") + 3 : 0;
|
|
491
|
+
const question = value.indexOf("?", from);
|
|
492
|
+
const hash = value.indexOf("#", from);
|
|
493
|
+
const at = question < 0 ? hash : hash < 0 ? question : Math.min(question, hash);
|
|
494
|
+
if (at < 0) return null;
|
|
495
|
+
const query = at === question ? value.slice(at + 1, hash > at ? hash : void 0) : null;
|
|
496
|
+
return { base: value.slice(0, at), query };
|
|
497
|
+
}
|
|
498
|
+
function decodeName(raw) {
|
|
499
|
+
try {
|
|
500
|
+
return decodeURIComponent(raw.replace(/\+/g, " "));
|
|
501
|
+
} catch {
|
|
502
|
+
return raw;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
function makeUrlQueryPolicy(keepQueryParams = []) {
|
|
506
|
+
const keep = new Set(keepQueryParams.filter((name) => typeof name === "string"));
|
|
507
|
+
const maskQuery = (query) => {
|
|
508
|
+
const out = [];
|
|
509
|
+
for (const part of query.split("&")) {
|
|
510
|
+
if (!part) continue;
|
|
511
|
+
const eq = part.indexOf("=");
|
|
512
|
+
const name = eq < 0 ? part : part.slice(0, eq);
|
|
513
|
+
if (keep.size && keep.has(decodeName(name))) out.push(part);
|
|
514
|
+
else if (eq < 0) out.push(MASK);
|
|
515
|
+
else out.push(eq === part.length - 1 ? part : `${name}=${MASK}`);
|
|
516
|
+
}
|
|
517
|
+
return out.join("&");
|
|
518
|
+
};
|
|
519
|
+
const stripName = (name) => {
|
|
520
|
+
if (!name.includes("?") && !name.includes("#")) return name;
|
|
521
|
+
return name.split(" ").map((token) => {
|
|
522
|
+
if (!token.startsWith("/") && !SCHEME.test(token)) return token;
|
|
523
|
+
return splitUrl(token)?.base ?? token;
|
|
524
|
+
}).join(" ");
|
|
525
|
+
};
|
|
526
|
+
return {
|
|
527
|
+
attributes(attributes) {
|
|
528
|
+
let out = null;
|
|
529
|
+
const set = (key, value) => {
|
|
530
|
+
out ??= { ...attributes };
|
|
531
|
+
out[key] = value;
|
|
532
|
+
};
|
|
533
|
+
let dropped = null;
|
|
534
|
+
for (const key of URL_KEYS) {
|
|
535
|
+
const value = attributes[key];
|
|
536
|
+
if (typeof value !== "string") continue;
|
|
537
|
+
const split = splitUrl(value);
|
|
538
|
+
if (!split) continue;
|
|
539
|
+
set(key, split.base);
|
|
540
|
+
if (split.query) dropped ??= split.query;
|
|
541
|
+
}
|
|
542
|
+
for (const key of NAME_KEYS) {
|
|
543
|
+
const value = attributes[key];
|
|
544
|
+
if (typeof value !== "string") continue;
|
|
545
|
+
const stripped = stripName(value);
|
|
546
|
+
if (stripped !== value) set(key, stripped);
|
|
547
|
+
}
|
|
548
|
+
const current = attributes[QUERY_KEY];
|
|
549
|
+
if (typeof current === "string") {
|
|
550
|
+
const masked = maskQuery(current.startsWith("?") ? current.slice(1) : current);
|
|
551
|
+
if (masked !== current) set(QUERY_KEY, masked);
|
|
552
|
+
} else if (current !== void 0) {
|
|
553
|
+
set(QUERY_KEY, MASK);
|
|
554
|
+
} else if (dropped !== null) {
|
|
555
|
+
const masked = maskQuery(dropped);
|
|
556
|
+
if (masked) set(QUERY_KEY, masked);
|
|
557
|
+
}
|
|
558
|
+
return out ?? attributes;
|
|
559
|
+
},
|
|
560
|
+
name: stripName
|
|
561
|
+
};
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// src/redact-exporter.ts
|
|
481
565
|
var scrubbedResources = /* @__PURE__ */ new WeakMap();
|
|
482
566
|
function redactResource(resource, redactor) {
|
|
483
567
|
const cached = scrubbedResources.get(resource);
|
|
@@ -486,17 +570,41 @@ function redactResource(resource, redactor) {
|
|
|
486
570
|
scrubbedResources.set(resource, scrubbed);
|
|
487
571
|
return scrubbed;
|
|
488
572
|
}
|
|
489
|
-
|
|
490
|
-
|
|
573
|
+
var DEFAULT_QUERY_POLICY = makeUrlQueryPolicy();
|
|
574
|
+
function stripQueries(span, query) {
|
|
575
|
+
const name = query.name(span.name);
|
|
576
|
+
const attributes = query.attributes(span.attributes);
|
|
577
|
+
if (name === span.name && attributes === span.attributes) return span;
|
|
578
|
+
return wrap(span, { name, attributes });
|
|
579
|
+
}
|
|
580
|
+
function wrap(span, fields) {
|
|
491
581
|
return {
|
|
492
|
-
name:
|
|
582
|
+
name: fields.name,
|
|
493
583
|
kind: span.kind,
|
|
494
584
|
spanContext: () => span.spanContext(),
|
|
495
585
|
parentSpanId: span.parentSpanId,
|
|
496
586
|
startTime: span.startTime,
|
|
497
587
|
endTime: span.endTime,
|
|
588
|
+
status: fields.status ?? span.status,
|
|
589
|
+
attributes: fields.attributes,
|
|
590
|
+
links: fields.links ?? span.links,
|
|
591
|
+
events: fields.events ?? span.events,
|
|
592
|
+
duration: span.duration,
|
|
593
|
+
ended: span.ended,
|
|
594
|
+
resource: fields.resource ?? span.resource,
|
|
595
|
+
instrumentationLibrary: span.instrumentationLibrary,
|
|
596
|
+
droppedAttributesCount: span.droppedAttributesCount,
|
|
597
|
+
droppedEventsCount: span.droppedEventsCount,
|
|
598
|
+
droppedLinksCount: span.droppedLinksCount
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
function redactSpan(span, redactor, query = DEFAULT_QUERY_POLICY) {
|
|
602
|
+
if (!redactor.enabled) return stripQueries(span, query);
|
|
603
|
+
const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
|
|
604
|
+
return wrap(span, {
|
|
605
|
+
name: query.name(redactor.text(span.name)),
|
|
498
606
|
status,
|
|
499
|
-
attributes: redactor.exported(span.attributes),
|
|
607
|
+
attributes: query.attributes(redactor.exported(span.attributes)),
|
|
500
608
|
links: span.links.map(
|
|
501
609
|
(link) => link.attributes ? { ...link, attributes: redactor.exported(link.attributes) } : link
|
|
502
610
|
),
|
|
@@ -505,34 +613,27 @@ function redactSpan(span, redactor) {
|
|
|
505
613
|
name: redactor.text(event.name),
|
|
506
614
|
...event.attributes ? { attributes: redactor.exported(event.attributes) } : {}
|
|
507
615
|
})),
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
resource: redactResource(span.resource, redactor),
|
|
511
|
-
instrumentationLibrary: span.instrumentationLibrary,
|
|
512
|
-
droppedAttributesCount: span.droppedAttributesCount,
|
|
513
|
-
droppedEventsCount: span.droppedEventsCount,
|
|
514
|
-
droppedLinksCount: span.droppedLinksCount
|
|
515
|
-
};
|
|
616
|
+
resource: redactResource(span.resource, redactor)
|
|
617
|
+
});
|
|
516
618
|
}
|
|
517
619
|
var RedactingSpanExporter = class {
|
|
518
|
-
constructor(inner, redactor) {
|
|
620
|
+
constructor(inner, redactor, query = DEFAULT_QUERY_POLICY) {
|
|
519
621
|
this.inner = inner;
|
|
520
622
|
this.redactor = redactor;
|
|
623
|
+
this.query = query;
|
|
521
624
|
}
|
|
522
625
|
inner;
|
|
523
626
|
redactor;
|
|
627
|
+
query;
|
|
524
628
|
export(spans, resultCallback) {
|
|
525
629
|
const redactor = this.redactor();
|
|
526
|
-
|
|
630
|
+
const scrubbed = [];
|
|
527
631
|
let failed = 0;
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
} catch {
|
|
534
|
-
failed++;
|
|
535
|
-
}
|
|
632
|
+
for (const span of spans) {
|
|
633
|
+
try {
|
|
634
|
+
scrubbed.push(redactSpan(span, redactor, this.query));
|
|
635
|
+
} catch {
|
|
636
|
+
failed++;
|
|
536
637
|
}
|
|
537
638
|
}
|
|
538
639
|
if (!failed) {
|
|
@@ -641,7 +742,7 @@ import { context, trace } from "@opentelemetry/api";
|
|
|
641
742
|
import { getRPCMetadata, RPCType } from "@opentelemetry/core";
|
|
642
743
|
var REQUEST_STATE = /* @__PURE__ */ Symbol.for("autter.runtime.request");
|
|
643
744
|
var BOUND = /* @__PURE__ */ Symbol.for("autter.runtime.bound");
|
|
644
|
-
var CAPTURED = /* @__PURE__ */ new WeakSet();
|
|
745
|
+
var CAPTURED = sharedSlot("requests", () => ({ captured: /* @__PURE__ */ new WeakSet() })).captured;
|
|
645
746
|
var capturer = () => {
|
|
646
747
|
};
|
|
647
748
|
function setRequestExceptionCapturer(fn) {
|
|
@@ -667,14 +768,14 @@ function defaultShouldCapture(error) {
|
|
|
667
768
|
return error instanceof RuntimeError || errorCodeOf(error) !== void 0 || responseStatusOf(error) >= 500;
|
|
668
769
|
}
|
|
669
770
|
function onRequestSpan(fn) {
|
|
670
|
-
const
|
|
671
|
-
const metadata = getRPCMetadata(
|
|
771
|
+
const active = context.active();
|
|
772
|
+
const metadata = getRPCMetadata(active);
|
|
672
773
|
const span = metadata?.type === RPCType.HTTP ? metadata.span : void 0;
|
|
673
|
-
if (!span || !span.isRecording() || trace.getSpan(
|
|
774
|
+
if (!span || !span.isRecording() || trace.getSpan(active) === span) {
|
|
674
775
|
fn();
|
|
675
776
|
return;
|
|
676
777
|
}
|
|
677
|
-
context.with(trace.setSpan(
|
|
778
|
+
context.with(trace.setSpan(active, span), fn);
|
|
678
779
|
}
|
|
679
780
|
function captureAtBoundary(error, state, rule = void 0, attributes) {
|
|
680
781
|
let wanted;
|
|
@@ -713,7 +814,7 @@ function bindEmitter(emitter, state) {
|
|
|
713
814
|
if (!target || typeof target !== "object" || target[BOUND]) return;
|
|
714
815
|
target[BOUND] = true;
|
|
715
816
|
const wrappers = /* @__PURE__ */ new WeakMap();
|
|
716
|
-
const
|
|
817
|
+
const wrap2 = (listener) => {
|
|
717
818
|
if (typeof listener !== "function") return listener;
|
|
718
819
|
let wrapped = wrappers.get(listener);
|
|
719
820
|
if (!wrapped) {
|
|
@@ -737,7 +838,7 @@ function bindEmitter(emitter, state) {
|
|
|
737
838
|
const original = target[method];
|
|
738
839
|
if (typeof original !== "function") continue;
|
|
739
840
|
target[method] = function(event, listener) {
|
|
740
|
-
return original.call(this, event,
|
|
841
|
+
return original.call(this, event, wrap2(listener));
|
|
741
842
|
};
|
|
742
843
|
}
|
|
743
844
|
for (const method of ["removeListener", "off"]) {
|
|
@@ -1176,6 +1277,13 @@ function installUnhandledRejectionCapture(capture, mode = unhandledRejectionsMod
|
|
|
1176
1277
|
}
|
|
1177
1278
|
|
|
1178
1279
|
// src/server.ts
|
|
1280
|
+
var S = sharedSlot("server", () => ({
|
|
1281
|
+
active: null,
|
|
1282
|
+
alwaysOnProvider: null,
|
|
1283
|
+
redactor: makeRedactor(true),
|
|
1284
|
+
loggerOnlyCapture: null,
|
|
1285
|
+
hookRequests: false
|
|
1286
|
+
}));
|
|
1179
1287
|
var LLM_MARKER_ATTRIBUTES = [
|
|
1180
1288
|
"gen_ai.operation.name",
|
|
1181
1289
|
"gen_ai.system",
|
|
@@ -1303,9 +1411,9 @@ var ErrorTraceRetentionProcessor = class {
|
|
|
1303
1411
|
}
|
|
1304
1412
|
/** Promote the active trace, if any — called on captured errors. */
|
|
1305
1413
|
retainActiveTrace() {
|
|
1306
|
-
const
|
|
1307
|
-
if (!
|
|
1308
|
-
const entry = this.entryFor(
|
|
1414
|
+
const active = trace2.getActiveSpan()?.spanContext();
|
|
1415
|
+
if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return;
|
|
1416
|
+
const entry = this.entryFor(active.traceId);
|
|
1309
1417
|
if (entry.retained) return;
|
|
1310
1418
|
entry.retained = true;
|
|
1311
1419
|
this.flush(entry);
|
|
@@ -1372,7 +1480,7 @@ function llmBaseAttributes(info) {
|
|
|
1372
1480
|
...info.sessionId ? { "autter.session_id": info.sessionId } : {},
|
|
1373
1481
|
// Caller-supplied extras go through redaction like every other
|
|
1374
1482
|
// custom attribute family (prompts can contain emails/keys).
|
|
1375
|
-
...info.attributes ?
|
|
1483
|
+
...info.attributes ? S.redactor(info.attributes) : {}
|
|
1376
1484
|
};
|
|
1377
1485
|
}
|
|
1378
1486
|
function usageAttributes(usage) {
|
|
@@ -1413,7 +1521,7 @@ async function runLlmSpan(tracer, info, fn) {
|
|
|
1413
1521
|
},
|
|
1414
1522
|
setResponseModel,
|
|
1415
1523
|
setModel: setResponseModel,
|
|
1416
|
-
setAttributes: (attributes) => span.setAttributes(
|
|
1524
|
+
setAttributes: (attributes) => span.setAttributes(S.redactor(attributes))
|
|
1417
1525
|
};
|
|
1418
1526
|
try {
|
|
1419
1527
|
const result = await context2.with(
|
|
@@ -1475,19 +1583,19 @@ async function runWithSpan(tracer, name, fn, attributes, links) {
|
|
|
1475
1583
|
}
|
|
1476
1584
|
function recordError(span, err) {
|
|
1477
1585
|
const isErr = isError(err);
|
|
1478
|
-
const message =
|
|
1586
|
+
const message = S.redactor.text(isErr ? err.message : String(err));
|
|
1479
1587
|
if (isErr) {
|
|
1480
1588
|
span.addEvent("exception", {
|
|
1481
1589
|
"exception.type": err.name,
|
|
1482
1590
|
"exception.message": message,
|
|
1483
|
-
...err.stack ? { "exception.stacktrace":
|
|
1484
|
-
...breadcrumbEventAttributes(
|
|
1591
|
+
...err.stack ? { "exception.stacktrace": S.redactor.text(err.stack) } : {},
|
|
1592
|
+
...breadcrumbEventAttributes(S.redactor.text, err)
|
|
1485
1593
|
});
|
|
1486
1594
|
}
|
|
1487
1595
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
1488
1596
|
}
|
|
1489
1597
|
function redactWithActive(attributes) {
|
|
1490
|
-
return
|
|
1598
|
+
return S.redactor(attributes);
|
|
1491
1599
|
}
|
|
1492
1600
|
function captureExpressRoute(_span, response) {
|
|
1493
1601
|
if (!(response instanceof ServerResponse)) return;
|
|
@@ -1500,42 +1608,41 @@ function captureExpressRoute(_span, response) {
|
|
|
1500
1608
|
};
|
|
1501
1609
|
response.prependListener("finish", setRoute);
|
|
1502
1610
|
response.prependListener("close", setRoute);
|
|
1503
|
-
if (hookRequests) startHookRequest(response);
|
|
1611
|
+
if (S.hookRequests) startHookRequest(response);
|
|
1504
1612
|
}
|
|
1505
|
-
var hookRequests = false;
|
|
1506
1613
|
function structuredErrorAttributes(error) {
|
|
1507
1614
|
const attrs = { ...errorAttributes(error, { causes: false }) };
|
|
1508
1615
|
const internal = errorInternal(error);
|
|
1509
1616
|
if (internal) {
|
|
1510
1617
|
try {
|
|
1511
1618
|
attrs["autter.error.internal"] = JSON.stringify(
|
|
1512
|
-
|
|
1619
|
+
S.redactor(internal)
|
|
1513
1620
|
).slice(0, 4e3);
|
|
1514
1621
|
} catch {
|
|
1515
1622
|
}
|
|
1516
1623
|
}
|
|
1517
1624
|
return attrs;
|
|
1518
1625
|
}
|
|
1519
|
-
var active = null;
|
|
1520
|
-
var activeAlwaysOnProvider = null;
|
|
1521
|
-
var activeRedactor = makeRedactor(true);
|
|
1522
1626
|
function initAutterServer(options) {
|
|
1523
|
-
if (active) return active;
|
|
1627
|
+
if (S.active) return S.active;
|
|
1524
1628
|
const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
|
|
1525
1629
|
/\/$/,
|
|
1526
1630
|
""
|
|
1527
1631
|
);
|
|
1528
1632
|
const headers = { authorization: `Bearer ${options.apiKey}` };
|
|
1633
|
+
const redactor = makeRedactor(options.redactAttributes ?? true);
|
|
1634
|
+
const queryPolicy = makeUrlQueryPolicy(options.keepQueryParams);
|
|
1529
1635
|
const traceExporter = () => new CountingExporter(
|
|
1530
1636
|
new RedactingSpanExporter(
|
|
1531
1637
|
new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }),
|
|
1532
|
-
() =>
|
|
1638
|
+
() => redactor,
|
|
1639
|
+
queryPolicy
|
|
1533
1640
|
)
|
|
1534
1641
|
);
|
|
1535
1642
|
const environment = options.environment ?? process.env.NODE_ENV ?? "production";
|
|
1536
1643
|
if (isDebugEnabled() || options.debug === true) setDebugMode(true);
|
|
1537
1644
|
debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
|
|
1538
|
-
|
|
1645
|
+
S.redactor = redactor;
|
|
1539
1646
|
const distro = options.distro ?? SDK_IDENTITY;
|
|
1540
1647
|
configureCompatCheck({ endpoint, enabled: options.compatCheck !== false, sdk: distro });
|
|
1541
1648
|
const resource = new Resource2({
|
|
@@ -1584,7 +1691,7 @@ function initAutterServer(options) {
|
|
|
1584
1691
|
// 60 s export.
|
|
1585
1692
|
temporalityPreference: AggregationTemporalityPreference.DELTA
|
|
1586
1693
|
}),
|
|
1587
|
-
() =>
|
|
1694
|
+
() => redactor
|
|
1588
1695
|
),
|
|
1589
1696
|
exportIntervalMillis: options.metricIntervalMs ?? 6e4
|
|
1590
1697
|
});
|
|
@@ -1628,12 +1735,12 @@ function initAutterServer(options) {
|
|
|
1628
1735
|
errorTraceBuffer?.retainActiveTrace();
|
|
1629
1736
|
telemetryStats.markCaptured();
|
|
1630
1737
|
const isErr = isError(error);
|
|
1631
|
-
const message =
|
|
1632
|
-
const stackText = isErr && error.stack ?
|
|
1738
|
+
const message = redactor.text(isErr ? error.message : String(error));
|
|
1739
|
+
const stackText = isErr && error.stack ? redactor.text(error.stack) : "";
|
|
1633
1740
|
const split = splitFingerprint(attributes);
|
|
1634
|
-
const fingerprint = fingerprintEventAttributes(split.fingerprint,
|
|
1741
|
+
const fingerprint = fingerprintEventAttributes(split.fingerprint, redactor.text);
|
|
1635
1742
|
if (fingerprint["autter.fingerprint"]) noteCompatFeature("fingerprint_override");
|
|
1636
|
-
const redacted =
|
|
1743
|
+
const redacted = redactor(split.attributes);
|
|
1637
1744
|
const activeSpan = trace2.getActiveSpan();
|
|
1638
1745
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1639
1746
|
const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
|
|
@@ -1660,17 +1767,17 @@ function initAutterServer(options) {
|
|
|
1660
1767
|
"exception.stacktrace": stackText,
|
|
1661
1768
|
...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
|
|
1662
1769
|
...declared,
|
|
1663
|
-
...breadcrumbEventAttributes(
|
|
1770
|
+
...breadcrumbEventAttributes(redactor.text, error)
|
|
1664
1771
|
});
|
|
1665
1772
|
} else {
|
|
1666
1773
|
const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureException")).join("\n");
|
|
1667
1774
|
span.addEvent("exception", {
|
|
1668
1775
|
"exception.type": isErr ? error.name : "Error",
|
|
1669
1776
|
"exception.message": message,
|
|
1670
|
-
...stack ? { "exception.stacktrace":
|
|
1777
|
+
...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
|
|
1671
1778
|
...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
|
|
1672
1779
|
...declared,
|
|
1673
|
-
...breadcrumbEventAttributes(
|
|
1780
|
+
...breadcrumbEventAttributes(redactor.text, error)
|
|
1674
1781
|
});
|
|
1675
1782
|
}
|
|
1676
1783
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
@@ -1682,16 +1789,16 @@ function initAutterServer(options) {
|
|
|
1682
1789
|
}
|
|
1683
1790
|
telemetryStats.markCaptured();
|
|
1684
1791
|
const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
|
|
1685
|
-
const safeMessage =
|
|
1792
|
+
const safeMessage = redactor.text(message);
|
|
1686
1793
|
const span = errorTracer.startSpan("Message", {
|
|
1687
|
-
attributes: { "autter.severity": severity, ...
|
|
1794
|
+
attributes: { "autter.severity": severity, ...redactor(attributes) }
|
|
1688
1795
|
});
|
|
1689
1796
|
span.addEvent("exception", {
|
|
1690
1797
|
"exception.type": "Message",
|
|
1691
1798
|
"exception.message": safeMessage,
|
|
1692
|
-
...stack ? { "exception.stacktrace":
|
|
1799
|
+
...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
|
|
1693
1800
|
"autter.severity": severity,
|
|
1694
|
-
...breadcrumbEventAttributes(
|
|
1801
|
+
...breadcrumbEventAttributes(redactor.text)
|
|
1695
1802
|
});
|
|
1696
1803
|
span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
|
|
1697
1804
|
span.end();
|
|
@@ -1702,11 +1809,11 @@ function initAutterServer(options) {
|
|
|
1702
1809
|
const activeSpan = trace2.getActiveSpan();
|
|
1703
1810
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1704
1811
|
const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
|
|
1705
|
-
const safeOutcome =
|
|
1812
|
+
const safeOutcome = redactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
1706
1813
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
1707
1814
|
const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
|
|
1708
1815
|
span.addEvent("autter.outcome", {
|
|
1709
|
-
...
|
|
1816
|
+
...redactor(attributes),
|
|
1710
1817
|
"autter.outcome.status": "error",
|
|
1711
1818
|
"autter.outcome.name": safeName,
|
|
1712
1819
|
"autter.outcome.message": safeMessage
|
|
@@ -1722,11 +1829,11 @@ function initAutterServer(options) {
|
|
|
1722
1829
|
distro,
|
|
1723
1830
|
release: options.release,
|
|
1724
1831
|
options: options.logging,
|
|
1725
|
-
redact:
|
|
1726
|
-
run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn,
|
|
1832
|
+
redact: redactor,
|
|
1833
|
+
run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, redactor(attributes), links),
|
|
1727
1834
|
reportOutcome: reportOutcome2
|
|
1728
1835
|
});
|
|
1729
|
-
hookRequests = options.logging?.requests === true;
|
|
1836
|
+
S.hookRequests = options.logging?.requests === true;
|
|
1730
1837
|
let onCrash = null;
|
|
1731
1838
|
let uninstallRejections = null;
|
|
1732
1839
|
if (options.captureGlobalErrors !== false) {
|
|
@@ -1769,17 +1876,20 @@ function initAutterServer(options) {
|
|
|
1769
1876
|
captureException: captureException2,
|
|
1770
1877
|
captureMessage: captureMessage2,
|
|
1771
1878
|
reportOutcome: reportOutcome2,
|
|
1772
|
-
withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn,
|
|
1879
|
+
withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn, redactor(attributes)),
|
|
1773
1880
|
withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
|
|
1774
1881
|
trackLlmCall: (call) => recordLlmCall(llmTracer, call),
|
|
1775
1882
|
shutdown: async () => {
|
|
1776
1883
|
const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
|
|
1777
|
-
hookRequests = false;
|
|
1778
1884
|
if (onCrash) process.off("uncaughtExceptionMonitor", onCrash);
|
|
1779
1885
|
uninstallRejections?.();
|
|
1780
1886
|
stopMemoryMetrics?.();
|
|
1781
|
-
active
|
|
1782
|
-
|
|
1887
|
+
if (S.active === server) {
|
|
1888
|
+
S.active = null;
|
|
1889
|
+
S.alwaysOnProvider = null;
|
|
1890
|
+
S.hookRequests = false;
|
|
1891
|
+
S.redactor = makeRedactor(true);
|
|
1892
|
+
}
|
|
1783
1893
|
autoFlushHandle?.dispose();
|
|
1784
1894
|
autoFlushHandle = null;
|
|
1785
1895
|
unregisterFlushTargets();
|
|
@@ -1788,82 +1898,81 @@ function initAutterServer(options) {
|
|
|
1788
1898
|
if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
|
|
1789
1899
|
}
|
|
1790
1900
|
};
|
|
1791
|
-
active = server;
|
|
1792
|
-
|
|
1901
|
+
S.active = server;
|
|
1902
|
+
S.alwaysOnProvider = alwaysOnProvider;
|
|
1793
1903
|
return server;
|
|
1794
1904
|
}
|
|
1795
1905
|
function captureException(error, attributes) {
|
|
1796
|
-
if (active) {
|
|
1797
|
-
active.captureException(error, attributes);
|
|
1906
|
+
if (S.active) {
|
|
1907
|
+
S.active.captureException(error, attributes);
|
|
1798
1908
|
return;
|
|
1799
1909
|
}
|
|
1800
|
-
if (loggerOnlyCapture) {
|
|
1801
|
-
loggerOnlyCapture(error, attributes);
|
|
1910
|
+
if (S.loggerOnlyCapture) {
|
|
1911
|
+
S.loggerOnlyCapture(error, attributes);
|
|
1802
1912
|
return;
|
|
1803
1913
|
}
|
|
1804
1914
|
markCaptured(error);
|
|
1805
1915
|
noteOperationError(error);
|
|
1806
1916
|
const split = splitFingerprint(attributes);
|
|
1807
|
-
const fingerprint = fingerprintEventAttributes(split.fingerprint,
|
|
1917
|
+
const fingerprint = fingerprintEventAttributes(split.fingerprint, S.redactor.text);
|
|
1808
1918
|
notifyException(error, { ...split.attributes, ...fingerprint });
|
|
1809
1919
|
const span = trace2.getTracer("autter-errors").startSpan(isError(error) ? error.name : "Error", {
|
|
1810
|
-
attributes: { ...
|
|
1920
|
+
attributes: { ...S.redactor(split.attributes), ...fingerprint }
|
|
1811
1921
|
});
|
|
1812
1922
|
recordError(span, error);
|
|
1813
1923
|
span.end();
|
|
1814
1924
|
}
|
|
1815
|
-
var loggerOnlyCapture = null;
|
|
1816
1925
|
function setLoggerOnlyCapture(fn) {
|
|
1817
|
-
loggerOnlyCapture = fn;
|
|
1926
|
+
S.loggerOnlyCapture = fn;
|
|
1818
1927
|
}
|
|
1819
1928
|
function serverActive() {
|
|
1820
|
-
return active !== null;
|
|
1929
|
+
return S.active !== null;
|
|
1821
1930
|
}
|
|
1822
1931
|
setRequestExceptionCapturer((error, attributes) => captureException(error, attributes));
|
|
1823
1932
|
setRequestSpanAnnotator((attributes) => {
|
|
1824
1933
|
const span = trace2.getActiveSpan();
|
|
1825
|
-
if (span?.isRecording()) span.setAttributes(
|
|
1934
|
+
if (span?.isRecording()) span.setAttributes(S.redactor(splitFingerprint(attributes).attributes));
|
|
1826
1935
|
});
|
|
1827
1936
|
function withProcessSpan(name, fn, attributes) {
|
|
1828
|
-
if (active) return active.withProcessSpan(name, fn, attributes);
|
|
1937
|
+
if (S.active) return S.active.withProcessSpan(name, fn, attributes);
|
|
1829
1938
|
return runWithSpan(
|
|
1830
1939
|
trace2.getTracer("autter-processes"),
|
|
1831
1940
|
name,
|
|
1832
1941
|
fn,
|
|
1833
|
-
|
|
1942
|
+
S.redactor(attributes)
|
|
1834
1943
|
);
|
|
1835
1944
|
}
|
|
1836
1945
|
function withLlmCall(info, fn) {
|
|
1837
|
-
if (active) return active.withLlmCall(info, fn);
|
|
1946
|
+
if (S.active) return S.active.withLlmCall(info, fn);
|
|
1838
1947
|
return runLlmSpan(trace2.getTracer("autter-llm"), info, fn);
|
|
1839
1948
|
}
|
|
1840
1949
|
function trackLlmCall(call) {
|
|
1841
|
-
if (active) {
|
|
1842
|
-
active.trackLlmCall(call);
|
|
1950
|
+
if (S.active) {
|
|
1951
|
+
S.active.trackLlmCall(call);
|
|
1843
1952
|
return;
|
|
1844
1953
|
}
|
|
1845
1954
|
recordLlmCall(trace2.getTracer("autter-llm"), call);
|
|
1846
1955
|
}
|
|
1847
1956
|
function captureMessage(message, severity = "warning", attributes) {
|
|
1848
|
-
if (active) {
|
|
1849
|
-
active.captureMessage(message, severity, attributes);
|
|
1957
|
+
if (S.active) {
|
|
1958
|
+
S.active.captureMessage(message, severity, attributes);
|
|
1850
1959
|
return;
|
|
1851
1960
|
}
|
|
1852
|
-
const safeMessage =
|
|
1961
|
+
const safeMessage = S.redactor.text(message);
|
|
1853
1962
|
const span = trace2.getTracer("autter-errors").startSpan("Message", {
|
|
1854
|
-
attributes: { "autter.severity": severity, ...
|
|
1963
|
+
attributes: { "autter.severity": severity, ...S.redactor(attributes) }
|
|
1855
1964
|
});
|
|
1856
1965
|
span.addEvent("exception", {
|
|
1857
1966
|
"exception.type": "Message",
|
|
1858
1967
|
"exception.message": safeMessage,
|
|
1859
1968
|
"autter.severity": severity,
|
|
1860
|
-
...breadcrumbEventAttributes(
|
|
1969
|
+
...breadcrumbEventAttributes(S.redactor.text)
|
|
1861
1970
|
});
|
|
1862
1971
|
span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
|
|
1863
1972
|
span.end();
|
|
1864
1973
|
}
|
|
1865
1974
|
function reportOutcome(name, message, attributes) {
|
|
1866
|
-
if (active) return active.reportOutcome(name, message, attributes);
|
|
1975
|
+
if (S.active) return S.active.reportOutcome(name, message, attributes);
|
|
1867
1976
|
const span = trace2.getTracer("autter-outcomes").startSpan("OutcomeFailure");
|
|
1868
1977
|
const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
1869
1978
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
@@ -1885,13 +1994,13 @@ function makeSafeCapture(options) {
|
|
|
1885
1994
|
};
|
|
1886
1995
|
}
|
|
1887
1996
|
function alwaysOnTracer(name) {
|
|
1888
|
-
return
|
|
1997
|
+
return S.alwaysOnProvider ? S.alwaysOnProvider.getTracer(name) : trace2.getTracer(name);
|
|
1889
1998
|
}
|
|
1890
1999
|
function autterLlmTracer() {
|
|
1891
2000
|
return alwaysOnTracer("autter-llm");
|
|
1892
2001
|
}
|
|
1893
2002
|
async function emitLlmSelftestTrace() {
|
|
1894
|
-
const provider =
|
|
2003
|
+
const provider = S.alwaysOnProvider;
|
|
1895
2004
|
if (!provider) {
|
|
1896
2005
|
throw new Error(
|
|
1897
2006
|
"emitLlmSelftestTrace() requires initAutterServer() to have been called"
|
|
@@ -2149,14 +2258,14 @@ function startCaughtExceptionSampler(options = {}) {
|
|
|
2149
2258
|
const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
|
|
2150
2259
|
const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
|
|
2151
2260
|
const session = new inspector.Session();
|
|
2152
|
-
let
|
|
2261
|
+
let active = true;
|
|
2153
2262
|
let minute = 0;
|
|
2154
2263
|
let sent = 0;
|
|
2155
2264
|
session.connect();
|
|
2156
2265
|
session.on("Debugger.paused", (message) => {
|
|
2157
2266
|
session.post("Debugger.resume", () => {
|
|
2158
2267
|
});
|
|
2159
|
-
if (!
|
|
2268
|
+
if (!active || message.params.reason !== "exception") return;
|
|
2160
2269
|
const nowMinute = Math.floor(Date.now() / 6e4);
|
|
2161
2270
|
if (nowMinute !== minute) {
|
|
2162
2271
|
minute = nowMinute;
|
|
@@ -2171,16 +2280,16 @@ function startCaughtExceptionSampler(options = {}) {
|
|
|
2171
2280
|
error.stack = `${error.name}: ${error.message}
|
|
2172
2281
|
${frames.join("\n")}`;
|
|
2173
2282
|
queueMicrotask(() => {
|
|
2174
|
-
if (
|
|
2283
|
+
if (active) captureException(error, { "autter.handled": true, "autter.sampled": true });
|
|
2175
2284
|
});
|
|
2176
2285
|
});
|
|
2177
2286
|
session.post("Debugger.enable", (error) => {
|
|
2178
|
-
if (!error &&
|
|
2287
|
+
if (!error && active) session.post("Debugger.setPauseOnExceptions", { state: "all" }, () => {
|
|
2179
2288
|
});
|
|
2180
2289
|
});
|
|
2181
2290
|
return { stop() {
|
|
2182
|
-
if (!
|
|
2183
|
-
|
|
2291
|
+
if (!active) return;
|
|
2292
|
+
active = false;
|
|
2184
2293
|
session.post("Debugger.setPauseOnExceptions", { state: "none" }, () => {
|
|
2185
2294
|
session.post("Debugger.disable", () => session.disconnect());
|
|
2186
2295
|
});
|
|
@@ -2228,9 +2337,9 @@ import {
|
|
|
2228
2337
|
SpanStatusCode as SpanStatusCode3,
|
|
2229
2338
|
trace as trace3
|
|
2230
2339
|
} from "@opentelemetry/api";
|
|
2231
|
-
var
|
|
2340
|
+
var L = sharedSlot("logging", () => ({ active: null }));
|
|
2232
2341
|
function initAutterLogging(options) {
|
|
2233
|
-
if (
|
|
2342
|
+
if (L.active) return L.active;
|
|
2234
2343
|
if (serverActive()) {
|
|
2235
2344
|
console.warn(
|
|
2236
2345
|
"[autter-runtime] initAutterLogging() ignored: initAutterServer() is already active and includes logging"
|
|
@@ -2332,11 +2441,11 @@ function initAutterLogging(options) {
|
|
|
2332
2441
|
autoFlushHandle?.dispose();
|
|
2333
2442
|
autoFlushHandle = null;
|
|
2334
2443
|
unregisterFlushTargets();
|
|
2335
|
-
|
|
2444
|
+
if (L.active === handle) L.active = null;
|
|
2336
2445
|
await shutdownRuntimeLogger();
|
|
2337
2446
|
}
|
|
2338
2447
|
};
|
|
2339
|
-
|
|
2448
|
+
L.active = handle;
|
|
2340
2449
|
return handle;
|
|
2341
2450
|
}
|
|
2342
2451
|
|