@autter/runtime-node 1.9.0 → 1.10.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 +30 -6
- package/dist/chunk-3UODRQBD.js +878 -0
- package/dist/chunk-HBH64LWQ.cjs +878 -0
- package/dist/{chunk-ZKM76SDP.js → chunk-KWAJIELR.js} +304 -201
- package/dist/{chunk-BHYHORUD.cjs → chunk-S6WJ5YLP.cjs} +304 -201
- package/dist/{chunk-YWTIKZSI.cjs → chunk-STOXJZ7Z.cjs} +38 -15
- package/dist/{chunk-HHKQ3UCH.js → chunk-V65UY6LU.js} +30 -7
- package/dist/cli.cjs +36 -9
- package/dist/cli.js +32 -5
- package/dist/index.cjs +655 -292
- package/dist/index.d.cts +154 -13
- package/dist/index.d.ts +154 -13
- package/dist/index.js +434 -71
- package/dist/{sinks-CLtQFPnn.d.ts → sinks-BfUoE96B.d.cts} +3 -1
- package/dist/{sinks-CLtQFPnn.d.cts → sinks-BfUoE96B.d.ts} +3 -1
- package/dist/testing.cjs +8 -8
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +2 -2
- package/package.json +2 -1
- package/dist/chunk-AN45KLWD.cjs +0 -202
- package/dist/chunk-JSGGUWRD.js +0 -202
package/dist/index.js
CHANGED
|
@@ -51,15 +51,17 @@ import {
|
|
|
51
51
|
stopLoggedErrorCapture,
|
|
52
52
|
toClientError,
|
|
53
53
|
withRuntimeOperation
|
|
54
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-V65UY6LU.js";
|
|
55
55
|
import {
|
|
56
|
-
runDoctor
|
|
57
|
-
|
|
56
|
+
runDoctor,
|
|
57
|
+
runVerify
|
|
58
|
+
} from "./chunk-3UODRQBD.js";
|
|
58
59
|
import {
|
|
59
60
|
COMPAT_MANIFEST,
|
|
60
61
|
CountingExporter,
|
|
61
62
|
INGESTER_VERSION_HEADER,
|
|
62
63
|
SDK_IDENTITY,
|
|
64
|
+
authHeaders,
|
|
63
65
|
configureCompatCheck,
|
|
64
66
|
debugLog,
|
|
65
67
|
ensureCompatConfigured,
|
|
@@ -69,14 +71,18 @@ import {
|
|
|
69
71
|
installAutterAutoFlush,
|
|
70
72
|
isDebugEnabled,
|
|
71
73
|
noteCompatFeature,
|
|
74
|
+
noteIngestRefusal,
|
|
72
75
|
noteRelayRejection,
|
|
73
76
|
observeIngesterResponse,
|
|
74
77
|
registerFlushTarget,
|
|
78
|
+
resolveIngestKey,
|
|
75
79
|
setDebugMode,
|
|
76
80
|
sharedSlot,
|
|
77
81
|
telemetryStats,
|
|
78
|
-
unregisterFlushTargets
|
|
79
|
-
|
|
82
|
+
unregisterFlushTargets,
|
|
83
|
+
warnKeyKind,
|
|
84
|
+
warnMissingKey
|
|
85
|
+
} from "./chunk-KWAJIELR.js";
|
|
80
86
|
|
|
81
87
|
// src/relay.ts
|
|
82
88
|
var IpWindow = class {
|
|
@@ -358,18 +364,53 @@ function relayFingerprint(raw, redactor) {
|
|
|
358
364
|
}
|
|
359
365
|
var defaultRelayRedactor = makeRedactor(true);
|
|
360
366
|
function sanitizeBrowserPayload(raw, redactor = defaultRelayRedactor) {
|
|
361
|
-
|
|
367
|
+
const checked = checkBrowserPayload(raw, redactor);
|
|
368
|
+
return "payload" in checked ? checked.payload : null;
|
|
369
|
+
}
|
|
370
|
+
var MAX_RELAY_ISSUES = 5;
|
|
371
|
+
function describe(value) {
|
|
372
|
+
if (value === null) return "null";
|
|
373
|
+
if (Array.isArray(value)) return "an array";
|
|
374
|
+
if (typeof value === "string") return value ? `"${value.slice(0, 40)}"` : "an empty string";
|
|
375
|
+
return typeof value === "undefined" ? "missing" : `a ${typeof value}`;
|
|
376
|
+
}
|
|
377
|
+
function checkBrowserPayload(raw, redactor = defaultRelayRedactor) {
|
|
378
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
379
|
+
return { issues: [{ path: [], message: `expected a JSON object, got ${describe(raw)}` }] };
|
|
380
|
+
}
|
|
362
381
|
const p = raw;
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
382
|
+
const issues = [];
|
|
383
|
+
const issue = (path, message) => {
|
|
384
|
+
if (issues.length < MAX_RELAY_ISSUES) issues.push({ path, message });
|
|
385
|
+
};
|
|
386
|
+
if (p.version !== 1) issue(["version"], `expected 1, got ${describe(p.version)}`);
|
|
387
|
+
if (typeof p.service !== "string" || !p.service) issue(["service"], `expected a non-empty string, got ${describe(p.service)}`);
|
|
388
|
+
if (typeof p.environment !== "string" || !p.environment) {
|
|
389
|
+
issue(["environment"], `expected a non-empty string, got ${describe(p.environment)}`);
|
|
390
|
+
}
|
|
391
|
+
if (!Array.isArray(p.events)) issue(["events"], `expected an array, got ${describe(p.events)}`);
|
|
392
|
+
else if (p.events.length > MAX_EVENTS) issue(["events"], `at most ${MAX_EVENTS} events per batch, got ${p.events.length}`);
|
|
393
|
+
if (Array.isArray(p.events) && p.events.length <= MAX_EVENTS) {
|
|
394
|
+
p.events.forEach((rawEvent, index) => {
|
|
395
|
+
if (typeof rawEvent !== "object" || rawEvent === null) {
|
|
396
|
+
issue(["events", index], `expected an object, got ${describe(rawEvent)}`);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const e = rawEvent;
|
|
400
|
+
if (typeof e.type !== "string" || !EVENT_TYPES.has(e.type)) {
|
|
401
|
+
issue(["events", index, "type"], `expected one of ${[...EVENT_TYPES].join(", ")}, got ${describe(e.type)}`);
|
|
402
|
+
}
|
|
403
|
+
if (typeof e.timestamp !== "string") {
|
|
404
|
+
issue(["events", index, "timestamp"], `expected an ISO 8601 string, got ${describe(e.timestamp)}`);
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
if (issues.length) return { issues };
|
|
409
|
+
const service = p.service;
|
|
410
|
+
const environment = p.environment;
|
|
367
411
|
const events = [];
|
|
368
412
|
for (const rawEvent of p.events) {
|
|
369
|
-
if (typeof rawEvent !== "object" || rawEvent === null) return null;
|
|
370
413
|
const e = rawEvent;
|
|
371
|
-
if (typeof e.type !== "string" || !EVENT_TYPES.has(e.type)) return null;
|
|
372
|
-
if (typeof e.timestamp !== "string") return null;
|
|
373
414
|
events.push({
|
|
374
415
|
type: e.type,
|
|
375
416
|
timestamp: e.timestamp,
|
|
@@ -390,31 +431,62 @@ function sanitizeBrowserPayload(raw, redactor = defaultRelayRedactor) {
|
|
|
390
431
|
...typeof e.traceId === "string" && TRACE_ID.test(e.traceId) ? { traceId: e.traceId } : {}
|
|
391
432
|
});
|
|
392
433
|
}
|
|
393
|
-
return {
|
|
434
|
+
return { payload: {
|
|
394
435
|
version: 1,
|
|
395
436
|
...typeof p.sessionId === "string" ? { sessionId: p.sessionId.slice(0, 100) } : {},
|
|
396
|
-
service:
|
|
397
|
-
environment:
|
|
437
|
+
service: service.slice(0, 200),
|
|
438
|
+
environment: environment.slice(0, 100),
|
|
398
439
|
...typeof p.release === "string" ? { release: p.release.slice(0, 200) } : {},
|
|
399
440
|
// @autter/runtime-browser version, for the ingester's compat records.
|
|
400
441
|
...typeof p.sdk === "string" && /^\d{1,6}\.\d{1,6}\.\d{1,6}[0-9A-Za-z.+-]{0,20}$/.test(p.sdk) ? { sdk: p.sdk } : {},
|
|
401
442
|
events
|
|
402
|
-
};
|
|
443
|
+
} };
|
|
403
444
|
}
|
|
404
|
-
|
|
445
|
+
var NO_KEY_BODY = {
|
|
446
|
+
error: "relay has no ingest key",
|
|
447
|
+
fix: "set AUTTER_RUNTIME_KEY (a server key, autter_rt_\u2026) where the relay runs"
|
|
448
|
+
};
|
|
449
|
+
var FORWARD_ATTEMPTS = 3;
|
|
450
|
+
var FORWARD_MAX_WAIT_MS = 1e4;
|
|
451
|
+
function forward(payload, opts, apiKey) {
|
|
405
452
|
const endpoint = (opts.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "");
|
|
406
453
|
const url = `${endpoint}/v1/browser`;
|
|
407
454
|
const compat = opts.compatCheck !== false;
|
|
408
455
|
if (compat) ensureCompatConfigured(endpoint);
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
456
|
+
const body = JSON.stringify(payload);
|
|
457
|
+
const attempt = async (n) => {
|
|
458
|
+
let response;
|
|
459
|
+
try {
|
|
460
|
+
response = await fetch(url, {
|
|
461
|
+
method: "POST",
|
|
462
|
+
headers: {
|
|
463
|
+
"content-type": "application/json",
|
|
464
|
+
...authHeaders(apiKey)
|
|
465
|
+
},
|
|
466
|
+
body,
|
|
467
|
+
signal: AbortSignal.timeout(1e4)
|
|
468
|
+
});
|
|
469
|
+
} catch (err) {
|
|
470
|
+
if (n >= FORWARD_ATTEMPTS) throw err;
|
|
471
|
+
await sleep(1e3 * 2 ** (n - 1));
|
|
472
|
+
return attempt(n + 1);
|
|
473
|
+
}
|
|
474
|
+
if ((response.status === 429 || response.status >= 500) && n < FORWARD_ATTEMPTS) {
|
|
475
|
+
const seconds = Number(response.headers.get("retry-after"));
|
|
476
|
+
await response.body?.cancel().catch(() => {
|
|
477
|
+
});
|
|
478
|
+
await sleep(seconds > 0 ? Math.min(seconds * 1e3, FORWARD_MAX_WAIT_MS) : 1e3 * 2 ** (n - 1));
|
|
479
|
+
return attempt(n + 1);
|
|
480
|
+
}
|
|
481
|
+
if (!response.ok) {
|
|
482
|
+
noteIngestRefusal({
|
|
483
|
+
status: response.status,
|
|
484
|
+
route: "/v1/browser",
|
|
485
|
+
endpoint,
|
|
486
|
+
body: await response.clone().text().catch(() => ""),
|
|
487
|
+
via: "relay"
|
|
488
|
+
});
|
|
489
|
+
}
|
|
418
490
|
if (!compat) return;
|
|
419
491
|
const types = new Set(
|
|
420
492
|
(payload.events ?? []).map((e) => String(e.type))
|
|
@@ -425,20 +497,33 @@ function forward(payload, opts) {
|
|
|
425
497
|
noteCompatFeature("browser_trace_propagation");
|
|
426
498
|
}
|
|
427
499
|
noteRelayRejection(types, response.status, response.headers);
|
|
428
|
-
}
|
|
500
|
+
};
|
|
501
|
+
void attempt(1).catch((err) => {
|
|
429
502
|
(opts.onError ?? ((e) => console.warn("autter relay forward failed:", e)))(
|
|
430
503
|
err
|
|
431
504
|
);
|
|
432
505
|
});
|
|
433
506
|
}
|
|
507
|
+
function sleep(ms) {
|
|
508
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
509
|
+
}
|
|
434
510
|
function createBrowserRelayFetchHandler(opts) {
|
|
435
511
|
const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
|
|
436
512
|
const redactor = opts.redact === void 0 || opts.redact === true ? defaultRelayRedactor : makeRedactor(opts.redact);
|
|
437
513
|
const limiter = opts.perIpRateLimit === false ? null : new IpWindow(opts.perIpRateLimit ?? 120);
|
|
514
|
+
const apiKey = resolveIngestKey(opts.apiKey);
|
|
515
|
+
if (!apiKey) warnMissingKey("relay");
|
|
516
|
+
else warnKeyKind(apiKey);
|
|
438
517
|
return async (request) => {
|
|
439
518
|
if (request.method !== "POST") {
|
|
440
519
|
return new Response(null, { status: 405 });
|
|
441
520
|
}
|
|
521
|
+
if (!apiKey) {
|
|
522
|
+
return new Response(JSON.stringify(NO_KEY_BODY), {
|
|
523
|
+
status: 500,
|
|
524
|
+
headers: { "content-type": "application/json" }
|
|
525
|
+
});
|
|
526
|
+
}
|
|
442
527
|
if (limiter) {
|
|
443
528
|
const ip = fetchClientKey(request, opts);
|
|
444
529
|
if (!limiter.allow(ip)) {
|
|
@@ -468,13 +553,14 @@ function createBrowserRelayFetchHandler(opts) {
|
|
|
468
553
|
status: 400
|
|
469
554
|
});
|
|
470
555
|
}
|
|
471
|
-
const
|
|
472
|
-
if (!payload) {
|
|
473
|
-
return new Response(JSON.stringify({ error: "invalid payload" }), {
|
|
474
|
-
status: 400
|
|
556
|
+
const checked = checkBrowserPayload(raw, redactor);
|
|
557
|
+
if (!("payload" in checked)) {
|
|
558
|
+
return new Response(JSON.stringify({ error: "invalid payload", issues: checked.issues }), {
|
|
559
|
+
status: 400,
|
|
560
|
+
headers: { "content-type": "application/json" }
|
|
475
561
|
});
|
|
476
562
|
}
|
|
477
|
-
forward(payload, opts);
|
|
563
|
+
forward(checked.payload, opts, apiKey);
|
|
478
564
|
return new Response(null, { status: 202 });
|
|
479
565
|
};
|
|
480
566
|
}
|
|
@@ -491,13 +577,16 @@ function createBrowserRelayHandler(opts) {
|
|
|
491
577
|
res.end();
|
|
492
578
|
}
|
|
493
579
|
}
|
|
580
|
+
const apiKey = resolveIngestKey(opts.apiKey);
|
|
581
|
+
if (!apiKey) warnMissingKey("relay");
|
|
582
|
+
else warnKeyKind(apiKey);
|
|
494
583
|
function handleParsed(raw, res) {
|
|
495
|
-
const
|
|
496
|
-
if (!payload) {
|
|
497
|
-
respond(res, 400, { error: "invalid payload" });
|
|
584
|
+
const checked = checkBrowserPayload(raw, redactor);
|
|
585
|
+
if (!("payload" in checked)) {
|
|
586
|
+
respond(res, 400, { error: "invalid payload", issues: checked.issues });
|
|
498
587
|
return;
|
|
499
588
|
}
|
|
500
|
-
forward(payload, opts);
|
|
589
|
+
forward(checked.payload, opts, apiKey);
|
|
501
590
|
respond(res, 202);
|
|
502
591
|
}
|
|
503
592
|
return (req, res) => {
|
|
@@ -505,6 +594,10 @@ function createBrowserRelayHandler(opts) {
|
|
|
505
594
|
respond(res, 405);
|
|
506
595
|
return;
|
|
507
596
|
}
|
|
597
|
+
if (!apiKey) {
|
|
598
|
+
respond(res, 500, NO_KEY_BODY);
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
508
601
|
if (limiter) {
|
|
509
602
|
const ip = nodeClientKey(req, opts);
|
|
510
603
|
if (!limiter.allow(ip)) {
|
|
@@ -554,13 +647,13 @@ function createBrowserRelayHandler(opts) {
|
|
|
554
647
|
|
|
555
648
|
// src/server.ts
|
|
556
649
|
import { errorMonitor } from "events";
|
|
557
|
-
import { createRequire } from "module";
|
|
558
|
-
import { join } from "path";
|
|
650
|
+
import { createRequire as createRequire2 } from "module";
|
|
651
|
+
import { join as join2 } from "path";
|
|
559
652
|
import { ServerResponse } from "http";
|
|
560
653
|
import { randomUUID } from "crypto";
|
|
561
654
|
import {
|
|
562
|
-
context as
|
|
563
|
-
trace as
|
|
655
|
+
context as context3,
|
|
656
|
+
trace as trace3,
|
|
564
657
|
SpanKind,
|
|
565
658
|
SpanStatusCode,
|
|
566
659
|
TraceFlags
|
|
@@ -806,6 +899,73 @@ var RedactingMetricExporter = class {
|
|
|
806
899
|
}
|
|
807
900
|
};
|
|
808
901
|
|
|
902
|
+
// src/ingest-exporters.ts
|
|
903
|
+
import { ExportResultCode as ExportResultCode2 } from "@opentelemetry/core";
|
|
904
|
+
import {
|
|
905
|
+
AggregationTemporality as AggregationTemporality2
|
|
906
|
+
} from "@opentelemetry/sdk-metrics";
|
|
907
|
+
function refusalOf(result) {
|
|
908
|
+
if (result.code === ExportResultCode2.SUCCESS) return null;
|
|
909
|
+
const error = result.error;
|
|
910
|
+
return typeof error?.code === "number" ? { status: error.code, body: error.data } : null;
|
|
911
|
+
}
|
|
912
|
+
var NO_KEY = {
|
|
913
|
+
code: ExportResultCode2.FAILED,
|
|
914
|
+
error: new Error("no Autter ingest key: not sent (set AUTTER_RUNTIME_KEY)")
|
|
915
|
+
};
|
|
916
|
+
function observe(endpoint, route, callback) {
|
|
917
|
+
return (result) => {
|
|
918
|
+
const refusal = refusalOf(result);
|
|
919
|
+
if (refusal) noteIngestRefusal({ ...refusal, endpoint, route });
|
|
920
|
+
callback(result);
|
|
921
|
+
};
|
|
922
|
+
}
|
|
923
|
+
var IngestSpanExporter = class {
|
|
924
|
+
constructor(inner, target) {
|
|
925
|
+
this.inner = inner;
|
|
926
|
+
this.target = target;
|
|
927
|
+
}
|
|
928
|
+
inner;
|
|
929
|
+
target;
|
|
930
|
+
export(spans, resultCallback) {
|
|
931
|
+
if (!this.target.hasKey) {
|
|
932
|
+
resultCallback(NO_KEY);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
this.inner.export(spans, observe(this.target.endpoint, "/v1/traces", resultCallback));
|
|
936
|
+
}
|
|
937
|
+
shutdown() {
|
|
938
|
+
return this.inner.shutdown();
|
|
939
|
+
}
|
|
940
|
+
forceFlush() {
|
|
941
|
+
return this.inner.forceFlush?.() ?? Promise.resolve();
|
|
942
|
+
}
|
|
943
|
+
};
|
|
944
|
+
var IngestMetricExporter = class {
|
|
945
|
+
constructor(inner, target) {
|
|
946
|
+
this.inner = inner;
|
|
947
|
+
this.target = target;
|
|
948
|
+
}
|
|
949
|
+
inner;
|
|
950
|
+
target;
|
|
951
|
+
export(metrics2, resultCallback) {
|
|
952
|
+
if (!this.target.hasKey) {
|
|
953
|
+
resultCallback(NO_KEY);
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
this.inner.export(metrics2, observe(this.target.endpoint, "/v1/metrics", resultCallback));
|
|
957
|
+
}
|
|
958
|
+
forceFlush() {
|
|
959
|
+
return this.inner.forceFlush();
|
|
960
|
+
}
|
|
961
|
+
shutdown() {
|
|
962
|
+
return this.inner.shutdown();
|
|
963
|
+
}
|
|
964
|
+
selectAggregationTemporality(instrumentType) {
|
|
965
|
+
return this.inner.selectAggregationTemporality ? this.inner.selectAggregationTemporality(instrumentType) : AggregationTemporality2.CUMULATIVE;
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
|
|
809
969
|
// src/memory.ts
|
|
810
970
|
import { PerformanceObserver } from "perf_hooks";
|
|
811
971
|
import { getHeapStatistics } from "v8";
|
|
@@ -914,6 +1074,27 @@ function captureAtBoundary(error, state, rule = void 0, attributes) {
|
|
|
914
1074
|
} catch {
|
|
915
1075
|
}
|
|
916
1076
|
}
|
|
1077
|
+
function requestScopeAttributes() {
|
|
1078
|
+
try {
|
|
1079
|
+
const out = {};
|
|
1080
|
+
const state = local.getStore();
|
|
1081
|
+
const active = context.active();
|
|
1082
|
+
const metadata = getRPCMetadata(active);
|
|
1083
|
+
const http = metadata?.type === RPCType.HTTP ? metadata : void 0;
|
|
1084
|
+
const spanAttributes = http?.span?.attributes;
|
|
1085
|
+
const req = state?.req;
|
|
1086
|
+
const nodeRequest = !!req && typeof req === "object" && typeof req.url === "string" && req.url.startsWith("/");
|
|
1087
|
+
const requestId = state?.requestId ?? spanAttributes?.["autter.request.id"];
|
|
1088
|
+
if (typeof requestId === "string" && requestId) out["autter.request.id"] = requestId;
|
|
1089
|
+
const route = http?.route ?? spanAttributes?.["http.route"] ?? (nodeRequest ? expressRouteOf(req) ?? normalizeRoutePath(pathOf(req)) : void 0);
|
|
1090
|
+
if (typeof route === "string" && route) out["http.route"] = route;
|
|
1091
|
+
const method = (nodeRequest ? req.method : void 0) ?? spanAttributes?.["http.request.method"] ?? spanAttributes?.["http.method"];
|
|
1092
|
+
if (typeof method === "string" && method) out["http.request.method"] = method.toUpperCase();
|
|
1093
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
1094
|
+
} catch {
|
|
1095
|
+
return void 0;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
917
1098
|
function requestStateOf(req) {
|
|
918
1099
|
if (!req || typeof req !== "object") return void 0;
|
|
919
1100
|
return req[REQUEST_STATE];
|
|
@@ -1403,6 +1584,173 @@ function installUnhandledRejectionCapture(capture, mode = unhandledRejectionsMod
|
|
|
1403
1584
|
};
|
|
1404
1585
|
}
|
|
1405
1586
|
|
|
1587
|
+
// src/express-errors.ts
|
|
1588
|
+
import { createRequire } from "module";
|
|
1589
|
+
import { join } from "path";
|
|
1590
|
+
import { context as context2, trace as trace2 } from "@opentelemetry/api";
|
|
1591
|
+
import { Hook } from "require-in-the-middle";
|
|
1592
|
+
var PATCHED = /* @__PURE__ */ Symbol.for("autter.runtime.express.layer");
|
|
1593
|
+
var WRAPPED = /* @__PURE__ */ Symbol.for("autter.runtime.express.next");
|
|
1594
|
+
var ERRORS = /* @__PURE__ */ Symbol.for("autter.runtime.express.errors");
|
|
1595
|
+
var MAX_ERRORS = 8;
|
|
1596
|
+
function noteExpressError(req, error) {
|
|
1597
|
+
if (error === void 0 || error === null || error === false) return;
|
|
1598
|
+
if (error === "route" || error === "router") return;
|
|
1599
|
+
if (!req || typeof req !== "object") return;
|
|
1600
|
+
try {
|
|
1601
|
+
const target = req;
|
|
1602
|
+
let list = target[ERRORS];
|
|
1603
|
+
if (!list) {
|
|
1604
|
+
list = [];
|
|
1605
|
+
target[ERRORS] = list;
|
|
1606
|
+
}
|
|
1607
|
+
if (list.length < MAX_ERRORS && !list.includes(error)) list.push(error);
|
|
1608
|
+
} catch {
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
function wrapNext(req, next) {
|
|
1612
|
+
if (typeof next !== "function") return next;
|
|
1613
|
+
const fn = next;
|
|
1614
|
+
const existing = fn[WRAPPED];
|
|
1615
|
+
if (existing) return existing;
|
|
1616
|
+
const wrapped = function autterExpressNext(...args) {
|
|
1617
|
+
if (args.length > 0) noteExpressError(req, args[0]);
|
|
1618
|
+
return fn.apply(this, args);
|
|
1619
|
+
};
|
|
1620
|
+
try {
|
|
1621
|
+
fn[WRAPPED] = wrapped;
|
|
1622
|
+
} catch {
|
|
1623
|
+
}
|
|
1624
|
+
return wrapped;
|
|
1625
|
+
}
|
|
1626
|
+
function patchLayerPrototype(proto) {
|
|
1627
|
+
if (!proto || typeof proto !== "object") return false;
|
|
1628
|
+
const target = proto;
|
|
1629
|
+
if (target[PATCHED]) return true;
|
|
1630
|
+
const requestName = typeof target.handleRequest === "function" ? "handleRequest" : typeof target.handle_request === "function" ? "handle_request" : null;
|
|
1631
|
+
const errorName = typeof target.handleError === "function" ? "handleError" : typeof target.handle_error === "function" ? "handle_error" : null;
|
|
1632
|
+
if (!requestName || !errorName) return false;
|
|
1633
|
+
const handleRequest = target[requestName];
|
|
1634
|
+
const handleError = target[errorName];
|
|
1635
|
+
target[requestName] = function autterHandleRequest(req, res, next) {
|
|
1636
|
+
let wrapped = next;
|
|
1637
|
+
try {
|
|
1638
|
+
wrapped = wrapNext(req, next);
|
|
1639
|
+
} catch {
|
|
1640
|
+
wrapped = next;
|
|
1641
|
+
}
|
|
1642
|
+
return handleRequest.call(this, req, res, wrapped);
|
|
1643
|
+
};
|
|
1644
|
+
target[errorName] = function autterHandleError(error, req, res, next) {
|
|
1645
|
+
let wrapped = next;
|
|
1646
|
+
try {
|
|
1647
|
+
noteExpressError(req, error);
|
|
1648
|
+
wrapped = wrapNext(req, next);
|
|
1649
|
+
} catch {
|
|
1650
|
+
wrapped = next;
|
|
1651
|
+
}
|
|
1652
|
+
return handleError.call(this, error, req, res, wrapped);
|
|
1653
|
+
};
|
|
1654
|
+
try {
|
|
1655
|
+
Object.defineProperty(target, PATCHED, { value: true });
|
|
1656
|
+
} catch {
|
|
1657
|
+
target[PATCHED] = true;
|
|
1658
|
+
}
|
|
1659
|
+
return true;
|
|
1660
|
+
}
|
|
1661
|
+
var LAYER_FILES = ["express/lib/router/layer.js", "router/lib/layer.js"];
|
|
1662
|
+
function patchLayerModule(exports) {
|
|
1663
|
+
try {
|
|
1664
|
+
const Layer = exports;
|
|
1665
|
+
if (typeof Layer === "function" && patchLayerPrototype(Layer.prototype))
|
|
1666
|
+
debugLog("express: error capture installed");
|
|
1667
|
+
} catch {
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
function scanModuleCache() {
|
|
1671
|
+
try {
|
|
1672
|
+
const cache = createRequire(join(process.cwd(), "autter-runtime-express.cjs")).cache;
|
|
1673
|
+
for (const [key, entry] of Object.entries(cache)) {
|
|
1674
|
+
const path = key.replace(/\\/g, "/");
|
|
1675
|
+
if (LAYER_FILES.some((file) => path.endsWith(`/node_modules/${file}`)))
|
|
1676
|
+
patchLayerModule(entry?.exports);
|
|
1677
|
+
}
|
|
1678
|
+
} catch {
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
var installed = false;
|
|
1682
|
+
function installExpressErrorCapture() {
|
|
1683
|
+
if (installed) return;
|
|
1684
|
+
installed = true;
|
|
1685
|
+
scanModuleCache();
|
|
1686
|
+
try {
|
|
1687
|
+
new Hook(["express", "router"], { internals: true }, (exports, name) => {
|
|
1688
|
+
const file = name.replace(/\\/g, "/");
|
|
1689
|
+
if (LAYER_FILES.includes(file)) patchLayerModule(exports);
|
|
1690
|
+
return exports;
|
|
1691
|
+
});
|
|
1692
|
+
} catch {
|
|
1693
|
+
}
|
|
1694
|
+
}
|
|
1695
|
+
function patchFromRequest(req) {
|
|
1696
|
+
try {
|
|
1697
|
+
const app = req?.app;
|
|
1698
|
+
if (!app || typeof app !== "function" && typeof app !== "object") return;
|
|
1699
|
+
const router = app._router ?? app.router;
|
|
1700
|
+
const layer = router?.stack?.[0];
|
|
1701
|
+
if (layer && typeof layer === "object" && patchLayerPrototype(Object.getPrototypeOf(layer)))
|
|
1702
|
+
debugLog("express: error capture installed (from a request)");
|
|
1703
|
+
} catch {
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
function declaredStatus(error) {
|
|
1707
|
+
if (!error || typeof error !== "object") return void 0;
|
|
1708
|
+
try {
|
|
1709
|
+
const value = error.status ?? error.statusCode;
|
|
1710
|
+
const status = typeof value === "string" ? Number(value) : value;
|
|
1711
|
+
return typeof status === "number" && Number.isInteger(status) && status >= 400 && status < 600 ? status : void 0;
|
|
1712
|
+
} catch {
|
|
1713
|
+
return void 0;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
function watchExpressResponse(span, res, enabled) {
|
|
1717
|
+
const req = res.req;
|
|
1718
|
+
if (!req) return;
|
|
1719
|
+
const ctx = context2.active();
|
|
1720
|
+
let done = false;
|
|
1721
|
+
const settle = (finished) => {
|
|
1722
|
+
if (done) return;
|
|
1723
|
+
done = true;
|
|
1724
|
+
try {
|
|
1725
|
+
const errors = req[ERRORS];
|
|
1726
|
+
if (!errors?.length) {
|
|
1727
|
+
patchFromRequest(req);
|
|
1728
|
+
return;
|
|
1729
|
+
}
|
|
1730
|
+
req[ERRORS] = void 0;
|
|
1731
|
+
if (!enabled()) return;
|
|
1732
|
+
if (finished && !(res.statusCode >= 500)) return;
|
|
1733
|
+
if (errors.some((error2) => isCaptured(error2))) return;
|
|
1734
|
+
const error = errors.find((candidate) => {
|
|
1735
|
+
const status = declaredStatus(candidate);
|
|
1736
|
+
return status === void 0 || status >= 500;
|
|
1737
|
+
});
|
|
1738
|
+
if (error === void 0) return;
|
|
1739
|
+
const state = requestStateOf(req);
|
|
1740
|
+
if (state && !state.sealed) noteOperationError(error, false, state);
|
|
1741
|
+
const run = () => captureAtBoundary(error, state, true);
|
|
1742
|
+
if (span.isRecording()) context2.with(trace2.setSpan(ctx, span), run);
|
|
1743
|
+
else context2.with(ctx, run);
|
|
1744
|
+
} catch {
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
try {
|
|
1748
|
+
res.prependListener("finish", () => settle(true));
|
|
1749
|
+
res.prependListener("close", () => settle(false));
|
|
1750
|
+
} catch {
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1406
1754
|
// src/route-label.ts
|
|
1407
1755
|
import { getRPCMetadata as getRPCMetadata2, RPCType as RPCType2 } from "@opentelemetry/core";
|
|
1408
1756
|
var ours = /* @__PURE__ */ new WeakMap();
|
|
@@ -1574,7 +1922,7 @@ var ErrorTraceRetentionProcessor = class {
|
|
|
1574
1922
|
}
|
|
1575
1923
|
/** Promote the active trace, if any — called on captured errors. */
|
|
1576
1924
|
retainActiveTrace() {
|
|
1577
|
-
const active =
|
|
1925
|
+
const active = trace3.getActiveSpan()?.spanContext();
|
|
1578
1926
|
if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return;
|
|
1579
1927
|
const entry = this.entryFor(active.traceId);
|
|
1580
1928
|
if (entry.retained) return;
|
|
@@ -1687,8 +2035,8 @@ async function runLlmSpan(tracer, info, fn) {
|
|
|
1687
2035
|
setAttributes: (attributes) => span.setAttributes(S.redactor(attributes))
|
|
1688
2036
|
};
|
|
1689
2037
|
try {
|
|
1690
|
-
const result = await
|
|
1691
|
-
|
|
2038
|
+
const result = await context3.with(
|
|
2039
|
+
trace3.setSpan(context3.active(), span),
|
|
1692
2040
|
() => fn(handle)
|
|
1693
2041
|
);
|
|
1694
2042
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -1731,8 +2079,8 @@ async function runWithSpan(tracer, name, fn, attributes, links) {
|
|
|
1731
2079
|
...links?.length ? { links } : {}
|
|
1732
2080
|
});
|
|
1733
2081
|
try {
|
|
1734
|
-
const result = await
|
|
1735
|
-
|
|
2082
|
+
const result = await context3.with(
|
|
2083
|
+
trace3.setSpan(context3.active(), span),
|
|
1736
2084
|
fn
|
|
1737
2085
|
);
|
|
1738
2086
|
span.setStatus({ code: SpanStatusCode.OK });
|
|
@@ -1762,7 +2110,7 @@ function redactWithActive(attributes) {
|
|
|
1762
2110
|
}
|
|
1763
2111
|
function patchLoadedHttpModules() {
|
|
1764
2112
|
try {
|
|
1765
|
-
const load =
|
|
2113
|
+
const load = createRequire2(join2(process.cwd(), "autter-runtime-http.cjs"));
|
|
1766
2114
|
load("http");
|
|
1767
2115
|
load("https");
|
|
1768
2116
|
} catch {
|
|
@@ -1771,7 +2119,7 @@ function patchLoadedHttpModules() {
|
|
|
1771
2119
|
var METRIC_ROUTE_ATTR = "autter.metric_has_route";
|
|
1772
2120
|
function captureRequestRoute(span, response) {
|
|
1773
2121
|
if (!(response instanceof ServerResponse)) return;
|
|
1774
|
-
const rpcMetadata = getRPCMetadata3(
|
|
2122
|
+
const rpcMetadata = getRPCMetadata3(context3.active());
|
|
1775
2123
|
if (rpcMetadata?.type !== RPCType3.HTTP) return;
|
|
1776
2124
|
let failed = false;
|
|
1777
2125
|
response.on(errorMonitor, () => {
|
|
@@ -1787,6 +2135,7 @@ function captureRequestRoute(span, response) {
|
|
|
1787
2135
|
setRoute();
|
|
1788
2136
|
if (rpcMetadata.route && !failed) span.setAttribute(METRIC_ROUTE_ATTR, true);
|
|
1789
2137
|
});
|
|
2138
|
+
if (S.expressErrors) watchExpressResponse(span, response, () => S.expressErrors === true);
|
|
1790
2139
|
if (S.hookRequests) startHookRequest(response);
|
|
1791
2140
|
}
|
|
1792
2141
|
function structuredErrorAttributes(error) {
|
|
@@ -1808,12 +2157,14 @@ function initAutterServer(options) {
|
|
|
1808
2157
|
/\/$/,
|
|
1809
2158
|
""
|
|
1810
2159
|
);
|
|
1811
|
-
const
|
|
2160
|
+
const apiKey = resolveIngestKey(options.apiKey);
|
|
2161
|
+
const headers = authHeaders(apiKey);
|
|
2162
|
+
const ingestTarget = { endpoint, hasKey: apiKey !== null };
|
|
1812
2163
|
const redactor = makeRedactor(options.redactAttributes ?? true);
|
|
1813
2164
|
const queryPolicy = makeUrlQueryPolicy(options.keepQueryParams);
|
|
1814
2165
|
const traceExporter = () => new CountingExporter(
|
|
1815
2166
|
new RedactingSpanExporter(
|
|
1816
|
-
new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }),
|
|
2167
|
+
new IngestSpanExporter(new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }), ingestTarget),
|
|
1817
2168
|
() => redactor,
|
|
1818
2169
|
queryPolicy
|
|
1819
2170
|
)
|
|
@@ -1821,6 +2172,8 @@ function initAutterServer(options) {
|
|
|
1821
2172
|
const environment = options.environment ?? process.env.NODE_ENV ?? "production";
|
|
1822
2173
|
if (isDebugEnabled() || options.debug === true) setDebugMode(true);
|
|
1823
2174
|
debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
|
|
2175
|
+
if (apiKey === null) warnMissingKey("server", options.service);
|
|
2176
|
+
else warnKeyKind(apiKey);
|
|
1824
2177
|
S.redactor = redactor;
|
|
1825
2178
|
const distro = options.distro ?? SDK_IDENTITY;
|
|
1826
2179
|
configureCompatCheck({ endpoint, enabled: options.compatCheck !== false, sdk: distro });
|
|
@@ -1869,7 +2222,7 @@ function initAutterServer(options) {
|
|
|
1869
2222
|
const mainSpanProcessor = new BatchSpanProcessor(traceExporter());
|
|
1870
2223
|
const metricReader = new PeriodicExportingMetricReader({
|
|
1871
2224
|
exporter: new RedactingMetricExporter(
|
|
1872
|
-
new OTLPMetricExporter({
|
|
2225
|
+
new IngestMetricExporter(new OTLPMetricExporter({
|
|
1873
2226
|
url: `${endpoint}/v1/metrics`,
|
|
1874
2227
|
headers,
|
|
1875
2228
|
// Deltas, not lifetime totals: the ingester SUMs data points
|
|
@@ -1877,7 +2230,7 @@ function initAutterServer(options) {
|
|
|
1877
2230
|
// temporality would re-count every past request on each
|
|
1878
2231
|
// 60 s export.
|
|
1879
2232
|
temporalityPreference: AggregationTemporalityPreference.DELTA
|
|
1880
|
-
}),
|
|
2233
|
+
}), ingestTarget),
|
|
1881
2234
|
() => redactor
|
|
1882
2235
|
),
|
|
1883
2236
|
exportIntervalMillis: options.metricIntervalMs ?? 6e4
|
|
@@ -1939,9 +2292,11 @@ function initAutterServer(options) {
|
|
|
1939
2292
|
const fingerprint = fingerprintEventAttributes(split.fingerprint, redactor.text);
|
|
1940
2293
|
if (fingerprint["autter.fingerprint"]) noteCompatFeature("fingerprint_override");
|
|
1941
2294
|
const redacted = redactor(split.attributes);
|
|
1942
|
-
const
|
|
1943
|
-
const
|
|
2295
|
+
const crash = attributes?.["autter.unhandled"] === true;
|
|
2296
|
+
const activeSpan = trace3.getActiveSpan();
|
|
2297
|
+
const reuseActive = !crash && activeSpan?.isRecording() === true;
|
|
1944
2298
|
const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
|
|
2299
|
+
const scope = reuseActive ? void 0 : requestScopeAttributes();
|
|
1945
2300
|
const structured = structuredErrorAttributes(error);
|
|
1946
2301
|
const causes = errorAttributes(error);
|
|
1947
2302
|
const declared = {
|
|
@@ -1950,6 +2305,7 @@ function initAutterServer(options) {
|
|
|
1950
2305
|
};
|
|
1951
2306
|
const requestId = currentOperation()?.requestId;
|
|
1952
2307
|
span.setAttributes({
|
|
2308
|
+
...scope,
|
|
1953
2309
|
"autter.severity": "error",
|
|
1954
2310
|
...redacted,
|
|
1955
2311
|
...structured,
|
|
@@ -2006,7 +2362,7 @@ function initAutterServer(options) {
|
|
|
2006
2362
|
if (!errorFilter({ type: "OutcomeFailure", message: `${name}: ${message}` })) return;
|
|
2007
2363
|
errorTraceBuffer?.retainActiveTrace();
|
|
2008
2364
|
telemetryStats.markCaptured();
|
|
2009
|
-
const activeSpan =
|
|
2365
|
+
const activeSpan = trace3.getActiveSpan();
|
|
2010
2366
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
2011
2367
|
const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
|
|
2012
2368
|
const safeOutcome = redactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
@@ -2035,7 +2391,7 @@ function initAutterServer(options) {
|
|
|
2035
2391
|
const split = splitFingerprint(attributes);
|
|
2036
2392
|
const fingerprint = fingerprintEventAttributes(split.fingerprint, redactor.text);
|
|
2037
2393
|
const redacted = redactor(split.attributes);
|
|
2038
|
-
const activeSpan =
|
|
2394
|
+
const activeSpan = trace3.getActiveSpan();
|
|
2039
2395
|
const reuseActive = activeSpan?.isRecording() === true;
|
|
2040
2396
|
const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
|
|
2041
2397
|
markCaptured(error);
|
|
@@ -2054,7 +2410,7 @@ function initAutterServer(options) {
|
|
|
2054
2410
|
}
|
|
2055
2411
|
configureRuntimeLogger({
|
|
2056
2412
|
endpoint,
|
|
2057
|
-
apiKey:
|
|
2413
|
+
apiKey: apiKey ?? "",
|
|
2058
2414
|
service: options.service,
|
|
2059
2415
|
environment,
|
|
2060
2416
|
distro,
|
|
@@ -2065,6 +2421,8 @@ function initAutterServer(options) {
|
|
|
2065
2421
|
reportOutcome: reportOutcome2
|
|
2066
2422
|
});
|
|
2067
2423
|
S.hookRequests = options.logging?.requests === true;
|
|
2424
|
+
S.expressErrors = options.captureExpressErrors !== false;
|
|
2425
|
+
if (S.expressErrors) installExpressErrorCapture();
|
|
2068
2426
|
S.handled = captureHandled;
|
|
2069
2427
|
startLoggedErrorCapture(options.captureLoggedErrors);
|
|
2070
2428
|
let onCrash = null;
|
|
@@ -2123,6 +2481,7 @@ function initAutterServer(options) {
|
|
|
2123
2481
|
S.alwaysOnProvider = null;
|
|
2124
2482
|
S.handled = null;
|
|
2125
2483
|
S.hookRequests = false;
|
|
2484
|
+
S.expressErrors = false;
|
|
2126
2485
|
S.redactor = makeRedactor(true);
|
|
2127
2486
|
}
|
|
2128
2487
|
autoFlushHandle?.dispose();
|
|
@@ -2151,7 +2510,7 @@ function captureException(error, attributes) {
|
|
|
2151
2510
|
const split = splitFingerprint(attributes);
|
|
2152
2511
|
const fingerprint = fingerprintEventAttributes(split.fingerprint, S.redactor.text);
|
|
2153
2512
|
notifyException(error, { ...split.attributes, ...fingerprint });
|
|
2154
|
-
const span =
|
|
2513
|
+
const span = trace3.getTracer("autter-errors").startSpan(isError(error) ? error.name : "Error", {
|
|
2155
2514
|
attributes: { ...S.redactor(split.attributes), ...fingerprint }
|
|
2156
2515
|
});
|
|
2157
2516
|
recordError(span, error);
|
|
@@ -2173,7 +2532,7 @@ function captureHandledError(error, attributes, severity) {
|
|
|
2173
2532
|
markCaptured(error);
|
|
2174
2533
|
const split = splitFingerprint(attributes);
|
|
2175
2534
|
notifyException(error, { ...split.attributes, "autter.severity": severity });
|
|
2176
|
-
const span =
|
|
2535
|
+
const span = trace3.getTracer("autter-errors").startSpan(isError(error) ? error.name : "Error");
|
|
2177
2536
|
span.addEvent("exception", {
|
|
2178
2537
|
...S.redactor(split.attributes),
|
|
2179
2538
|
"exception.type": isError(error) ? error.name : "Error",
|
|
@@ -2191,13 +2550,13 @@ function serverActive() {
|
|
|
2191
2550
|
setRequestExceptionCapturer((error, attributes) => captureException(error, attributes));
|
|
2192
2551
|
setHandledCapture(captureHandledError);
|
|
2193
2552
|
setRequestSpanAnnotator((attributes) => {
|
|
2194
|
-
const span =
|
|
2553
|
+
const span = trace3.getActiveSpan();
|
|
2195
2554
|
if (span?.isRecording()) span.setAttributes(S.redactor(splitFingerprint(attributes).attributes));
|
|
2196
2555
|
});
|
|
2197
2556
|
function withProcessSpan(name, fn, attributes) {
|
|
2198
2557
|
if (S.active) return S.active.withProcessSpan(name, fn, attributes);
|
|
2199
2558
|
return runWithSpan(
|
|
2200
|
-
|
|
2559
|
+
trace3.getTracer("autter-processes"),
|
|
2201
2560
|
name,
|
|
2202
2561
|
fn,
|
|
2203
2562
|
S.redactor(attributes)
|
|
@@ -2205,14 +2564,14 @@ function withProcessSpan(name, fn, attributes) {
|
|
|
2205
2564
|
}
|
|
2206
2565
|
function withLlmCall(info, fn) {
|
|
2207
2566
|
if (S.active) return S.active.withLlmCall(info, fn);
|
|
2208
|
-
return runLlmSpan(
|
|
2567
|
+
return runLlmSpan(trace3.getTracer("autter-llm"), info, fn);
|
|
2209
2568
|
}
|
|
2210
2569
|
function trackLlmCall(call) {
|
|
2211
2570
|
if (S.active) {
|
|
2212
2571
|
S.active.trackLlmCall(call);
|
|
2213
2572
|
return;
|
|
2214
2573
|
}
|
|
2215
|
-
recordLlmCall(
|
|
2574
|
+
recordLlmCall(trace3.getTracer("autter-llm"), call);
|
|
2216
2575
|
}
|
|
2217
2576
|
function captureMessage(message, severity = "warning", attributes) {
|
|
2218
2577
|
if (S.active) {
|
|
@@ -2220,7 +2579,7 @@ function captureMessage(message, severity = "warning", attributes) {
|
|
|
2220
2579
|
return;
|
|
2221
2580
|
}
|
|
2222
2581
|
const safeMessage = S.redactor.text(message);
|
|
2223
|
-
const span =
|
|
2582
|
+
const span = trace3.getTracer("autter-errors").startSpan("Message", {
|
|
2224
2583
|
attributes: { "autter.severity": severity, ...S.redactor(attributes) }
|
|
2225
2584
|
});
|
|
2226
2585
|
span.addEvent("exception", {
|
|
@@ -2234,7 +2593,7 @@ function captureMessage(message, severity = "warning", attributes) {
|
|
|
2234
2593
|
}
|
|
2235
2594
|
function reportOutcome(name, message, attributes) {
|
|
2236
2595
|
if (S.active) return S.active.reportOutcome(name, message, attributes);
|
|
2237
|
-
const span =
|
|
2596
|
+
const span = trace3.getTracer("autter-outcomes").startSpan("OutcomeFailure");
|
|
2238
2597
|
const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
|
|
2239
2598
|
const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
|
|
2240
2599
|
const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
|
|
@@ -2255,7 +2614,7 @@ function makeSafeCapture(options) {
|
|
|
2255
2614
|
};
|
|
2256
2615
|
}
|
|
2257
2616
|
function alwaysOnTracer(name) {
|
|
2258
|
-
return S.alwaysOnProvider ? S.alwaysOnProvider.getTracer(name) :
|
|
2617
|
+
return S.alwaysOnProvider ? S.alwaysOnProvider.getTracer(name) : trace3.getTracer(name);
|
|
2259
2618
|
}
|
|
2260
2619
|
function autterLlmTracer() {
|
|
2261
2620
|
return alwaysOnTracer("autter-llm");
|
|
@@ -2275,7 +2634,7 @@ async function emitLlmSelftestTrace() {
|
|
|
2275
2634
|
attributes: { "autter.selftest": true }
|
|
2276
2635
|
},
|
|
2277
2636
|
(llm) => {
|
|
2278
|
-
traceId =
|
|
2637
|
+
traceId = trace3.getActiveSpan()?.spanContext().traceId ?? "";
|
|
2279
2638
|
llm.setUsage({ inputTokens: 1, outputTokens: 1 });
|
|
2280
2639
|
llm.setCost(0);
|
|
2281
2640
|
}
|
|
@@ -2596,7 +2955,7 @@ function autterKoa(options = {}) {
|
|
|
2596
2955
|
// src/logging-only.ts
|
|
2597
2956
|
import {
|
|
2598
2957
|
SpanStatusCode as SpanStatusCode3,
|
|
2599
|
-
trace as
|
|
2958
|
+
trace as trace4
|
|
2600
2959
|
} from "@opentelemetry/api";
|
|
2601
2960
|
var L = sharedSlot("logging", () => ({ active: null }));
|
|
2602
2961
|
function initAutterLogging(options) {
|
|
@@ -2631,7 +2990,7 @@ function initAutterLogging(options) {
|
|
|
2631
2990
|
const split = splitFingerprint(attributes);
|
|
2632
2991
|
const fingerprint = fingerprintEventAttributes(split.fingerprint, redact.text);
|
|
2633
2992
|
const redacted = redact(split.attributes);
|
|
2634
|
-
const span =
|
|
2993
|
+
const span = trace4.getActiveSpan();
|
|
2635
2994
|
if (mode === "auto" && span?.isRecording()) {
|
|
2636
2995
|
noteOperationError(error);
|
|
2637
2996
|
notifyException(error, { ...redacted, ...fingerprint });
|
|
@@ -2672,7 +3031,7 @@ function initAutterLogging(options) {
|
|
|
2672
3031
|
const fingerprint = fingerprintEventAttributes(split.fingerprint, redact.text);
|
|
2673
3032
|
const redacted = redact(split.attributes);
|
|
2674
3033
|
notifyException(error, { ...redacted, ...fingerprint, "autter.severity": severity });
|
|
2675
|
-
const span =
|
|
3034
|
+
const span = trace4.getActiveSpan();
|
|
2676
3035
|
if (mode === "auto" && span?.isRecording()) {
|
|
2677
3036
|
span.addEvent("exception", {
|
|
2678
3037
|
...redacted,
|
|
@@ -2690,7 +3049,9 @@ function initAutterLogging(options) {
|
|
|
2690
3049
|
const captured = /* @__PURE__ */ new WeakSet();
|
|
2691
3050
|
configureRuntimeLogger({
|
|
2692
3051
|
endpoint,
|
|
2693
|
-
|
|
3052
|
+
// Normalised ("undefined"/empty is no key), no env fallback: without
|
|
3053
|
+
// an apiKey this mode logs locally only, by design.
|
|
3054
|
+
apiKey: resolveIngestKey(options.apiKey, {}) ?? "",
|
|
2694
3055
|
service: options.service,
|
|
2695
3056
|
environment,
|
|
2696
3057
|
...options.release ? { release: options.release } : {},
|
|
@@ -2850,6 +3211,7 @@ export {
|
|
|
2850
3211
|
captureException,
|
|
2851
3212
|
captureMessage,
|
|
2852
3213
|
captureRequestError,
|
|
3214
|
+
checkBrowserPayload,
|
|
2853
3215
|
consoleSink,
|
|
2854
3216
|
createBrowserRelayFetchHandler,
|
|
2855
3217
|
createBrowserRelayHandler,
|
|
@@ -2877,6 +3239,7 @@ export {
|
|
|
2877
3239
|
reportOutcome,
|
|
2878
3240
|
runDoctor,
|
|
2879
3241
|
runInBackground,
|
|
3242
|
+
runVerify,
|
|
2880
3243
|
runtimeContext,
|
|
2881
3244
|
runtimeLogStats,
|
|
2882
3245
|
runtimeLogger,
|