@autter/runtime-node 1.6.0 → 1.7.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 +58 -5
- package/dist/{chunk-ARN26OK6.cjs → chunk-GYTQLITW.cjs} +126 -39
- package/dist/{chunk-UGNPCOIW.cjs → chunk-HKVFURYT.cjs} +11 -11
- package/dist/{chunk-FBKYOHU2.js → chunk-KA4AOZX2.js} +41 -31
- package/dist/{chunk-OY2HTUWY.js → chunk-LG52CW3V.js} +118 -31
- package/dist/{chunk-Y4T7SQMO.js → chunk-QUC6OUE7.js} +1 -1
- package/dist/{chunk-UKYTXZOQ.cjs → chunk-RV4MJNM2.cjs} +65 -55
- package/dist/cli.cjs +8 -8
- package/dist/cli.js +2 -2
- package/dist/index.cjs +465 -295
- package/dist/index.d.cts +15 -2
- package/dist/index.d.ts +15 -2
- package/dist/index.js +284 -114
- 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-KA4AOZX2.js";
|
|
49
49
|
import {
|
|
50
50
|
runDoctor
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-QUC6OUE7.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-LG52CW3V.js";
|
|
73
74
|
|
|
74
75
|
// src/relay.ts
|
|
75
76
|
var IpWindow = class {
|
|
@@ -440,6 +441,9 @@ function createBrowserRelayHandler(opts) {
|
|
|
440
441
|
}
|
|
441
442
|
|
|
442
443
|
// src/server.ts
|
|
444
|
+
import { errorMonitor } from "events";
|
|
445
|
+
import { createRequire } from "module";
|
|
446
|
+
import { join } from "path";
|
|
443
447
|
import { ServerResponse } from "http";
|
|
444
448
|
import { randomUUID } from "crypto";
|
|
445
449
|
import {
|
|
@@ -449,7 +453,7 @@ import {
|
|
|
449
453
|
SpanStatusCode,
|
|
450
454
|
TraceFlags
|
|
451
455
|
} from "@opentelemetry/api";
|
|
452
|
-
import { getRPCMetadata as
|
|
456
|
+
import { getRPCMetadata as getRPCMetadata3, RPCType as RPCType3 } from "@opentelemetry/core";
|
|
453
457
|
import {
|
|
454
458
|
AggregationTemporalityPreference,
|
|
455
459
|
OTLPMetricExporter
|
|
@@ -478,6 +482,89 @@ import { Resource } from "@opentelemetry/resources";
|
|
|
478
482
|
import {
|
|
479
483
|
AggregationTemporality
|
|
480
484
|
} from "@opentelemetry/sdk-metrics";
|
|
485
|
+
|
|
486
|
+
// src/url-query.ts
|
|
487
|
+
var URL_KEYS = ["http.target", "http.url", "url.full", "url.original", "url.path"];
|
|
488
|
+
var QUERY_KEY = "url.query";
|
|
489
|
+
var NAME_KEYS = ["next.span_name"];
|
|
490
|
+
var MASK = "[redacted]";
|
|
491
|
+
var SCHEME = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
492
|
+
function splitUrl(value) {
|
|
493
|
+
const from = SCHEME.test(value) ? value.indexOf("://") + 3 : 0;
|
|
494
|
+
const question = value.indexOf("?", from);
|
|
495
|
+
const hash = value.indexOf("#", from);
|
|
496
|
+
const at = question < 0 ? hash : hash < 0 ? question : Math.min(question, hash);
|
|
497
|
+
if (at < 0) return null;
|
|
498
|
+
const query = at === question ? value.slice(at + 1, hash > at ? hash : void 0) : null;
|
|
499
|
+
return { base: value.slice(0, at), query };
|
|
500
|
+
}
|
|
501
|
+
function decodeName(raw) {
|
|
502
|
+
try {
|
|
503
|
+
return decodeURIComponent(raw.replace(/\+/g, " "));
|
|
504
|
+
} catch {
|
|
505
|
+
return raw;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
function makeUrlQueryPolicy(keepQueryParams = []) {
|
|
509
|
+
const keep = new Set(keepQueryParams.filter((name) => typeof name === "string"));
|
|
510
|
+
const maskQuery = (query) => {
|
|
511
|
+
const out = [];
|
|
512
|
+
for (const part of query.split("&")) {
|
|
513
|
+
if (!part) continue;
|
|
514
|
+
const eq = part.indexOf("=");
|
|
515
|
+
const name = eq < 0 ? part : part.slice(0, eq);
|
|
516
|
+
if (keep.size && keep.has(decodeName(name))) out.push(part);
|
|
517
|
+
else if (eq < 0) out.push(MASK);
|
|
518
|
+
else out.push(eq === part.length - 1 ? part : `${name}=${MASK}`);
|
|
519
|
+
}
|
|
520
|
+
return out.join("&");
|
|
521
|
+
};
|
|
522
|
+
const stripName = (name) => {
|
|
523
|
+
if (!name.includes("?") && !name.includes("#")) return name;
|
|
524
|
+
return name.split(" ").map((token) => {
|
|
525
|
+
if (!token.startsWith("/") && !SCHEME.test(token)) return token;
|
|
526
|
+
return splitUrl(token)?.base ?? token;
|
|
527
|
+
}).join(" ");
|
|
528
|
+
};
|
|
529
|
+
return {
|
|
530
|
+
attributes(attributes) {
|
|
531
|
+
let out = null;
|
|
532
|
+
const set = (key, value) => {
|
|
533
|
+
out ??= { ...attributes };
|
|
534
|
+
out[key] = value;
|
|
535
|
+
};
|
|
536
|
+
let dropped = null;
|
|
537
|
+
for (const key of URL_KEYS) {
|
|
538
|
+
const value = attributes[key];
|
|
539
|
+
if (typeof value !== "string") continue;
|
|
540
|
+
const split = splitUrl(value);
|
|
541
|
+
if (!split) continue;
|
|
542
|
+
set(key, split.base);
|
|
543
|
+
if (split.query) dropped ??= split.query;
|
|
544
|
+
}
|
|
545
|
+
for (const key of NAME_KEYS) {
|
|
546
|
+
const value = attributes[key];
|
|
547
|
+
if (typeof value !== "string") continue;
|
|
548
|
+
const stripped = stripName(value);
|
|
549
|
+
if (stripped !== value) set(key, stripped);
|
|
550
|
+
}
|
|
551
|
+
const current = attributes[QUERY_KEY];
|
|
552
|
+
if (typeof current === "string") {
|
|
553
|
+
const masked = maskQuery(current.startsWith("?") ? current.slice(1) : current);
|
|
554
|
+
if (masked !== current) set(QUERY_KEY, masked);
|
|
555
|
+
} else if (current !== void 0) {
|
|
556
|
+
set(QUERY_KEY, MASK);
|
|
557
|
+
} else if (dropped !== null) {
|
|
558
|
+
const masked = maskQuery(dropped);
|
|
559
|
+
if (masked) set(QUERY_KEY, masked);
|
|
560
|
+
}
|
|
561
|
+
return out ?? attributes;
|
|
562
|
+
},
|
|
563
|
+
name: stripName
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// src/redact-exporter.ts
|
|
481
568
|
var scrubbedResources = /* @__PURE__ */ new WeakMap();
|
|
482
569
|
function redactResource(resource, redactor) {
|
|
483
570
|
const cached = scrubbedResources.get(resource);
|
|
@@ -486,17 +573,41 @@ function redactResource(resource, redactor) {
|
|
|
486
573
|
scrubbedResources.set(resource, scrubbed);
|
|
487
574
|
return scrubbed;
|
|
488
575
|
}
|
|
489
|
-
|
|
490
|
-
|
|
576
|
+
var DEFAULT_QUERY_POLICY = makeUrlQueryPolicy();
|
|
577
|
+
function stripQueries(span, query) {
|
|
578
|
+
const name = query.name(span.name);
|
|
579
|
+
const attributes = query.attributes(span.attributes);
|
|
580
|
+
if (name === span.name && attributes === span.attributes) return span;
|
|
581
|
+
return wrap(span, { name, attributes });
|
|
582
|
+
}
|
|
583
|
+
function wrap(span, fields) {
|
|
491
584
|
return {
|
|
492
|
-
name:
|
|
585
|
+
name: fields.name,
|
|
493
586
|
kind: span.kind,
|
|
494
587
|
spanContext: () => span.spanContext(),
|
|
495
588
|
parentSpanId: span.parentSpanId,
|
|
496
589
|
startTime: span.startTime,
|
|
497
590
|
endTime: span.endTime,
|
|
591
|
+
status: fields.status ?? span.status,
|
|
592
|
+
attributes: fields.attributes,
|
|
593
|
+
links: fields.links ?? span.links,
|
|
594
|
+
events: fields.events ?? span.events,
|
|
595
|
+
duration: span.duration,
|
|
596
|
+
ended: span.ended,
|
|
597
|
+
resource: fields.resource ?? span.resource,
|
|
598
|
+
instrumentationLibrary: span.instrumentationLibrary,
|
|
599
|
+
droppedAttributesCount: span.droppedAttributesCount,
|
|
600
|
+
droppedEventsCount: span.droppedEventsCount,
|
|
601
|
+
droppedLinksCount: span.droppedLinksCount
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function redactSpan(span, redactor, query = DEFAULT_QUERY_POLICY) {
|
|
605
|
+
if (!redactor.enabled) return stripQueries(span, query);
|
|
606
|
+
const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
|
|
607
|
+
return wrap(span, {
|
|
608
|
+
name: query.name(redactor.text(span.name)),
|
|
498
609
|
status,
|
|
499
|
-
attributes: redactor.exported(span.attributes),
|
|
610
|
+
attributes: query.attributes(redactor.exported(span.attributes)),
|
|
500
611
|
links: span.links.map(
|
|
501
612
|
(link) => link.attributes ? { ...link, attributes: redactor.exported(link.attributes) } : link
|
|
502
613
|
),
|
|
@@ -505,34 +616,27 @@ function redactSpan(span, redactor) {
|
|
|
505
616
|
name: redactor.text(event.name),
|
|
506
617
|
...event.attributes ? { attributes: redactor.exported(event.attributes) } : {}
|
|
507
618
|
})),
|
|
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
|
-
};
|
|
619
|
+
resource: redactResource(span.resource, redactor)
|
|
620
|
+
});
|
|
516
621
|
}
|
|
517
622
|
var RedactingSpanExporter = class {
|
|
518
|
-
constructor(inner, redactor) {
|
|
623
|
+
constructor(inner, redactor, query = DEFAULT_QUERY_POLICY) {
|
|
519
624
|
this.inner = inner;
|
|
520
625
|
this.redactor = redactor;
|
|
626
|
+
this.query = query;
|
|
521
627
|
}
|
|
522
628
|
inner;
|
|
523
629
|
redactor;
|
|
630
|
+
query;
|
|
524
631
|
export(spans, resultCallback) {
|
|
525
632
|
const redactor = this.redactor();
|
|
526
|
-
|
|
633
|
+
const scrubbed = [];
|
|
527
634
|
let failed = 0;
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
} catch {
|
|
534
|
-
failed++;
|
|
535
|
-
}
|
|
635
|
+
for (const span of spans) {
|
|
636
|
+
try {
|
|
637
|
+
scrubbed.push(redactSpan(span, redactor, this.query));
|
|
638
|
+
} catch {
|
|
639
|
+
failed++;
|
|
536
640
|
}
|
|
537
641
|
}
|
|
538
642
|
if (!failed) {
|
|
@@ -641,7 +745,7 @@ import { context, trace } from "@opentelemetry/api";
|
|
|
641
745
|
import { getRPCMetadata, RPCType } from "@opentelemetry/core";
|
|
642
746
|
var REQUEST_STATE = /* @__PURE__ */ Symbol.for("autter.runtime.request");
|
|
643
747
|
var BOUND = /* @__PURE__ */ Symbol.for("autter.runtime.bound");
|
|
644
|
-
var CAPTURED = /* @__PURE__ */ new WeakSet();
|
|
748
|
+
var CAPTURED = sharedSlot("requests", () => ({ captured: /* @__PURE__ */ new WeakSet() })).captured;
|
|
645
749
|
var capturer = () => {
|
|
646
750
|
};
|
|
647
751
|
function setRequestExceptionCapturer(fn) {
|
|
@@ -667,14 +771,14 @@ function defaultShouldCapture(error) {
|
|
|
667
771
|
return error instanceof RuntimeError || errorCodeOf(error) !== void 0 || responseStatusOf(error) >= 500;
|
|
668
772
|
}
|
|
669
773
|
function onRequestSpan(fn) {
|
|
670
|
-
const
|
|
671
|
-
const metadata = getRPCMetadata(
|
|
774
|
+
const active = context.active();
|
|
775
|
+
const metadata = getRPCMetadata(active);
|
|
672
776
|
const span = metadata?.type === RPCType.HTTP ? metadata.span : void 0;
|
|
673
|
-
if (!span || !span.isRecording() || trace.getSpan(
|
|
777
|
+
if (!span || !span.isRecording() || trace.getSpan(active) === span) {
|
|
674
778
|
fn();
|
|
675
779
|
return;
|
|
676
780
|
}
|
|
677
|
-
context.with(trace.setSpan(
|
|
781
|
+
context.with(trace.setSpan(active, span), fn);
|
|
678
782
|
}
|
|
679
783
|
function captureAtBoundary(error, state, rule = void 0, attributes) {
|
|
680
784
|
let wanted;
|
|
@@ -713,7 +817,7 @@ function bindEmitter(emitter, state) {
|
|
|
713
817
|
if (!target || typeof target !== "object" || target[BOUND]) return;
|
|
714
818
|
target[BOUND] = true;
|
|
715
819
|
const wrappers = /* @__PURE__ */ new WeakMap();
|
|
716
|
-
const
|
|
820
|
+
const wrap2 = (listener) => {
|
|
717
821
|
if (typeof listener !== "function") return listener;
|
|
718
822
|
let wrapped = wrappers.get(listener);
|
|
719
823
|
if (!wrapped) {
|
|
@@ -737,7 +841,7 @@ function bindEmitter(emitter, state) {
|
|
|
737
841
|
const original = target[method];
|
|
738
842
|
if (typeof original !== "function") continue;
|
|
739
843
|
target[method] = function(event, listener) {
|
|
740
|
-
return original.call(this, event,
|
|
844
|
+
return original.call(this, event, wrap2(listener));
|
|
741
845
|
};
|
|
742
846
|
}
|
|
743
847
|
for (const method of ["removeListener", "off"]) {
|
|
@@ -1175,7 +1279,48 @@ function installUnhandledRejectionCapture(capture, mode = unhandledRejectionsMod
|
|
|
1175
1279
|
};
|
|
1176
1280
|
}
|
|
1177
1281
|
|
|
1282
|
+
// src/route-label.ts
|
|
1283
|
+
import { getRPCMetadata as getRPCMetadata2, RPCType as RPCType2 } from "@opentelemetry/core";
|
|
1284
|
+
var ours = /* @__PURE__ */ new WeakMap();
|
|
1285
|
+
var RAW_PATH_SPAN_TYPES = /* @__PURE__ */ new Set(["BaseServer.renderToResponse"]);
|
|
1286
|
+
function noteFrameworkRoute(parent, attributes) {
|
|
1287
|
+
const route = attributes?.["next.route"];
|
|
1288
|
+
if (typeof route !== "string" || !route.startsWith("/")) return;
|
|
1289
|
+
if (RAW_PATH_SPAN_TYPES.has(String(attributes?.["next.span_type"] ?? ""))) return;
|
|
1290
|
+
const rpc = getRPCMetadata2(parent);
|
|
1291
|
+
if (!rpc || rpc.type !== RPCType2.HTTP) return;
|
|
1292
|
+
const mine = ours.get(rpc);
|
|
1293
|
+
if (rpc.route !== void 0 && rpc.route !== mine) return;
|
|
1294
|
+
if (mine !== void 0 && mine.includes("[") && !route.includes("[")) return;
|
|
1295
|
+
if (mine !== void 0 && (route === `${mine}/route` || route === `${mine}/page`)) return;
|
|
1296
|
+
rpc.route = route;
|
|
1297
|
+
ours.set(rpc, route);
|
|
1298
|
+
}
|
|
1299
|
+
var RouteLabelSampler = class {
|
|
1300
|
+
constructor(delegate) {
|
|
1301
|
+
this.delegate = delegate;
|
|
1302
|
+
}
|
|
1303
|
+
delegate;
|
|
1304
|
+
shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
|
|
1305
|
+
try {
|
|
1306
|
+
noteFrameworkRoute(ctx, attributes);
|
|
1307
|
+
} catch {
|
|
1308
|
+
}
|
|
1309
|
+
return this.delegate.shouldSample(ctx, traceId, spanName, spanKind, attributes, links);
|
|
1310
|
+
}
|
|
1311
|
+
toString() {
|
|
1312
|
+
return `RouteLabel(${this.delegate.toString()})`;
|
|
1313
|
+
}
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1178
1316
|
// src/server.ts
|
|
1317
|
+
var S = sharedSlot("server", () => ({
|
|
1318
|
+
active: null,
|
|
1319
|
+
alwaysOnProvider: null,
|
|
1320
|
+
redactor: makeRedactor(true),
|
|
1321
|
+
loggerOnlyCapture: null,
|
|
1322
|
+
hookRequests: false
|
|
1323
|
+
}));
|
|
1179
1324
|
var LLM_MARKER_ATTRIBUTES = [
|
|
1180
1325
|
"gen_ai.operation.name",
|
|
1181
1326
|
"gen_ai.system",
|
|
@@ -1303,9 +1448,9 @@ var ErrorTraceRetentionProcessor = class {
|
|
|
1303
1448
|
}
|
|
1304
1449
|
/** Promote the active trace, if any — called on captured errors. */
|
|
1305
1450
|
retainActiveTrace() {
|
|
1306
|
-
const
|
|
1307
|
-
if (!
|
|
1308
|
-
const entry = this.entryFor(
|
|
1451
|
+
const active = trace2.getActiveSpan()?.spanContext();
|
|
1452
|
+
if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return;
|
|
1453
|
+
const entry = this.entryFor(active.traceId);
|
|
1309
1454
|
if (entry.retained) return;
|
|
1310
1455
|
entry.retained = true;
|
|
1311
1456
|
this.flush(entry);
|
|
@@ -1372,7 +1517,7 @@ function llmBaseAttributes(info) {
|
|
|
1372
1517
|
...info.sessionId ? { "autter.session_id": info.sessionId } : {},
|
|
1373
1518
|
// Caller-supplied extras go through redaction like every other
|
|
1374
1519
|
// custom attribute family (prompts can contain emails/keys).
|
|
1375
|
-
...info.attributes ?
|
|
1520
|
+
...info.attributes ? S.redactor(info.attributes) : {}
|
|
1376
1521
|
};
|
|
1377
1522
|
}
|
|
1378
1523
|
function usageAttributes(usage) {
|
|
@@ -1413,7 +1558,7 @@ async function runLlmSpan(tracer, info, fn) {
|
|
|
1413
1558
|
},
|
|
1414
1559
|
setResponseModel,
|
|
1415
1560
|
setModel: setResponseModel,
|
|
1416
|
-
setAttributes: (attributes) => span.setAttributes(
|
|
1561
|
+
setAttributes: (attributes) => span.setAttributes(S.redactor(attributes))
|
|
1417
1562
|
};
|
|
1418
1563
|
try {
|
|
1419
1564
|
const result = await context2.with(
|
|
@@ -1475,67 +1620,82 @@ async function runWithSpan(tracer, name, fn, attributes, links) {
|
|
|
1475
1620
|
}
|
|
1476
1621
|
function recordError(span, err) {
|
|
1477
1622
|
const isErr = isError(err);
|
|
1478
|
-
const message =
|
|
1623
|
+
const message = S.redactor.text(isErr ? err.message : String(err));
|
|
1479
1624
|
if (isErr) {
|
|
1480
1625
|
span.addEvent("exception", {
|
|
1481
1626
|
"exception.type": err.name,
|
|
1482
1627
|
"exception.message": message,
|
|
1483
|
-
...err.stack ? { "exception.stacktrace":
|
|
1484
|
-
...breadcrumbEventAttributes(
|
|
1628
|
+
...err.stack ? { "exception.stacktrace": S.redactor.text(err.stack) } : {},
|
|
1629
|
+
...breadcrumbEventAttributes(S.redactor.text, err)
|
|
1485
1630
|
});
|
|
1486
1631
|
}
|
|
1487
1632
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
1488
1633
|
}
|
|
1489
1634
|
function redactWithActive(attributes) {
|
|
1490
|
-
return
|
|
1635
|
+
return S.redactor(attributes);
|
|
1491
1636
|
}
|
|
1492
|
-
function
|
|
1637
|
+
function patchLoadedHttpModules() {
|
|
1638
|
+
try {
|
|
1639
|
+
const load = createRequire(join(process.cwd(), "autter-runtime-http.cjs"));
|
|
1640
|
+
load("http");
|
|
1641
|
+
load("https");
|
|
1642
|
+
} catch {
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1645
|
+
var METRIC_ROUTE_ATTR = "autter.metric_has_route";
|
|
1646
|
+
function captureRequestRoute(span, response) {
|
|
1493
1647
|
if (!(response instanceof ServerResponse)) return;
|
|
1494
|
-
const rpcMetadata =
|
|
1495
|
-
if (rpcMetadata?.type !==
|
|
1648
|
+
const rpcMetadata = getRPCMetadata3(context2.active());
|
|
1649
|
+
if (rpcMetadata?.type !== RPCType3.HTTP) return;
|
|
1650
|
+
let failed = false;
|
|
1651
|
+
response.on(errorMonitor, () => {
|
|
1652
|
+
failed = true;
|
|
1653
|
+
});
|
|
1496
1654
|
const setRoute = () => {
|
|
1497
1655
|
if (rpcMetadata.route) return;
|
|
1498
1656
|
const route = expressRouteOf(response.req);
|
|
1499
1657
|
if (route) rpcMetadata.route = route;
|
|
1500
1658
|
};
|
|
1501
1659
|
response.prependListener("finish", setRoute);
|
|
1502
|
-
response.prependListener("close",
|
|
1503
|
-
|
|
1660
|
+
response.prependListener("close", () => {
|
|
1661
|
+
setRoute();
|
|
1662
|
+
if (rpcMetadata.route && !failed) span.setAttribute(METRIC_ROUTE_ATTR, true);
|
|
1663
|
+
});
|
|
1664
|
+
if (S.hookRequests) startHookRequest(response);
|
|
1504
1665
|
}
|
|
1505
|
-
var hookRequests = false;
|
|
1506
1666
|
function structuredErrorAttributes(error) {
|
|
1507
1667
|
const attrs = { ...errorAttributes(error, { causes: false }) };
|
|
1508
1668
|
const internal = errorInternal(error);
|
|
1509
1669
|
if (internal) {
|
|
1510
1670
|
try {
|
|
1511
1671
|
attrs["autter.error.internal"] = JSON.stringify(
|
|
1512
|
-
|
|
1672
|
+
S.redactor(internal)
|
|
1513
1673
|
).slice(0, 4e3);
|
|
1514
1674
|
} catch {
|
|
1515
1675
|
}
|
|
1516
1676
|
}
|
|
1517
1677
|
return attrs;
|
|
1518
1678
|
}
|
|
1519
|
-
var active = null;
|
|
1520
|
-
var activeAlwaysOnProvider = null;
|
|
1521
|
-
var activeRedactor = makeRedactor(true);
|
|
1522
1679
|
function initAutterServer(options) {
|
|
1523
|
-
if (active) return active;
|
|
1680
|
+
if (S.active) return S.active;
|
|
1524
1681
|
const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
|
|
1525
1682
|
/\/$/,
|
|
1526
1683
|
""
|
|
1527
1684
|
);
|
|
1528
1685
|
const headers = { authorization: `Bearer ${options.apiKey}` };
|
|
1686
|
+
const redactor = makeRedactor(options.redactAttributes ?? true);
|
|
1687
|
+
const queryPolicy = makeUrlQueryPolicy(options.keepQueryParams);
|
|
1529
1688
|
const traceExporter = () => new CountingExporter(
|
|
1530
1689
|
new RedactingSpanExporter(
|
|
1531
1690
|
new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }),
|
|
1532
|
-
() =>
|
|
1691
|
+
() => redactor,
|
|
1692
|
+
queryPolicy
|
|
1533
1693
|
)
|
|
1534
1694
|
);
|
|
1535
1695
|
const environment = options.environment ?? process.env.NODE_ENV ?? "production";
|
|
1536
1696
|
if (isDebugEnabled() || options.debug === true) setDebugMode(true);
|
|
1537
1697
|
debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
|
|
1538
|
-
|
|
1698
|
+
S.redactor = redactor;
|
|
1539
1699
|
const distro = options.distro ?? SDK_IDENTITY;
|
|
1540
1700
|
configureCompatCheck({ endpoint, enabled: options.compatCheck !== false, sdk: distro });
|
|
1541
1701
|
const resource = new Resource2({
|
|
@@ -1549,8 +1709,14 @@ function initAutterServer(options) {
|
|
|
1549
1709
|
"telemetry.distro.version": distro.version,
|
|
1550
1710
|
// Tells the ingester request metrics arrive on the metrics pipe, so
|
|
1551
1711
|
// it must not also fold our server spans into usage rollups (that
|
|
1552
|
-
// would double-count every sampled request)
|
|
1553
|
-
"autter.metrics_wired": true
|
|
1712
|
+
// would double-count every sampled request)...
|
|
1713
|
+
"autter.metrics_wired": true,
|
|
1714
|
+
// ...for the requests whose metric carries their route: those
|
|
1715
|
+
// request spans say so (`autter.metric_has_route`, see
|
|
1716
|
+
// captureRequestRoute). Ingesters honour metrics_wired only with
|
|
1717
|
+
// this, so an older SDK, whose Next.js metrics have no route, keeps
|
|
1718
|
+
// its span-fed per-route counts.
|
|
1719
|
+
"autter.metrics_routes": true
|
|
1554
1720
|
});
|
|
1555
1721
|
const rootSampler = new TraceIdRatioBasedSampler(options.traceSampleRate ?? 0.01);
|
|
1556
1722
|
const headSampler = new ParentBasedSampler({
|
|
@@ -1567,6 +1733,7 @@ function initAutterServer(options) {
|
|
|
1567
1733
|
const retainTraces = retainOnError || slowThresholdMs > 0;
|
|
1568
1734
|
let sampler = retainTraces ? new RecordUnsampledSampler(headSampler) : headSampler;
|
|
1569
1735
|
if (options.llmTracing !== false) sampler = new LlmAwareSampler(sampler);
|
|
1736
|
+
sampler = new RouteLabelSampler(sampler);
|
|
1570
1737
|
const errorTraceBuffer = retainTraces ? new ErrorTraceRetentionProcessor(
|
|
1571
1738
|
new BatchSpanProcessor(traceExporter(), { scheduledDelayMillis: 2e3 }),
|
|
1572
1739
|
retainOnError,
|
|
@@ -1584,7 +1751,7 @@ function initAutterServer(options) {
|
|
|
1584
1751
|
// 60 s export.
|
|
1585
1752
|
temporalityPreference: AggregationTemporalityPreference.DELTA
|
|
1586
1753
|
}),
|
|
1587
|
-
() =>
|
|
1754
|
+
() => redactor
|
|
1588
1755
|
),
|
|
1589
1756
|
exportIntervalMillis: options.metricIntervalMs ?? 6e4
|
|
1590
1757
|
});
|
|
@@ -1605,11 +1772,12 @@ function initAutterServer(options) {
|
|
|
1605
1772
|
) })
|
|
1606
1773
|
],
|
|
1607
1774
|
instrumentations: [
|
|
1608
|
-
new HttpInstrumentation({ responseHook:
|
|
1775
|
+
new HttpInstrumentation({ responseHook: captureRequestRoute }),
|
|
1609
1776
|
...options.instrumentations ?? []
|
|
1610
1777
|
]
|
|
1611
1778
|
});
|
|
1612
1779
|
sdk.start();
|
|
1780
|
+
patchLoadedHttpModules();
|
|
1613
1781
|
const stopMemoryMetrics = options.memoryMetrics === false ? null : startMemoryMetrics();
|
|
1614
1782
|
noteCompatFeature("endpoint_latency");
|
|
1615
1783
|
if (stopMemoryMetrics) noteCompatFeature("memory_metrics");
|
|
@@ -1628,12 +1796,12 @@ function initAutterServer(options) {
|
|
|
1628
1796
|
errorTraceBuffer?.retainActiveTrace();
|
|
1629
1797
|
telemetryStats.markCaptured();
|
|
1630
1798
|
const isErr = isError(error);
|
|
1631
|
-
const message =
|
|
1632
|
-
const stackText = isErr && error.stack ?
|
|
1799
|
+
const message = redactor.text(isErr ? error.message : String(error));
|
|
1800
|
+
const stackText = isErr && error.stack ? redactor.text(error.stack) : "";
|
|
1633
1801
|
const split = splitFingerprint(attributes);
|
|
1634
|
-
const fingerprint = fingerprintEventAttributes(split.fingerprint,
|
|
1802
|
+
const fingerprint = fingerprintEventAttributes(split.fingerprint, redactor.text);
|
|
1635
1803
|
if (fingerprint["autter.fingerprint"]) noteCompatFeature("fingerprint_override");
|
|
1636
|
-
const redacted =
|
|
1804
|
+
const redacted = redactor(split.attributes);
|
|
1637
1805
|
const activeSpan = trace2.getActiveSpan();
|
|
1638
1806
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1639
1807
|
const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
|
|
@@ -1660,17 +1828,17 @@ function initAutterServer(options) {
|
|
|
1660
1828
|
"exception.stacktrace": stackText,
|
|
1661
1829
|
...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
|
|
1662
1830
|
...declared,
|
|
1663
|
-
...breadcrumbEventAttributes(
|
|
1831
|
+
...breadcrumbEventAttributes(redactor.text, error)
|
|
1664
1832
|
});
|
|
1665
1833
|
} else {
|
|
1666
1834
|
const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureException")).join("\n");
|
|
1667
1835
|
span.addEvent("exception", {
|
|
1668
1836
|
"exception.type": isErr ? error.name : "Error",
|
|
1669
1837
|
"exception.message": message,
|
|
1670
|
-
...stack ? { "exception.stacktrace":
|
|
1838
|
+
...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
|
|
1671
1839
|
...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
|
|
1672
1840
|
...declared,
|
|
1673
|
-
...breadcrumbEventAttributes(
|
|
1841
|
+
...breadcrumbEventAttributes(redactor.text, error)
|
|
1674
1842
|
});
|
|
1675
1843
|
}
|
|
1676
1844
|
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
@@ -1682,16 +1850,16 @@ function initAutterServer(options) {
|
|
|
1682
1850
|
}
|
|
1683
1851
|
telemetryStats.markCaptured();
|
|
1684
1852
|
const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
|
|
1685
|
-
const safeMessage =
|
|
1853
|
+
const safeMessage = redactor.text(message);
|
|
1686
1854
|
const span = errorTracer.startSpan("Message", {
|
|
1687
|
-
attributes: { "autter.severity": severity, ...
|
|
1855
|
+
attributes: { "autter.severity": severity, ...redactor(attributes) }
|
|
1688
1856
|
});
|
|
1689
1857
|
span.addEvent("exception", {
|
|
1690
1858
|
"exception.type": "Message",
|
|
1691
1859
|
"exception.message": safeMessage,
|
|
1692
|
-
...stack ? { "exception.stacktrace":
|
|
1860
|
+
...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
|
|
1693
1861
|
"autter.severity": severity,
|
|
1694
|
-
...breadcrumbEventAttributes(
|
|
1862
|
+
...breadcrumbEventAttributes(redactor.text)
|
|
1695
1863
|
});
|
|
1696
1864
|
span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
|
|
1697
1865
|
span.end();
|
|
@@ -1702,11 +1870,11 @@ function initAutterServer(options) {
|
|
|
1702
1870
|
const activeSpan = trace2.getActiveSpan();
|
|
1703
1871
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
1704
1872
|
const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
|
|
1705
|
-
const safeOutcome =
|
|
1873
|
+
const safeOutcome = redactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
1706
1874
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
1707
1875
|
const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
|
|
1708
1876
|
span.addEvent("autter.outcome", {
|
|
1709
|
-
...
|
|
1877
|
+
...redactor(attributes),
|
|
1710
1878
|
"autter.outcome.status": "error",
|
|
1711
1879
|
"autter.outcome.name": safeName,
|
|
1712
1880
|
"autter.outcome.message": safeMessage
|
|
@@ -1722,11 +1890,11 @@ function initAutterServer(options) {
|
|
|
1722
1890
|
distro,
|
|
1723
1891
|
release: options.release,
|
|
1724
1892
|
options: options.logging,
|
|
1725
|
-
redact:
|
|
1726
|
-
run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn,
|
|
1893
|
+
redact: redactor,
|
|
1894
|
+
run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, redactor(attributes), links),
|
|
1727
1895
|
reportOutcome: reportOutcome2
|
|
1728
1896
|
});
|
|
1729
|
-
hookRequests = options.logging?.requests === true;
|
|
1897
|
+
S.hookRequests = options.logging?.requests === true;
|
|
1730
1898
|
let onCrash = null;
|
|
1731
1899
|
let uninstallRejections = null;
|
|
1732
1900
|
if (options.captureGlobalErrors !== false) {
|
|
@@ -1769,17 +1937,20 @@ function initAutterServer(options) {
|
|
|
1769
1937
|
captureException: captureException2,
|
|
1770
1938
|
captureMessage: captureMessage2,
|
|
1771
1939
|
reportOutcome: reportOutcome2,
|
|
1772
|
-
withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn,
|
|
1940
|
+
withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn, redactor(attributes)),
|
|
1773
1941
|
withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
|
|
1774
1942
|
trackLlmCall: (call) => recordLlmCall(llmTracer, call),
|
|
1775
1943
|
shutdown: async () => {
|
|
1776
1944
|
const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
|
|
1777
|
-
hookRequests = false;
|
|
1778
1945
|
if (onCrash) process.off("uncaughtExceptionMonitor", onCrash);
|
|
1779
1946
|
uninstallRejections?.();
|
|
1780
1947
|
stopMemoryMetrics?.();
|
|
1781
|
-
active
|
|
1782
|
-
|
|
1948
|
+
if (S.active === server) {
|
|
1949
|
+
S.active = null;
|
|
1950
|
+
S.alwaysOnProvider = null;
|
|
1951
|
+
S.hookRequests = false;
|
|
1952
|
+
S.redactor = makeRedactor(true);
|
|
1953
|
+
}
|
|
1783
1954
|
autoFlushHandle?.dispose();
|
|
1784
1955
|
autoFlushHandle = null;
|
|
1785
1956
|
unregisterFlushTargets();
|
|
@@ -1788,82 +1959,81 @@ function initAutterServer(options) {
|
|
|
1788
1959
|
if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
|
|
1789
1960
|
}
|
|
1790
1961
|
};
|
|
1791
|
-
active = server;
|
|
1792
|
-
|
|
1962
|
+
S.active = server;
|
|
1963
|
+
S.alwaysOnProvider = alwaysOnProvider;
|
|
1793
1964
|
return server;
|
|
1794
1965
|
}
|
|
1795
1966
|
function captureException(error, attributes) {
|
|
1796
|
-
if (active) {
|
|
1797
|
-
active.captureException(error, attributes);
|
|
1967
|
+
if (S.active) {
|
|
1968
|
+
S.active.captureException(error, attributes);
|
|
1798
1969
|
return;
|
|
1799
1970
|
}
|
|
1800
|
-
if (loggerOnlyCapture) {
|
|
1801
|
-
loggerOnlyCapture(error, attributes);
|
|
1971
|
+
if (S.loggerOnlyCapture) {
|
|
1972
|
+
S.loggerOnlyCapture(error, attributes);
|
|
1802
1973
|
return;
|
|
1803
1974
|
}
|
|
1804
1975
|
markCaptured(error);
|
|
1805
1976
|
noteOperationError(error);
|
|
1806
1977
|
const split = splitFingerprint(attributes);
|
|
1807
|
-
const fingerprint = fingerprintEventAttributes(split.fingerprint,
|
|
1978
|
+
const fingerprint = fingerprintEventAttributes(split.fingerprint, S.redactor.text);
|
|
1808
1979
|
notifyException(error, { ...split.attributes, ...fingerprint });
|
|
1809
1980
|
const span = trace2.getTracer("autter-errors").startSpan(isError(error) ? error.name : "Error", {
|
|
1810
|
-
attributes: { ...
|
|
1981
|
+
attributes: { ...S.redactor(split.attributes), ...fingerprint }
|
|
1811
1982
|
});
|
|
1812
1983
|
recordError(span, error);
|
|
1813
1984
|
span.end();
|
|
1814
1985
|
}
|
|
1815
|
-
var loggerOnlyCapture = null;
|
|
1816
1986
|
function setLoggerOnlyCapture(fn) {
|
|
1817
|
-
loggerOnlyCapture = fn;
|
|
1987
|
+
S.loggerOnlyCapture = fn;
|
|
1818
1988
|
}
|
|
1819
1989
|
function serverActive() {
|
|
1820
|
-
return active !== null;
|
|
1990
|
+
return S.active !== null;
|
|
1821
1991
|
}
|
|
1822
1992
|
setRequestExceptionCapturer((error, attributes) => captureException(error, attributes));
|
|
1823
1993
|
setRequestSpanAnnotator((attributes) => {
|
|
1824
1994
|
const span = trace2.getActiveSpan();
|
|
1825
|
-
if (span?.isRecording()) span.setAttributes(
|
|
1995
|
+
if (span?.isRecording()) span.setAttributes(S.redactor(splitFingerprint(attributes).attributes));
|
|
1826
1996
|
});
|
|
1827
1997
|
function withProcessSpan(name, fn, attributes) {
|
|
1828
|
-
if (active) return active.withProcessSpan(name, fn, attributes);
|
|
1998
|
+
if (S.active) return S.active.withProcessSpan(name, fn, attributes);
|
|
1829
1999
|
return runWithSpan(
|
|
1830
2000
|
trace2.getTracer("autter-processes"),
|
|
1831
2001
|
name,
|
|
1832
2002
|
fn,
|
|
1833
|
-
|
|
2003
|
+
S.redactor(attributes)
|
|
1834
2004
|
);
|
|
1835
2005
|
}
|
|
1836
2006
|
function withLlmCall(info, fn) {
|
|
1837
|
-
if (active) return active.withLlmCall(info, fn);
|
|
2007
|
+
if (S.active) return S.active.withLlmCall(info, fn);
|
|
1838
2008
|
return runLlmSpan(trace2.getTracer("autter-llm"), info, fn);
|
|
1839
2009
|
}
|
|
1840
2010
|
function trackLlmCall(call) {
|
|
1841
|
-
if (active) {
|
|
1842
|
-
active.trackLlmCall(call);
|
|
2011
|
+
if (S.active) {
|
|
2012
|
+
S.active.trackLlmCall(call);
|
|
1843
2013
|
return;
|
|
1844
2014
|
}
|
|
1845
2015
|
recordLlmCall(trace2.getTracer("autter-llm"), call);
|
|
1846
2016
|
}
|
|
1847
2017
|
function captureMessage(message, severity = "warning", attributes) {
|
|
1848
|
-
if (active) {
|
|
1849
|
-
active.captureMessage(message, severity, attributes);
|
|
2018
|
+
if (S.active) {
|
|
2019
|
+
S.active.captureMessage(message, severity, attributes);
|
|
1850
2020
|
return;
|
|
1851
2021
|
}
|
|
1852
|
-
const safeMessage =
|
|
2022
|
+
const safeMessage = S.redactor.text(message);
|
|
1853
2023
|
const span = trace2.getTracer("autter-errors").startSpan("Message", {
|
|
1854
|
-
attributes: { "autter.severity": severity, ...
|
|
2024
|
+
attributes: { "autter.severity": severity, ...S.redactor(attributes) }
|
|
1855
2025
|
});
|
|
1856
2026
|
span.addEvent("exception", {
|
|
1857
2027
|
"exception.type": "Message",
|
|
1858
2028
|
"exception.message": safeMessage,
|
|
1859
2029
|
"autter.severity": severity,
|
|
1860
|
-
...breadcrumbEventAttributes(
|
|
2030
|
+
...breadcrumbEventAttributes(S.redactor.text)
|
|
1861
2031
|
});
|
|
1862
2032
|
span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
|
|
1863
2033
|
span.end();
|
|
1864
2034
|
}
|
|
1865
2035
|
function reportOutcome(name, message, attributes) {
|
|
1866
|
-
if (active) return active.reportOutcome(name, message, attributes);
|
|
2036
|
+
if (S.active) return S.active.reportOutcome(name, message, attributes);
|
|
1867
2037
|
const span = trace2.getTracer("autter-outcomes").startSpan("OutcomeFailure");
|
|
1868
2038
|
const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
1869
2039
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
@@ -1885,13 +2055,13 @@ function makeSafeCapture(options) {
|
|
|
1885
2055
|
};
|
|
1886
2056
|
}
|
|
1887
2057
|
function alwaysOnTracer(name) {
|
|
1888
|
-
return
|
|
2058
|
+
return S.alwaysOnProvider ? S.alwaysOnProvider.getTracer(name) : trace2.getTracer(name);
|
|
1889
2059
|
}
|
|
1890
2060
|
function autterLlmTracer() {
|
|
1891
2061
|
return alwaysOnTracer("autter-llm");
|
|
1892
2062
|
}
|
|
1893
2063
|
async function emitLlmSelftestTrace() {
|
|
1894
|
-
const provider =
|
|
2064
|
+
const provider = S.alwaysOnProvider;
|
|
1895
2065
|
if (!provider) {
|
|
1896
2066
|
throw new Error(
|
|
1897
2067
|
"emitLlmSelftestTrace() requires initAutterServer() to have been called"
|
|
@@ -2149,14 +2319,14 @@ function startCaughtExceptionSampler(options = {}) {
|
|
|
2149
2319
|
const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
|
|
2150
2320
|
const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
|
|
2151
2321
|
const session = new inspector.Session();
|
|
2152
|
-
let
|
|
2322
|
+
let active = true;
|
|
2153
2323
|
let minute = 0;
|
|
2154
2324
|
let sent = 0;
|
|
2155
2325
|
session.connect();
|
|
2156
2326
|
session.on("Debugger.paused", (message) => {
|
|
2157
2327
|
session.post("Debugger.resume", () => {
|
|
2158
2328
|
});
|
|
2159
|
-
if (!
|
|
2329
|
+
if (!active || message.params.reason !== "exception") return;
|
|
2160
2330
|
const nowMinute = Math.floor(Date.now() / 6e4);
|
|
2161
2331
|
if (nowMinute !== minute) {
|
|
2162
2332
|
minute = nowMinute;
|
|
@@ -2171,16 +2341,16 @@ function startCaughtExceptionSampler(options = {}) {
|
|
|
2171
2341
|
error.stack = `${error.name}: ${error.message}
|
|
2172
2342
|
${frames.join("\n")}`;
|
|
2173
2343
|
queueMicrotask(() => {
|
|
2174
|
-
if (
|
|
2344
|
+
if (active) captureException(error, { "autter.handled": true, "autter.sampled": true });
|
|
2175
2345
|
});
|
|
2176
2346
|
});
|
|
2177
2347
|
session.post("Debugger.enable", (error) => {
|
|
2178
|
-
if (!error &&
|
|
2348
|
+
if (!error && active) session.post("Debugger.setPauseOnExceptions", { state: "all" }, () => {
|
|
2179
2349
|
});
|
|
2180
2350
|
});
|
|
2181
2351
|
return { stop() {
|
|
2182
|
-
if (!
|
|
2183
|
-
|
|
2352
|
+
if (!active) return;
|
|
2353
|
+
active = false;
|
|
2184
2354
|
session.post("Debugger.setPauseOnExceptions", { state: "none" }, () => {
|
|
2185
2355
|
session.post("Debugger.disable", () => session.disconnect());
|
|
2186
2356
|
});
|
|
@@ -2228,9 +2398,9 @@ import {
|
|
|
2228
2398
|
SpanStatusCode as SpanStatusCode3,
|
|
2229
2399
|
trace as trace3
|
|
2230
2400
|
} from "@opentelemetry/api";
|
|
2231
|
-
var
|
|
2401
|
+
var L = sharedSlot("logging", () => ({ active: null }));
|
|
2232
2402
|
function initAutterLogging(options) {
|
|
2233
|
-
if (
|
|
2403
|
+
if (L.active) return L.active;
|
|
2234
2404
|
if (serverActive()) {
|
|
2235
2405
|
console.warn(
|
|
2236
2406
|
"[autter-runtime] initAutterLogging() ignored: initAutterServer() is already active and includes logging"
|
|
@@ -2332,11 +2502,11 @@ function initAutterLogging(options) {
|
|
|
2332
2502
|
autoFlushHandle?.dispose();
|
|
2333
2503
|
autoFlushHandle = null;
|
|
2334
2504
|
unregisterFlushTargets();
|
|
2335
|
-
|
|
2505
|
+
if (L.active === handle) L.active = null;
|
|
2336
2506
|
await shutdownRuntimeLogger();
|
|
2337
2507
|
}
|
|
2338
2508
|
};
|
|
2339
|
-
|
|
2509
|
+
L.active = handle;
|
|
2340
2510
|
return handle;
|
|
2341
2511
|
}
|
|
2342
2512
|
|