@autter/runtime-node 1.5.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 +139 -1
- package/dist/{chunk-GI47WGRR.cjs → chunk-4MVWIRBI.cjs} +120 -39
- package/dist/{chunk-3TJHUCZ6.js → chunk-5KISVAVB.js} +326 -54
- package/dist/{chunk-L6SRL65J.cjs → chunk-7OTD2YPT.cjs} +11 -11
- package/dist/{chunk-L7HWKMCZ.js → chunk-HRDELHZP.js} +112 -31
- package/dist/{chunk-ZS4WQJQR.js → chunk-L5ENELB2.js} +1 -1
- package/dist/{chunk-P4VRTFAV.cjs → chunk-UXTIMS3G.cjs} +353 -81
- package/dist/cli.cjs +29 -9
- package/dist/cli.js +22 -2
- package/dist/index.cjs +668 -272
- package/dist/index.d.cts +160 -7
- package/dist/index.d.ts +160 -7
- package/dist/index.js +529 -133
- package/dist/{sinks-RFV76lF1.d.cts → sinks-CPGDyfU8.d.cts} +29 -1
- package/dist/{sinks-RFV76lF1.d.ts → sinks-CPGDyfU8.d.ts} +29 -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 +3 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
noteCompatFeature,
|
|
3
|
-
observeIngesterResponse
|
|
4
|
-
|
|
3
|
+
observeIngesterResponse,
|
|
4
|
+
sharedSlot
|
|
5
|
+
} from "./chunk-HRDELHZP.js";
|
|
5
6
|
|
|
6
7
|
// ../runtime-core/dist/index.js
|
|
7
8
|
var SENSITIVE_KEY_PATTERNS = [
|
|
@@ -327,8 +328,8 @@ function priority(key) {
|
|
|
327
328
|
if (/^(?:exception|autter\.error)\./.test(key)) return 1;
|
|
328
329
|
return 0;
|
|
329
330
|
}
|
|
330
|
-
function boundContext(attributes = {},
|
|
331
|
-
const redacted =
|
|
331
|
+
function boundContext(attributes = {}, redact3) {
|
|
332
|
+
const redacted = redact3 ? redact3(attributes) : redactAttributes(attributes);
|
|
332
333
|
let budget = 512;
|
|
333
334
|
let characters = 16384;
|
|
334
335
|
let truncated = false;
|
|
@@ -365,14 +366,14 @@ function boundContext(attributes = {}, redact2) {
|
|
|
365
366
|
if (truncated) result["autter.context.truncated"] = true;
|
|
366
367
|
return result;
|
|
367
368
|
}
|
|
368
|
-
function userContext(attributes = {},
|
|
369
|
+
function userContext(attributes = {}, redact3) {
|
|
369
370
|
return Object.fromEntries(
|
|
370
|
-
Object.entries(boundContext(attributes,
|
|
371
|
+
Object.entries(boundContext(attributes, redact3)).filter(
|
|
371
372
|
([key]) => !RESERVED_KEY.test(key)
|
|
372
373
|
)
|
|
373
374
|
);
|
|
374
375
|
}
|
|
375
|
-
function mergeContext(current, next = {},
|
|
376
|
+
function mergeContext(current, next = {}, redact3) {
|
|
376
377
|
const merge2 = (left, right, depth) => {
|
|
377
378
|
const result = { ...left };
|
|
378
379
|
for (const [key, value] of Object.entries(right)) {
|
|
@@ -381,7 +382,7 @@ function mergeContext(current, next = {}, redact2) {
|
|
|
381
382
|
}
|
|
382
383
|
return result;
|
|
383
384
|
};
|
|
384
|
-
return userContext(merge2(current, userContext(next,
|
|
385
|
+
return userContext(merge2(current, userContext(next, redact3), 0), redact3);
|
|
385
386
|
}
|
|
386
387
|
function toSpanAttributes(context) {
|
|
387
388
|
return Object.fromEntries(
|
|
@@ -473,6 +474,17 @@ function defineRuntimeErrors(namespace, catalog) {
|
|
|
473
474
|
}
|
|
474
475
|
return out;
|
|
475
476
|
}
|
|
477
|
+
function isError(value) {
|
|
478
|
+
if (!value || typeof value !== "object") return false;
|
|
479
|
+
try {
|
|
480
|
+
if (value instanceof Error) return true;
|
|
481
|
+
const native = Error.isError;
|
|
482
|
+
if (typeof native === "function") return native(value) === true;
|
|
483
|
+
return Object.prototype.toString.call(value) === "[object Error]";
|
|
484
|
+
} catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
476
488
|
function isRuntimeErrorLike(err) {
|
|
477
489
|
if (err instanceof RuntimeError) return true;
|
|
478
490
|
if (!err || typeof err !== "object") return false;
|
|
@@ -523,15 +535,15 @@ function errorAttributes(err, options = {}) {
|
|
|
523
535
|
for (let n = 1; n <= CAUSE_DEPTH && cause !== void 0 && cause !== null; n++) {
|
|
524
536
|
if (seen.has(cause)) break;
|
|
525
537
|
seen.add(cause);
|
|
526
|
-
const
|
|
527
|
-
const type =
|
|
528
|
-
const message =
|
|
538
|
+
const isError2 = typeof cause === "object";
|
|
539
|
+
const type = isError2 ? String(field(cause, "name") ?? cause.constructor?.name ?? "Error") : typeof cause;
|
|
540
|
+
const message = isError2 ? field(cause, "message") : cause;
|
|
529
541
|
out[`exception.cause.${n}.type`] = type.slice(0, 200);
|
|
530
542
|
out[`exception.cause.${n}.message`] = String(message ?? "").slice(0, 1e3);
|
|
531
543
|
const causeCode = field(cause, "code");
|
|
532
544
|
if (typeof causeCode === "string" && causeCode)
|
|
533
545
|
out[`exception.cause.${n}.code`] = causeCode.slice(0, CODE_MAX_LENGTH);
|
|
534
|
-
cause =
|
|
546
|
+
cause = isError2 ? field(cause, "cause") : void 0;
|
|
535
547
|
}
|
|
536
548
|
}
|
|
537
549
|
return out;
|
|
@@ -577,19 +589,19 @@ function createInlineLogState(startedAt) {
|
|
|
577
589
|
level: "info"
|
|
578
590
|
};
|
|
579
591
|
}
|
|
580
|
-
function appendInlineLog(state, level, message, attrs,
|
|
592
|
+
function appendInlineLog(state, level, message, attrs, redact3, now = Date.now()) {
|
|
581
593
|
state.level = maxLevel(state.level, level);
|
|
582
594
|
if (state.logs.length >= INLINE_LOG_LIMIT) {
|
|
583
595
|
state.logsTruncated = true;
|
|
584
596
|
return;
|
|
585
597
|
}
|
|
586
|
-
const text = String(boundContext({ message },
|
|
598
|
+
const text = String(boundContext({ message }, redact3).message ?? "").slice(
|
|
587
599
|
0,
|
|
588
600
|
INLINE_MESSAGE_MAX
|
|
589
601
|
);
|
|
590
602
|
let small;
|
|
591
603
|
if (attrs && Object.keys(attrs).length) {
|
|
592
|
-
small = boundContext(attrs,
|
|
604
|
+
small = boundContext(attrs, redact3);
|
|
593
605
|
const encoded = JSON.stringify(small);
|
|
594
606
|
if (encoded.length > 1e3) small = { "autter.context.truncated": true };
|
|
595
607
|
}
|
|
@@ -806,6 +818,172 @@ function parseUserAgent(ua) {
|
|
|
806
818
|
const device = !value ? "unknown" : bot ? "bot" : /iPad|Tablet/.test(value) || /Android/.test(value) && !/Mobile/.test(value) ? "tablet" : /Mobi|iPhone|iPod|Android/.test(value) ? "mobile" : "desktop";
|
|
807
819
|
return { browser, os, device, bot };
|
|
808
820
|
}
|
|
821
|
+
var BREADCRUMBS_ATTRIBUTE = "autter.breadcrumbs";
|
|
822
|
+
var MAX_BREADCRUMBS = 30;
|
|
823
|
+
var MAX_MESSAGE = 500;
|
|
824
|
+
var MAX_DATA_KEYS = 10;
|
|
825
|
+
var MAX_DATA_STRING = 200;
|
|
826
|
+
var BREADCRUMBS_ATTRIBUTE_MAX_CHARS = 16 * 1024;
|
|
827
|
+
var MASK = "[redacted]";
|
|
828
|
+
var TYPES = /* @__PURE__ */ new Set(["console", "request", "navigation", "click", "log", "custom"]);
|
|
829
|
+
var LEVELS = {
|
|
830
|
+
debug: "debug",
|
|
831
|
+
trace: "debug",
|
|
832
|
+
info: "info",
|
|
833
|
+
log: "info",
|
|
834
|
+
warning: "warning",
|
|
835
|
+
warn: "warning",
|
|
836
|
+
error: "error",
|
|
837
|
+
fatal: "error"
|
|
838
|
+
};
|
|
839
|
+
var UNSAFE_KEY = /^(?:__proto__|constructor|prototype)$/;
|
|
840
|
+
function scrubber(redact3) {
|
|
841
|
+
return (value, max) => {
|
|
842
|
+
const scrubbed = redact3({ message: value.slice(0, max + 512) }).message;
|
|
843
|
+
return stripUrlQueries(typeof scrubbed === "string" ? scrubbed : "").slice(0, max);
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function cleanData(raw, redact3) {
|
|
847
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return void 0;
|
|
848
|
+
const picked = {};
|
|
849
|
+
let count = 0;
|
|
850
|
+
for (const key of Object.keys(raw).slice(0, 64)) {
|
|
851
|
+
if (count >= MAX_DATA_KEYS) break;
|
|
852
|
+
if (!key || UNSAFE_KEY.test(key)) continue;
|
|
853
|
+
const value = raw[key];
|
|
854
|
+
const name = key.slice(0, 100);
|
|
855
|
+
if (typeof value === "string") {
|
|
856
|
+
const text = /(?:url|path|route|target)$/i.test(name) ? value.split(/[?#]/)[0] : value;
|
|
857
|
+
picked[name] = text.slice(0, MAX_DATA_STRING + 512);
|
|
858
|
+
} else if (typeof value === "number") {
|
|
859
|
+
if (!Number.isFinite(value)) continue;
|
|
860
|
+
picked[name] = value;
|
|
861
|
+
} else if (typeof value === "boolean" || value === null) {
|
|
862
|
+
picked[name] = value;
|
|
863
|
+
} else {
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
count++;
|
|
867
|
+
}
|
|
868
|
+
if (count === 0) return void 0;
|
|
869
|
+
const redacted = redact3(picked);
|
|
870
|
+
const out = {};
|
|
871
|
+
for (const key of Object.keys(picked)) {
|
|
872
|
+
const value = key in redacted ? redacted[key] : picked[key];
|
|
873
|
+
out[key] = typeof value === "string" ? stripUrlQueries(value).slice(0, MAX_DATA_STRING) : value;
|
|
874
|
+
}
|
|
875
|
+
return out;
|
|
876
|
+
}
|
|
877
|
+
function timestamp(value) {
|
|
878
|
+
if (value === void 0) return (/* @__PURE__ */ new Date()).toISOString();
|
|
879
|
+
if (typeof value !== "string" && typeof value !== "number" && !(value instanceof Date)) return null;
|
|
880
|
+
const at = new Date(value);
|
|
881
|
+
return Number.isNaN(at.getTime()) ? null : at.toISOString();
|
|
882
|
+
}
|
|
883
|
+
function normalizeBreadcrumb(input, redact3, options = {}) {
|
|
884
|
+
try {
|
|
885
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
886
|
+
const raw = input;
|
|
887
|
+
if (options.requireAt && raw.at === void 0) return null;
|
|
888
|
+
const at = timestamp(raw.at);
|
|
889
|
+
if (!at) return null;
|
|
890
|
+
const rawMessage = raw.message;
|
|
891
|
+
const message = typeof rawMessage === "string" ? rawMessage : typeof rawMessage === "number" || typeof rawMessage === "boolean" ? String(rawMessage) : "";
|
|
892
|
+
const data = cleanData(raw.data, redact3);
|
|
893
|
+
if (!message && !data) return null;
|
|
894
|
+
const type = typeof raw.type === "string" && TYPES.has(raw.type) ? raw.type : "custom";
|
|
895
|
+
const level = typeof raw.level === "string" ? LEVELS[raw.level.toLowerCase()] : void 0;
|
|
896
|
+
return {
|
|
897
|
+
type,
|
|
898
|
+
at,
|
|
899
|
+
...level ? { level } : {},
|
|
900
|
+
message: scrubber(redact3)(message, MAX_MESSAGE),
|
|
901
|
+
...data ? { data } : {}
|
|
902
|
+
};
|
|
903
|
+
} catch {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function sanitizeBreadcrumbs(raw, redact3) {
|
|
908
|
+
const out = [];
|
|
909
|
+
try {
|
|
910
|
+
if (!Array.isArray(raw)) return void 0;
|
|
911
|
+
const first = Math.max(0, raw.length - 200);
|
|
912
|
+
for (let i = raw.length - 1; i >= first && out.length < MAX_BREADCRUMBS; i--) {
|
|
913
|
+
const crumb = normalizeBreadcrumb(raw[i], redact3, { requireAt: true });
|
|
914
|
+
if (crumb) out.push(crumb);
|
|
915
|
+
}
|
|
916
|
+
} catch {
|
|
917
|
+
}
|
|
918
|
+
return out.length ? out.reverse() : void 0;
|
|
919
|
+
}
|
|
920
|
+
var BreadcrumbTrail = class {
|
|
921
|
+
constructor(max = MAX_BREADCRUMBS) {
|
|
922
|
+
this.max = max;
|
|
923
|
+
}
|
|
924
|
+
max;
|
|
925
|
+
items = [];
|
|
926
|
+
add(crumb) {
|
|
927
|
+
this.items.push(crumb);
|
|
928
|
+
if (this.items.length > this.max) this.items.splice(0, this.items.length - this.max);
|
|
929
|
+
}
|
|
930
|
+
/** Copies, oldest first. */
|
|
931
|
+
list() {
|
|
932
|
+
return this.items.map((crumb) => ({ ...crumb, ...crumb.data ? { data: { ...crumb.data } } : {} }));
|
|
933
|
+
}
|
|
934
|
+
get size() {
|
|
935
|
+
return this.items.length;
|
|
936
|
+
}
|
|
937
|
+
clear() {
|
|
938
|
+
this.items = [];
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
function breadcrumbsAttribute(list, scrub, maxChars = BREADCRUMBS_ATTRIBUTE_MAX_CHARS) {
|
|
942
|
+
const parts = [];
|
|
943
|
+
let chars = 2;
|
|
944
|
+
for (let i = list.length - 1; i >= 0 && parts.length < MAX_BREADCRUMBS; i--) {
|
|
945
|
+
const crumb = list[i];
|
|
946
|
+
let json = JSON.stringify(crumb);
|
|
947
|
+
if (scrub(json) !== json) {
|
|
948
|
+
json = JSON.stringify({ type: crumb.type, at: crumb.at, ...crumb.level ? { level: crumb.level } : {}, message: MASK });
|
|
949
|
+
}
|
|
950
|
+
if (chars + json.length + 1 > maxChars) break;
|
|
951
|
+
chars += json.length + 1;
|
|
952
|
+
parts.push(json);
|
|
953
|
+
}
|
|
954
|
+
if (parts.length === 0) return void 0;
|
|
955
|
+
const out = `[${parts.reverse().join(",")}]`;
|
|
956
|
+
return scrub(out) === out ? out : void 0;
|
|
957
|
+
}
|
|
958
|
+
var FINGERPRINT_ATTRIBUTE = "autter.fingerprint";
|
|
959
|
+
var FINGERPRINT_MAX_VALUES = 10;
|
|
960
|
+
var FINGERPRINT_MAX_LENGTH = 200;
|
|
961
|
+
function fingerprintValues(value, scrub = (text) => text) {
|
|
962
|
+
const list = Array.isArray(value) ? value : [value];
|
|
963
|
+
const values = list.filter((item) => typeof item === "string" && item !== "").slice(0, FINGERPRINT_MAX_VALUES).map((item) => scrub(item.slice(0, FINGERPRINT_MAX_LENGTH + 512)).slice(0, FINGERPRINT_MAX_LENGTH)).filter((item) => item !== "");
|
|
964
|
+
return values.length > 0 ? values : void 0;
|
|
965
|
+
}
|
|
966
|
+
function fingerprintEventAttributes(value, scrub) {
|
|
967
|
+
const values = fingerprintValues(value, scrub);
|
|
968
|
+
return values ? { [FINGERPRINT_ATTRIBUTE]: JSON.stringify(values) } : {};
|
|
969
|
+
}
|
|
970
|
+
function splitFingerprint(attributes) {
|
|
971
|
+
if (!attributes || typeof attributes !== "object" || !("fingerprint" in attributes)) {
|
|
972
|
+
return { attributes: attributes ?? void 0, fingerprint: void 0 };
|
|
973
|
+
}
|
|
974
|
+
const { fingerprint, ...rest } = attributes;
|
|
975
|
+
return { attributes: rest, fingerprint };
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// src/breadcrumbs.ts
|
|
979
|
+
import { trace as trace2 } from "@opentelemetry/api";
|
|
980
|
+
|
|
981
|
+
// src/logger.ts
|
|
982
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
983
|
+
import { randomUUID } from "crypto";
|
|
984
|
+
import {
|
|
985
|
+
trace
|
|
986
|
+
} from "@opentelemetry/api";
|
|
809
987
|
|
|
810
988
|
// src/sinks.ts
|
|
811
989
|
import {
|
|
@@ -816,7 +994,7 @@ import {
|
|
|
816
994
|
unlinkSync
|
|
817
995
|
} from "fs";
|
|
818
996
|
import { join, resolve } from "path";
|
|
819
|
-
var sinkStats = { dropped: 0 };
|
|
997
|
+
var sinkStats = sharedSlot("sinks", () => ({ dropped: 0 }));
|
|
820
998
|
function otlpSink(options = {}) {
|
|
821
999
|
let context = null;
|
|
822
1000
|
let queue = [];
|
|
@@ -1185,23 +1363,22 @@ function memorySink() {
|
|
|
1185
1363
|
}
|
|
1186
1364
|
|
|
1187
1365
|
// src/logger.ts
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
var
|
|
1195
|
-
var
|
|
1196
|
-
var extraSinks = /* @__PURE__ */ new Set();
|
|
1366
|
+
var shared = sharedSlot("logger", () => ({
|
|
1367
|
+
local: new AsyncLocalStorage(),
|
|
1368
|
+
config: null,
|
|
1369
|
+
sinks: [],
|
|
1370
|
+
extraSinks: /* @__PURE__ */ new Set()
|
|
1371
|
+
}));
|
|
1372
|
+
var local = shared.local;
|
|
1373
|
+
var extraSinks = shared.extraSinks;
|
|
1197
1374
|
var fallbackConsole = null;
|
|
1198
1375
|
function redact(attributes) {
|
|
1199
|
-
return config?.redact(attributes) ?? redactAttributes(attributes);
|
|
1376
|
+
return shared.config?.redact(attributes) ?? redactAttributes(attributes);
|
|
1200
1377
|
}
|
|
1201
1378
|
var safe = (attributes = {}) => boundContext(attributes, redact);
|
|
1202
1379
|
var merge = (current, next) => mergeContext(current, next, redact);
|
|
1203
1380
|
function activeSinks() {
|
|
1204
|
-
if (config) return extraSinks.size ? [...sinks, ...extraSinks] : sinks;
|
|
1381
|
+
if (shared.config) return extraSinks.size ? [...shared.sinks, ...extraSinks] : shared.sinks;
|
|
1205
1382
|
if (extraSinks.size) return [...extraSinks];
|
|
1206
1383
|
fallbackConsole ??= consoleSink();
|
|
1207
1384
|
return [fallbackConsole];
|
|
@@ -1237,9 +1414,10 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1237
1414
|
const state = options.state !== void 0 ? options.state ?? void 0 : local.getStore();
|
|
1238
1415
|
if (state?.sealed) return;
|
|
1239
1416
|
const summary = extra["autter.event.type"] === "operation";
|
|
1240
|
-
if (!summary
|
|
1417
|
+
if (!summary) recordLogBreadcrumb(level, message, attributes, state);
|
|
1418
|
+
if (!summary && LEVEL_SEVERITY[level] < LEVEL_SEVERITY[shared.config?.options?.minLevel ?? "debug"])
|
|
1241
1419
|
return;
|
|
1242
|
-
if (!summary && state && config?.options?.inline !== false) {
|
|
1420
|
+
if (!summary && state && shared.config?.options?.inline !== false) {
|
|
1243
1421
|
const { "exception.stacktrace": _stack, ...inlineAttrs } = userContext(
|
|
1244
1422
|
attributes,
|
|
1245
1423
|
redact
|
|
@@ -1259,7 +1437,7 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1259
1437
|
...operationAttributes(state),
|
|
1260
1438
|
...user
|
|
1261
1439
|
};
|
|
1262
|
-
const enrichers = config?.options?.enrich;
|
|
1440
|
+
const enrichers = shared.config?.options?.enrich;
|
|
1263
1441
|
if (summary && state && enrichers?.length) {
|
|
1264
1442
|
const event2 = { level, message, attributes: raw };
|
|
1265
1443
|
for (const enrich of enrichers) {
|
|
@@ -1287,9 +1465,9 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1287
1465
|
}
|
|
1288
1466
|
}
|
|
1289
1467
|
function configureRuntimeLogger(next) {
|
|
1290
|
-
config = next;
|
|
1291
|
-
sinks = defaultSinks(next);
|
|
1292
|
-
for (const sink of sinks) {
|
|
1468
|
+
shared.config = next;
|
|
1469
|
+
shared.sinks = defaultSinks(next);
|
|
1470
|
+
for (const sink of shared.sinks) {
|
|
1293
1471
|
try {
|
|
1294
1472
|
sink.start?.({
|
|
1295
1473
|
endpoint: next.endpoint,
|
|
@@ -1303,23 +1481,26 @@ function configureRuntimeLogger(next) {
|
|
|
1303
1481
|
}
|
|
1304
1482
|
}
|
|
1305
1483
|
}
|
|
1484
|
+
function loggerConfigured() {
|
|
1485
|
+
return shared.config;
|
|
1486
|
+
}
|
|
1306
1487
|
function addRuntimeSink(sink) {
|
|
1307
1488
|
extraSinks.add(sink);
|
|
1308
1489
|
return () => extraSinks.delete(sink);
|
|
1309
1490
|
}
|
|
1310
1491
|
function notifyException(error, attributes = {}) {
|
|
1311
|
-
if (!extraSinks.size && !sinks.some((sink) => sink.exception)) return;
|
|
1492
|
+
if (!extraSinks.size && !shared.sinks.some((sink) => sink.exception)) return;
|
|
1312
1493
|
const state = local.getStore();
|
|
1313
1494
|
const record = {
|
|
1314
1495
|
time: Date.now(),
|
|
1315
1496
|
error,
|
|
1316
|
-
message: error
|
|
1317
|
-
type: error
|
|
1497
|
+
message: isError(error) ? error.message : String(error),
|
|
1498
|
+
type: isError(error) ? error.name : "Error",
|
|
1318
1499
|
attributes: { ...attributes, ...errorAttributes(error) },
|
|
1319
1500
|
...state ? { operationId: state.id } : {},
|
|
1320
1501
|
...state?.requestId ? { requestId: state.requestId } : {}
|
|
1321
1502
|
};
|
|
1322
|
-
for (const sink of [...sinks, ...extraSinks]) {
|
|
1503
|
+
for (const sink of [...shared.sinks, ...extraSinks]) {
|
|
1323
1504
|
try {
|
|
1324
1505
|
sink.exception?.(record);
|
|
1325
1506
|
} catch {
|
|
@@ -1328,25 +1509,25 @@ function notifyException(error, attributes = {}) {
|
|
|
1328
1509
|
}
|
|
1329
1510
|
function runtimeLogStats() {
|
|
1330
1511
|
return {
|
|
1331
|
-
buffered: sinks.reduce((sum, sink) => sum + (sink.buffered?.() ?? 0), 0),
|
|
1512
|
+
buffered: shared.sinks.reduce((sum, sink) => sum + (sink.buffered?.() ?? 0), 0),
|
|
1332
1513
|
dropped: sinkStats.dropped
|
|
1333
1514
|
};
|
|
1334
1515
|
}
|
|
1335
1516
|
async function flushRuntimeLogs() {
|
|
1336
|
-
if (!config) return;
|
|
1517
|
+
if (!shared.config) return;
|
|
1337
1518
|
const results = await Promise.allSettled(
|
|
1338
|
-
sinks.map((sink) => Promise.resolve().then(() => sink.flush?.()))
|
|
1519
|
+
shared.sinks.map((sink) => Promise.resolve().then(() => sink.flush?.()))
|
|
1339
1520
|
);
|
|
1340
1521
|
const failed = results.find((result) => result.status === "rejected");
|
|
1341
1522
|
if (failed) throw failed.reason;
|
|
1342
1523
|
}
|
|
1343
1524
|
async function shutdownRuntimeLogger() {
|
|
1344
|
-
const active = sinks;
|
|
1525
|
+
const active = shared.sinks;
|
|
1345
1526
|
const results = await Promise.allSettled(
|
|
1346
1527
|
active.map((sink) => Promise.resolve().then(() => sink.shutdown?.()))
|
|
1347
1528
|
);
|
|
1348
|
-
config = null;
|
|
1349
|
-
sinks = [];
|
|
1529
|
+
shared.config = null;
|
|
1530
|
+
shared.sinks = [];
|
|
1350
1531
|
const failed = results.find((result) => result.status === "rejected");
|
|
1351
1532
|
if (failed) throw failed.reason;
|
|
1352
1533
|
}
|
|
@@ -1367,11 +1548,11 @@ function createRuntimeLogger(attributes = {}) {
|
|
|
1367
1548
|
warn: (message, extra) => emit("warning", message, merge(attrs, extra)),
|
|
1368
1549
|
error: (error, extra) => emit(
|
|
1369
1550
|
"error",
|
|
1370
|
-
error
|
|
1551
|
+
isError(error) ? error.message : String(error),
|
|
1371
1552
|
{
|
|
1372
1553
|
...attrs,
|
|
1373
1554
|
...extra,
|
|
1374
|
-
...error
|
|
1555
|
+
...isError(error) ? {
|
|
1375
1556
|
"exception.type": error.name,
|
|
1376
1557
|
"exception.stacktrace": error.stack ?? ""
|
|
1377
1558
|
} : {}
|
|
@@ -1382,16 +1563,16 @@ function createRuntimeLogger(attributes = {}) {
|
|
|
1382
1563
|
}
|
|
1383
1564
|
var runtimeLogger = createRuntimeLogger();
|
|
1384
1565
|
function captureExceptionAsLog(error, attributes = {}) {
|
|
1385
|
-
const
|
|
1386
|
-
const message =
|
|
1387
|
-
const stack =
|
|
1566
|
+
const isErr = isError(error);
|
|
1567
|
+
const message = isErr ? error.message : String(error);
|
|
1568
|
+
const stack = isErr && error.stack ? error.stack : new Error().stack?.split("\n").filter((line, i) => i === 0 || !/captureException/.test(line)).join("\n") ?? "";
|
|
1388
1569
|
noteOperationError(error);
|
|
1389
1570
|
emit(
|
|
1390
1571
|
"error",
|
|
1391
1572
|
message,
|
|
1392
1573
|
{
|
|
1393
1574
|
...attributes,
|
|
1394
|
-
"exception.type":
|
|
1575
|
+
"exception.type": isErr ? error.name : "Error",
|
|
1395
1576
|
"exception.message": message,
|
|
1396
1577
|
"exception.stacktrace": stack
|
|
1397
1578
|
},
|
|
@@ -1486,7 +1667,7 @@ function emitSummary(state, options = {}) {
|
|
|
1486
1667
|
state.message ?? `${state.name}: ${state.outcome}`,
|
|
1487
1668
|
{
|
|
1488
1669
|
...operationAttributes(state),
|
|
1489
|
-
...err
|
|
1670
|
+
...isError(err) ? {
|
|
1490
1671
|
"exception.type": err.name,
|
|
1491
1672
|
"exception.stacktrace": err.stack ?? ""
|
|
1492
1673
|
} : {}
|
|
@@ -1498,7 +1679,7 @@ function emitSummary(state, options = {}) {
|
|
|
1498
1679
|
}
|
|
1499
1680
|
function reportExplicitFailure(state) {
|
|
1500
1681
|
if (state.outcome === "failed" && state.explicitOutcome && !state.errorThrown)
|
|
1501
|
-
config?.reportOutcome(state.name, state.message ?? "Operation failed", {
|
|
1682
|
+
shared.config?.reportOutcome(state.name, state.message ?? "Operation failed", {
|
|
1502
1683
|
...traceAttributes(state),
|
|
1503
1684
|
"autter.outcome.stack": state.reportingStack ?? ""
|
|
1504
1685
|
});
|
|
@@ -1521,6 +1702,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1521
1702
|
...parent?.requestId ? { requestId: parent.requestId } : {}
|
|
1522
1703
|
}
|
|
1523
1704
|
);
|
|
1705
|
+
if (linked && parent) state.breadcrumbs = parent.breadcrumbs ??= new BreadcrumbTrail();
|
|
1524
1706
|
const operation = operationHandle(state);
|
|
1525
1707
|
const run = () => local.run(state, async () => {
|
|
1526
1708
|
let thrown;
|
|
@@ -1530,7 +1712,8 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1530
1712
|
state.outcome = "failed";
|
|
1531
1713
|
thrown = error;
|
|
1532
1714
|
noteOperationError(error, true, state);
|
|
1533
|
-
|
|
1715
|
+
rememberThrownBreadcrumbs(error, state);
|
|
1716
|
+
shared.config?.captureThrown?.(error);
|
|
1534
1717
|
throw error;
|
|
1535
1718
|
} finally {
|
|
1536
1719
|
trace.getActiveSpan()?.setAttributes({
|
|
@@ -1539,7 +1722,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1539
1722
|
"autter.operation.kind": state.kind
|
|
1540
1723
|
});
|
|
1541
1724
|
if (state.outcome === "failed" && !thrown)
|
|
1542
|
-
config?.reportOutcome(
|
|
1725
|
+
shared.config?.reportOutcome(
|
|
1543
1726
|
state.name,
|
|
1544
1727
|
state.message ?? "Operation failed",
|
|
1545
1728
|
{
|
|
@@ -1560,7 +1743,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1560
1743
|
}
|
|
1561
1744
|
}
|
|
1562
1745
|
] : [];
|
|
1563
|
-
const promise = config?.run ? config.run(state.name, run, traceAttributes(state), links) : run();
|
|
1746
|
+
const promise = shared.config?.run ? shared.config.run(state.name, run, traceAttributes(state), links) : run();
|
|
1564
1747
|
if (!options.waitUntil) return promise;
|
|
1565
1748
|
const waitUntil = options.waitUntil;
|
|
1566
1749
|
return promise.finally(() => {
|
|
@@ -1634,6 +1817,88 @@ var runtimeContext = {
|
|
|
1634
1817
|
}
|
|
1635
1818
|
};
|
|
1636
1819
|
|
|
1820
|
+
// src/breadcrumbs.ts
|
|
1821
|
+
var INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
1822
|
+
var MAX_TRACE_TRAILS = 200;
|
|
1823
|
+
var trails = sharedSlot("breadcrumbs", () => ({
|
|
1824
|
+
byTrace: /* @__PURE__ */ new Map(),
|
|
1825
|
+
process: new BreadcrumbTrail(),
|
|
1826
|
+
thrown: /* @__PURE__ */ new WeakMap()
|
|
1827
|
+
}));
|
|
1828
|
+
var byTrace = trails.byTrace;
|
|
1829
|
+
var processTrail = trails.process;
|
|
1830
|
+
var thrownTrails = trails.thrown;
|
|
1831
|
+
function redact2(attributes) {
|
|
1832
|
+
return loggerConfigured()?.redact(attributes) ?? redactAttributes(attributes);
|
|
1833
|
+
}
|
|
1834
|
+
function trailFor(create, state = local.getStore()) {
|
|
1835
|
+
if (state) {
|
|
1836
|
+
if (!state.breadcrumbs && create) state.breadcrumbs = new BreadcrumbTrail();
|
|
1837
|
+
return state.breadcrumbs;
|
|
1838
|
+
}
|
|
1839
|
+
const traceId = trace2.getActiveSpan()?.spanContext().traceId;
|
|
1840
|
+
if (traceId && traceId !== INVALID_TRACE_ID) {
|
|
1841
|
+
let trail = byTrace.get(traceId);
|
|
1842
|
+
if (!trail && create) {
|
|
1843
|
+
trail = new BreadcrumbTrail();
|
|
1844
|
+
byTrace.set(traceId, trail);
|
|
1845
|
+
if (byTrace.size > MAX_TRACE_TRAILS) {
|
|
1846
|
+
const oldest = byTrace.keys().next().value;
|
|
1847
|
+
if (oldest !== void 0) byTrace.delete(oldest);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
return trail;
|
|
1851
|
+
}
|
|
1852
|
+
return processTrail;
|
|
1853
|
+
}
|
|
1854
|
+
function addBreadcrumb(input) {
|
|
1855
|
+
try {
|
|
1856
|
+
const crumb = normalizeBreadcrumb(input, redact2);
|
|
1857
|
+
if (!crumb) return;
|
|
1858
|
+
trailFor(true)?.add(crumb);
|
|
1859
|
+
noteCompatFeature("breadcrumbs");
|
|
1860
|
+
} catch {
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function recordLogBreadcrumb(level, message, attributes, state) {
|
|
1864
|
+
try {
|
|
1865
|
+
const data = {};
|
|
1866
|
+
let count = 0;
|
|
1867
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
1868
|
+
if (count >= 10) break;
|
|
1869
|
+
if (/^(?:exception|autter)\./.test(key)) continue;
|
|
1870
|
+
if (value === null || ["string", "number", "boolean"].includes(typeof value)) {
|
|
1871
|
+
data[key] = value;
|
|
1872
|
+
count++;
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
const crumb = normalizeBreadcrumb({ type: "log", level, message, data }, redact2);
|
|
1876
|
+
if (crumb) trailFor(true, state)?.add(crumb);
|
|
1877
|
+
} catch {
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
function attributeBudget() {
|
|
1881
|
+
const limit = Number(
|
|
1882
|
+
process.env.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT ?? process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT
|
|
1883
|
+
);
|
|
1884
|
+
return Number.isFinite(limit) && limit > 0 ? Math.min(BREADCRUMBS_ATTRIBUTE_MAX_CHARS, limit) : BREADCRUMBS_ATTRIBUTE_MAX_CHARS;
|
|
1885
|
+
}
|
|
1886
|
+
function rememberThrownBreadcrumbs(error, state) {
|
|
1887
|
+
if (state.breadcrumbs && error !== null && (typeof error === "object" || typeof error === "function"))
|
|
1888
|
+
thrownTrails.set(error, state.breadcrumbs);
|
|
1889
|
+
}
|
|
1890
|
+
function breadcrumbEventAttributes(scrub, error) {
|
|
1891
|
+
try {
|
|
1892
|
+
const thrown = error !== null && typeof error === "object" ? thrownTrails.get(error) : void 0;
|
|
1893
|
+
const trail = thrown ?? trailFor(false);
|
|
1894
|
+
if (!trail?.size) return {};
|
|
1895
|
+
const json = breadcrumbsAttribute(trail.list(), scrub, attributeBudget());
|
|
1896
|
+
return json ? { [BREADCRUMBS_ATTRIBUTE]: json } : {};
|
|
1897
|
+
} catch {
|
|
1898
|
+
return {};
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1637
1902
|
export {
|
|
1638
1903
|
redactAttributes,
|
|
1639
1904
|
redactText,
|
|
@@ -1641,6 +1906,7 @@ export {
|
|
|
1641
1906
|
CODE_PATTERN,
|
|
1642
1907
|
RuntimeError,
|
|
1643
1908
|
defineRuntimeErrors,
|
|
1909
|
+
isError,
|
|
1644
1910
|
isRuntimeErrorLike,
|
|
1645
1911
|
errorCodeOf,
|
|
1646
1912
|
errorAttributes,
|
|
@@ -1654,6 +1920,12 @@ export {
|
|
|
1654
1920
|
compileIgnore,
|
|
1655
1921
|
requestOutcome,
|
|
1656
1922
|
parseUserAgent,
|
|
1923
|
+
sanitizeBreadcrumbs,
|
|
1924
|
+
fingerprintValues,
|
|
1925
|
+
fingerprintEventAttributes,
|
|
1926
|
+
splitFingerprint,
|
|
1927
|
+
addBreadcrumb,
|
|
1928
|
+
breadcrumbEventAttributes,
|
|
1657
1929
|
otlpSink,
|
|
1658
1930
|
consoleSink,
|
|
1659
1931
|
fileSink,
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunk4MVWIRBIcjs = require('./chunk-4MVWIRBI.cjs');
|
|
9
9
|
|
|
10
10
|
// src/doctor.ts
|
|
11
11
|
var _fs = require('fs');
|
|
@@ -30,19 +30,19 @@ function installedSdks(cwd) {
|
|
|
30
30
|
}
|
|
31
31
|
if (_path.dirname.call(void 0, dir) === dir) break;
|
|
32
32
|
}
|
|
33
|
-
if (!found.has(
|
|
33
|
+
if (!found.has(_chunk4MVWIRBIcjs.SDK_IDENTITY.name)) found.set(_chunk4MVWIRBIcjs.SDK_IDENTITY.name, _chunk4MVWIRBIcjs.SDK_IDENTITY.version);
|
|
34
34
|
return [...found].map(([name, version]) => ({ name, version }));
|
|
35
35
|
}
|
|
36
36
|
function featuresInUse(sdks) {
|
|
37
|
-
return
|
|
37
|
+
return _chunk4MVWIRBIcjs.COMPAT_MANIFEST.features.filter(
|
|
38
38
|
(feature) => sdks.some((sdk) => {
|
|
39
39
|
const min = feature.sdks[sdk.name];
|
|
40
|
-
return min !== void 0 &&
|
|
40
|
+
return min !== void 0 && _chunk4MVWIRBIcjs.versionAtLeast.call(void 0, sdk.version, min) === true;
|
|
41
41
|
})
|
|
42
42
|
).map((feature) => feature.id);
|
|
43
43
|
}
|
|
44
44
|
async function checkKey(endpoint, key, timeoutMs) {
|
|
45
|
-
const res = await
|
|
45
|
+
const res = await _chunk4MVWIRBIcjs.compatRequest.call(void 0, "POST", `${endpoint}/v1/traces`, {
|
|
46
46
|
body: JSON.stringify({ resourceSpans: [] }),
|
|
47
47
|
headers: { authorization: `Bearer ${key}` },
|
|
48
48
|
unref: false,
|
|
@@ -62,10 +62,10 @@ async function runDoctor(options = {}) {
|
|
|
62
62
|
const features = _optionalChain([options, 'access', _ => _.features, 'optionalAccess', _2 => _2.length]) ? options.features : featuresInUse(sdks);
|
|
63
63
|
const routes = [
|
|
64
64
|
...new Set(
|
|
65
|
-
features.map((id) => _optionalChain([
|
|
65
|
+
features.map((id) => _optionalChain([_chunk4MVWIRBIcjs.COMPAT_MANIFEST, 'access', _3 => _3.features, 'access', _4 => _4.find, 'call', _5 => _5((f) => f.id === id), 'optionalAccess', _6 => _6.route])).filter((route) => Boolean(route))
|
|
66
66
|
)
|
|
67
67
|
];
|
|
68
|
-
const { info, error } = await
|
|
68
|
+
const { info, error } = await _chunk4MVWIRBIcjs.fetchIngesterCompat.call(void 0, endpoint, { probeRoutes: routes, unref: false, timeoutMs });
|
|
69
69
|
const issues = [];
|
|
70
70
|
const seen = /* @__PURE__ */ new Set();
|
|
71
71
|
const add = (issue) => {
|
|
@@ -75,15 +75,15 @@ async function runDoctor(options = {}) {
|
|
|
75
75
|
issues.push(issue);
|
|
76
76
|
}
|
|
77
77
|
};
|
|
78
|
-
|
|
78
|
+
_chunk4MVWIRBIcjs.evaluateCompat.call(void 0, { features, ingester: info }).forEach(add);
|
|
79
79
|
for (const sdk of sdks) {
|
|
80
80
|
if (_optionalChain([options, 'access', _7 => _7.features, 'optionalAccess', _8 => _8.length])) {
|
|
81
|
-
|
|
81
|
+
_chunk4MVWIRBIcjs.evaluateCompat.call(void 0, { features: options.features, ingester: null, sdk }).forEach(add);
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
const key = options.key ? await checkKey(endpoint, options.key, timeoutMs) : void 0;
|
|
85
85
|
const featureRows = features.flatMap((id) => {
|
|
86
|
-
const feature =
|
|
86
|
+
const feature = _chunk4MVWIRBIcjs.COMPAT_MANIFEST.features.find((f) => f.id === id);
|
|
87
87
|
if (!feature) return [];
|
|
88
88
|
const bad = issues.some((issue) => issue.feature === id);
|
|
89
89
|
const known = _optionalChain([info, 'optionalAccess', _9 => _9.version]) != null || feature.route !== void 0 && _optionalChain([info, 'optionalAccess', _10 => _10.routes, 'optionalAccess', _11 => _11[feature.route]]) !== void 0;
|
|
@@ -153,7 +153,7 @@ Checks that your Autter SDKs, ingester and ClickHouse schema versions match.
|
|
|
153
153
|
Options:
|
|
154
154
|
--endpoint <url> Ingester base URL (default: $AUTTER_ENDPOINT, $OTEL_EXPORTER_OTLP_ENDPOINT, or ${DEFAULT_ENDPOINT})
|
|
155
155
|
--key <key> Also verify an ingest key (default: $AUTTER_RUNTIME_KEY)
|
|
156
|
-
--features <a,b> Only check these features (${
|
|
156
|
+
--features <a,b> Only check these features (${_chunk4MVWIRBIcjs.COMPAT_MANIFEST.features.map((f) => f.id).join(", ")})
|
|
157
157
|
--json Machine-readable output
|
|
158
158
|
--timeout <ms> Per-request timeout (default 5000)
|
|
159
159
|
|