@autter/runtime-node 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -0
- package/dist/{chunk-ARN26OK6.cjs → chunk-4MVWIRBI.cjs} +89 -39
- package/dist/{chunk-FBKYOHU2.js → chunk-5KISVAVB.js} +41 -31
- package/dist/{chunk-UGNPCOIW.cjs → chunk-7OTD2YPT.cjs} +11 -11
- package/dist/{chunk-OY2HTUWY.js → chunk-HRDELHZP.js} +81 -31
- package/dist/{chunk-Y4T7SQMO.js → chunk-L5ENELB2.js} +1 -1
- package/dist/{chunk-UKYTXZOQ.cjs → chunk-UXTIMS3G.cjs} +65 -55
- package/dist/cli.cjs +8 -8
- package/dist/cli.js +2 -2
- package/dist/index.cjs +399 -290
- package/dist/index.d.cts +12 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +215 -106
- package/dist/testing.cjs +8 -8
- package/dist/testing.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -184,6 +184,7 @@ Defaults (cheap by construction):
|
|
|
184
184
|
| Request metrics | exported every 60 s |
|
|
185
185
|
| Logs | not collected |
|
|
186
186
|
| PII in custom attributes | redacted before export (`redactAttributes`) |
|
|
187
|
+
| Query strings in span URLs | parameter names only (`keepQueryParams`) |
|
|
187
188
|
| Forgotten `shutdown()` | exporters still flushed on exit (`autoFlush`) |
|
|
188
189
|
|
|
189
190
|
**Error-linked trace retention.** Errors export at 100% while traces are
|
|
@@ -383,6 +384,48 @@ This closes the server-side gap to match the browser relay's payload
|
|
|
383
384
|
whitelist; it is best-effort scrubbing of obvious PII shapes, not a DLP
|
|
384
385
|
engine — keep secrets out of attributes in the first place.
|
|
385
386
|
|
|
387
|
+
**Query strings (1.6.1+).** Query strings carry what a path never should:
|
|
388
|
+
emails, one-time codes, API keys, session ids, search terms. So no span
|
|
389
|
+
leaves the process with query values, whichever instrumentation made it
|
|
390
|
+
(HTTP server and client spans, undici/fetch, Express, Fastify, Next.js's own
|
|
391
|
+
spans):
|
|
392
|
+
|
|
393
|
+
- `http.target`, `http.url`, `url.full` and `url.original` are cut at the `?`
|
|
394
|
+
(and `#`): `/search?email=jane@example.com&page=2` becomes `/search`;
|
|
395
|
+
- `url.query` keeps only the parameter names, `email=[redacted]&page=[redacted]`.
|
|
396
|
+
It is added from the URL when the instrumentation did not set it, so you
|
|
397
|
+
still see which parameters a request used. A parameter without `=`
|
|
398
|
+
(`/verify?<token>`) may itself be the secret and is masked whole;
|
|
399
|
+
- span names lose their query too (Next.js names a request span
|
|
400
|
+
`GET /search?q=…` until it knows the route).
|
|
401
|
+
|
|
402
|
+
List the parameters whose values are safe to keep, such as pagination or
|
|
403
|
+
sorting (exact names, after percent-decoding; kept values are still scrubbed
|
|
404
|
+
by `redactAttributes`):
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
initAutterServer({ ..., keepQueryParams: ["page", "sort"] });
|
|
408
|
+
// url.query: "email=[redacted]&page=2"
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
This runs at export, like the scrubbing above, and also with
|
|
412
|
+
`redactAttributes: false`. Route templates (`http.route`) and request
|
|
413
|
+
summaries never contained a query.
|
|
414
|
+
|
|
415
|
+
### One SDK per process, however many copies are loaded
|
|
416
|
+
|
|
417
|
+
Bundlers can load this package more than once: Next.js bundles one copy
|
|
418
|
+
into `instrumentation.ts` and another into each route (unless it is in
|
|
419
|
+
`serverExternalPackages`), and a process can load both the ESM and the CJS
|
|
420
|
+
build. Since 1.6.1 every copy shares one process-wide state
|
|
421
|
+
(`globalThis[Symbol.for("@autter/runtime-node")]`): the copy that ran
|
|
422
|
+
`initAutterServer` (or `initAutterLogging`) is the SDK for all of them, so
|
|
423
|
+
`withRuntimeRequest`, `captureException`, `runtimeLogger` and the rest export
|
|
424
|
+
through it from any copy, and an error one copy reported is never reported
|
|
425
|
+
again by another. Before any copy starts, and after `shutdown()`, every copy
|
|
426
|
+
behaves as before: records go to the console. The shared object is
|
|
427
|
+
versioned; a copy that finds a layout it does not know keeps its own state.
|
|
428
|
+
|
|
386
429
|
## 3. LLM tracing
|
|
387
430
|
|
|
388
431
|
For the field contract, manual reporting patterns, and provider-agnostic
|
|
@@ -464,7 +464,7 @@ var _https = require('https');
|
|
|
464
464
|
// package.json
|
|
465
465
|
var package_default = {
|
|
466
466
|
name: "@autter/runtime-node",
|
|
467
|
-
version: "1.6.
|
|
467
|
+
version: "1.6.1",
|
|
468
468
|
description: "Autter Runtime for Node.js: request wide events, coded errors, operation logging, same-origin browser relay and a curated OpenTelemetry server tracker",
|
|
469
469
|
license: "MIT",
|
|
470
470
|
type: "module",
|
|
@@ -539,6 +539,55 @@ var package_default = {
|
|
|
539
539
|
]
|
|
540
540
|
};
|
|
541
541
|
|
|
542
|
+
// src/shared.ts
|
|
543
|
+
var SHARED_STATE_KEY = /* @__PURE__ */ Symbol.for("@autter/runtime-node");
|
|
544
|
+
var SHARED_STATE_LAYOUT = 1;
|
|
545
|
+
function isObject(value) {
|
|
546
|
+
return typeof value === "object" && value !== null;
|
|
547
|
+
}
|
|
548
|
+
var VERSION = package_default.version;
|
|
549
|
+
function resolveShared() {
|
|
550
|
+
const fresh = { v: SHARED_STATE_LAYOUT, sdk: VERSION };
|
|
551
|
+
const host = globalThis;
|
|
552
|
+
let existing;
|
|
553
|
+
try {
|
|
554
|
+
existing = host[SHARED_STATE_KEY];
|
|
555
|
+
if (existing === void 0) {
|
|
556
|
+
Object.defineProperty(host, SHARED_STATE_KEY, {
|
|
557
|
+
value: fresh,
|
|
558
|
+
configurable: true,
|
|
559
|
+
enumerable: false,
|
|
560
|
+
writable: false
|
|
561
|
+
});
|
|
562
|
+
return fresh;
|
|
563
|
+
}
|
|
564
|
+
} catch (e) {
|
|
565
|
+
return fresh;
|
|
566
|
+
}
|
|
567
|
+
if (isObject(existing) && existing.v === SHARED_STATE_LAYOUT) return existing;
|
|
568
|
+
debugLog(
|
|
569
|
+
`another copy of @autter/runtime-node uses shared state layout ${String(isObject(existing) ? existing.v : typeof existing)}; this copy (${VERSION}, layout ${SHARED_STATE_LAYOUT}) keeps its own state`
|
|
570
|
+
);
|
|
571
|
+
return fresh;
|
|
572
|
+
}
|
|
573
|
+
var shared = resolveShared();
|
|
574
|
+
function sharedSlot(name, init) {
|
|
575
|
+
const fresh = init();
|
|
576
|
+
try {
|
|
577
|
+
const existing = shared[name];
|
|
578
|
+
if (!isObject(existing)) {
|
|
579
|
+
shared[name] = fresh;
|
|
580
|
+
return fresh;
|
|
581
|
+
}
|
|
582
|
+
for (const [key, value] of Object.entries(fresh)) {
|
|
583
|
+
if (existing[key] === void 0) existing[key] = value;
|
|
584
|
+
}
|
|
585
|
+
return existing;
|
|
586
|
+
} catch (e2) {
|
|
587
|
+
return fresh;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
542
591
|
// src/compat.ts
|
|
543
592
|
var SDK_IDENTITY = {
|
|
544
593
|
name: "@autter/runtime-node",
|
|
@@ -587,7 +636,7 @@ function compatRequest(method, url, options = {}) {
|
|
|
587
636
|
if (options.unref !== false) req.on("socket", (socket) => socket.unref());
|
|
588
637
|
req.on("error", () => done(null));
|
|
589
638
|
req.end(options.body);
|
|
590
|
-
} catch (
|
|
639
|
+
} catch (e3) {
|
|
591
640
|
done(null);
|
|
592
641
|
}
|
|
593
642
|
});
|
|
@@ -600,7 +649,7 @@ async function fetchIngesterCompat(endpoint, options = {}) {
|
|
|
600
649
|
let report = null;
|
|
601
650
|
try {
|
|
602
651
|
report = JSON.parse(res.body);
|
|
603
|
-
} catch (
|
|
652
|
+
} catch (e4) {
|
|
604
653
|
}
|
|
605
654
|
const info = _nullishCoalesce(ingesterInfoFromReport(report), () => ( headerInfo(res.headers)));
|
|
606
655
|
return info ? { info, report } : { info: null, report, error: "unrecognised /v1/compat response" };
|
|
@@ -631,7 +680,7 @@ function envDisabled() {
|
|
|
631
680
|
return value === "0" || value === "false" || value === "off";
|
|
632
681
|
}
|
|
633
682
|
var defaultWarn = (message) => console.warn(`[autter-runtime] ${message}`);
|
|
634
|
-
var
|
|
683
|
+
var compat = sharedSlot("compat", () => ({ state: freshState(null, false) }));
|
|
635
684
|
function freshState(endpoint, enabled, sdk = SDK_IDENTITY, warn = defaultWarn) {
|
|
636
685
|
return {
|
|
637
686
|
endpoint,
|
|
@@ -646,7 +695,7 @@ function freshState(endpoint, enabled, sdk = SDK_IDENTITY, warn = defaultWarn) {
|
|
|
646
695
|
};
|
|
647
696
|
}
|
|
648
697
|
function configureCompatCheck(options) {
|
|
649
|
-
state = freshState(
|
|
698
|
+
compat.state = freshState(
|
|
650
699
|
options.endpoint.replace(/\/$/, ""),
|
|
651
700
|
options.enabled !== false && !envDisabled(),
|
|
652
701
|
_nullishCoalesce(options.sdk, () => ( SDK_IDENTITY)),
|
|
@@ -654,23 +703,23 @@ function configureCompatCheck(options) {
|
|
|
654
703
|
);
|
|
655
704
|
}
|
|
656
705
|
function ensureCompatConfigured(endpoint) {
|
|
657
|
-
if (state.endpoint === null && !envDisabled()) {
|
|
658
|
-
state = freshState(endpoint.replace(/\/$/, ""), true);
|
|
706
|
+
if (compat.state.endpoint === null && !envDisabled()) {
|
|
707
|
+
compat.state = freshState(endpoint.replace(/\/$/, ""), true);
|
|
659
708
|
}
|
|
660
709
|
}
|
|
661
710
|
function noteCompatFeature(id) {
|
|
662
711
|
try {
|
|
663
|
-
if (!state.enabled || state.features.has(id) || !featureById(id)) return;
|
|
664
|
-
state.features.add(id);
|
|
665
|
-
if (state.info) {
|
|
712
|
+
if (!compat.state.enabled || compat.state.features.has(id) || !featureById(id)) return;
|
|
713
|
+
compat.state.features.add(id);
|
|
714
|
+
if (compat.state.info) {
|
|
666
715
|
evaluateAndWarn();
|
|
667
716
|
return;
|
|
668
717
|
}
|
|
669
|
-
if (state.started) return;
|
|
670
|
-
state.started = true;
|
|
671
|
-
const current = state;
|
|
718
|
+
if (compat.state.started) return;
|
|
719
|
+
compat.state.started = true;
|
|
720
|
+
const current = compat.state;
|
|
672
721
|
setTimeout(() => void runCheck(current), 0).unref();
|
|
673
|
-
} catch (
|
|
722
|
+
} catch (e5) {
|
|
674
723
|
}
|
|
675
724
|
}
|
|
676
725
|
async function runCheck(current) {
|
|
@@ -679,7 +728,7 @@ async function runCheck(current) {
|
|
|
679
728
|
const { info, error } = await fetchIngesterCompat(current.endpoint, {
|
|
680
729
|
probeRoutes: routesFor(current.features)
|
|
681
730
|
});
|
|
682
|
-
if (state !== current) return;
|
|
731
|
+
if (compat.state !== current) return;
|
|
683
732
|
if (!info) {
|
|
684
733
|
debugLog(`compat check skipped: ${_nullishCoalesce(error, () => ( "ingester version unknown"))}`);
|
|
685
734
|
return;
|
|
@@ -703,8 +752,8 @@ function routesFor(features) {
|
|
|
703
752
|
return routes;
|
|
704
753
|
}
|
|
705
754
|
function mergeInfo(next) {
|
|
706
|
-
const prev = state.info;
|
|
707
|
-
state.info = {
|
|
755
|
+
const prev = compat.state.info;
|
|
756
|
+
compat.state.info = {
|
|
708
757
|
version: _nullishCoalesce(_nullishCoalesce(next.version, () => ( _optionalChain([prev, 'optionalAccess', _21 => _21.version]))), () => ( null)),
|
|
709
758
|
...next.legacy || _optionalChain([prev, 'optionalAccess', _22 => _22.legacy]) ? { legacy: true } : {},
|
|
710
759
|
..._nullishCoalesce(next.schema, () => ( _optionalChain([prev, 'optionalAccess', _23 => _23.schema]))) ? { schema: _nullishCoalesce(next.schema, () => ( _optionalChain([prev, 'optionalAccess', _24 => _24.schema]))) } : {},
|
|
@@ -712,17 +761,17 @@ function mergeInfo(next) {
|
|
|
712
761
|
};
|
|
713
762
|
}
|
|
714
763
|
function evaluateAndWarn() {
|
|
715
|
-
const info = state.info;
|
|
764
|
+
const info = compat.state.info;
|
|
716
765
|
if (!info) return;
|
|
717
|
-
if (info.version === null && state.endpoint) {
|
|
718
|
-
const unprobed = routesFor(state.features).filter(
|
|
719
|
-
(route) => _optionalChain([info, 'access', _26 => _26.routes, 'optionalAccess', _27 => _27[route]]) === void 0 && !state.pendingProbes.has(route)
|
|
766
|
+
if (info.version === null && compat.state.endpoint) {
|
|
767
|
+
const unprobed = routesFor(compat.state.features).filter(
|
|
768
|
+
(route) => _optionalChain([info, 'access', _26 => _26.routes, 'optionalAccess', _27 => _27[route]]) === void 0 && !compat.state.pendingProbes.has(route)
|
|
720
769
|
);
|
|
721
770
|
if (unprobed.length) {
|
|
722
|
-
const current = state;
|
|
771
|
+
const current = compat.state;
|
|
723
772
|
for (const route of unprobed) current.pendingProbes.add(route);
|
|
724
773
|
void Promise.all(unprobed.map((route) => probeRoute(current.endpoint, route, {}).then((exists) => [route, exists]))).then((results) => {
|
|
725
|
-
if (state !== current) return;
|
|
774
|
+
if (compat.state !== current) return;
|
|
726
775
|
const routes = {};
|
|
727
776
|
for (const [route, exists] of results) if (exists !== null) routes[route] = exists;
|
|
728
777
|
mergeInfo({ version: null, legacy: true, routes });
|
|
@@ -731,56 +780,56 @@ function evaluateAndWarn() {
|
|
|
731
780
|
});
|
|
732
781
|
}
|
|
733
782
|
}
|
|
734
|
-
for (const issue of evaluateCompat({ features: state.features, ingester: info })) {
|
|
783
|
+
for (const issue of evaluateCompat({ features: compat.state.features, ingester: info })) {
|
|
735
784
|
warnOnce(issue);
|
|
736
785
|
}
|
|
737
786
|
}
|
|
738
787
|
function warnOnce(issue) {
|
|
739
788
|
const key = `${issue.feature}:${issue.kind}`;
|
|
740
|
-
if (state.warned.has(key)) return;
|
|
741
|
-
state.warned.add(key);
|
|
789
|
+
if (compat.state.warned.has(key)) return;
|
|
790
|
+
compat.state.warned.add(key);
|
|
742
791
|
try {
|
|
743
|
-
state.warn(issue.message);
|
|
744
|
-
} catch (
|
|
792
|
+
compat.state.warn(issue.message);
|
|
793
|
+
} catch (e6) {
|
|
745
794
|
}
|
|
746
795
|
}
|
|
747
796
|
function observeIngesterResponse(response) {
|
|
748
797
|
try {
|
|
749
|
-
if (!state.enabled) return;
|
|
798
|
+
if (!compat.state.enabled) return;
|
|
750
799
|
const fromHeader = headerInfo(response.headers);
|
|
751
800
|
if (fromHeader) {
|
|
752
|
-
if (_optionalChain([
|
|
801
|
+
if (_optionalChain([compat, 'access', _28 => _28.state, 'access', _29 => _29.info, 'optionalAccess', _30 => _30.version]) !== fromHeader.version) {
|
|
753
802
|
mergeInfo(fromHeader);
|
|
754
803
|
evaluateAndWarn();
|
|
755
804
|
}
|
|
756
805
|
return;
|
|
757
806
|
}
|
|
758
|
-
if (response.status === 404 && response.route && !_optionalChain([state, 'access',
|
|
807
|
+
if (response.status === 404 && response.route && !_optionalChain([compat, 'access', _31 => _31.state, 'access', _32 => _32.info, 'optionalAccess', _33 => _33.version])) {
|
|
759
808
|
mergeInfo({ version: null, legacy: true, routes: { [response.route]: false } });
|
|
760
809
|
evaluateAndWarn();
|
|
761
810
|
}
|
|
762
|
-
} catch (
|
|
811
|
+
} catch (e7) {
|
|
763
812
|
}
|
|
764
813
|
}
|
|
765
814
|
function noteRelayRejection(eventTypes, status, headers) {
|
|
766
815
|
try {
|
|
767
|
-
if (!state.enabled || status !== 400 || headerInfo(headers)) return [];
|
|
816
|
+
if (!compat.state.enabled || status !== 400 || headerInfo(headers)) return [];
|
|
768
817
|
const named = [];
|
|
769
818
|
for (const id of featuresForBrowserEvents(eventTypes)) {
|
|
770
819
|
const feature = featureById(id);
|
|
771
820
|
const key = `${id}:relay_rejected`;
|
|
772
|
-
if (state.warned.has(key)) continue;
|
|
773
|
-
state.warned.add(key);
|
|
821
|
+
if (compat.state.warned.has(key)) continue;
|
|
822
|
+
compat.state.warned.add(key);
|
|
774
823
|
named.push(id);
|
|
775
824
|
try {
|
|
776
|
-
state.warn(
|
|
825
|
+
compat.state.warn(
|
|
777
826
|
`The ingester rejected a browser batch containing ${feature.title.toLowerCase()} events. ${feature.title} needs ingester >= ${feature.ingester}; yours is 1.4.0 or older (it predates version reporting), so those batches are dropped. ${ingesterUpgradeHint(COMPAT_MANIFEST)}`
|
|
778
827
|
);
|
|
779
|
-
} catch (
|
|
828
|
+
} catch (e8) {
|
|
780
829
|
}
|
|
781
830
|
}
|
|
782
831
|
return named;
|
|
783
|
-
} catch (
|
|
832
|
+
} catch (e9) {
|
|
784
833
|
return [];
|
|
785
834
|
}
|
|
786
835
|
}
|
|
@@ -807,4 +856,5 @@ function noteRelayRejection(eventTypes, status, headers) {
|
|
|
807
856
|
|
|
808
857
|
|
|
809
858
|
|
|
810
|
-
|
|
859
|
+
|
|
860
|
+
exports.COMPAT_MANIFEST = COMPAT_MANIFEST; exports.INGESTER_VERSION_HEADER = INGESTER_VERSION_HEADER; exports.versionAtLeast = versionAtLeast; exports.featuresForBrowserEvents = featuresForBrowserEvents; exports.evaluateCompat = evaluateCompat; exports.setDebugMode = setDebugMode; exports.isDebugEnabled = isDebugEnabled; exports.debugLog = debugLog; exports.telemetryStats = telemetryStats; exports.CountingExporter = CountingExporter; exports.registerFlushTarget = registerFlushTarget; exports.unregisterFlushTargets = unregisterFlushTargets; exports.installAutterAutoFlush = installAutterAutoFlush; exports.sharedSlot = sharedSlot; exports.SDK_IDENTITY = SDK_IDENTITY; exports.compatRequest = compatRequest; exports.fetchIngesterCompat = fetchIngesterCompat; exports.configureCompatCheck = configureCompatCheck; exports.ensureCompatConfigured = ensureCompatConfigured; exports.noteCompatFeature = noteCompatFeature; exports.observeIngesterResponse = observeIngesterResponse; exports.noteRelayRejection = noteRelayRejection;
|
|
@@ -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 = [
|
|
@@ -993,7 +994,7 @@ import {
|
|
|
993
994
|
unlinkSync
|
|
994
995
|
} from "fs";
|
|
995
996
|
import { join, resolve } from "path";
|
|
996
|
-
var sinkStats = { dropped: 0 };
|
|
997
|
+
var sinkStats = sharedSlot("sinks", () => ({ dropped: 0 }));
|
|
997
998
|
function otlpSink(options = {}) {
|
|
998
999
|
let context = null;
|
|
999
1000
|
let queue = [];
|
|
@@ -1362,18 +1363,22 @@ function memorySink() {
|
|
|
1362
1363
|
}
|
|
1363
1364
|
|
|
1364
1365
|
// src/logger.ts
|
|
1365
|
-
var
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
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;
|
|
1369
1374
|
var fallbackConsole = null;
|
|
1370
1375
|
function redact(attributes) {
|
|
1371
|
-
return config?.redact(attributes) ?? redactAttributes(attributes);
|
|
1376
|
+
return shared.config?.redact(attributes) ?? redactAttributes(attributes);
|
|
1372
1377
|
}
|
|
1373
1378
|
var safe = (attributes = {}) => boundContext(attributes, redact);
|
|
1374
1379
|
var merge = (current, next) => mergeContext(current, next, redact);
|
|
1375
1380
|
function activeSinks() {
|
|
1376
|
-
if (config) return extraSinks.size ? [...sinks, ...extraSinks] : sinks;
|
|
1381
|
+
if (shared.config) return extraSinks.size ? [...shared.sinks, ...extraSinks] : shared.sinks;
|
|
1377
1382
|
if (extraSinks.size) return [...extraSinks];
|
|
1378
1383
|
fallbackConsole ??= consoleSink();
|
|
1379
1384
|
return [fallbackConsole];
|
|
@@ -1410,9 +1415,9 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1410
1415
|
if (state?.sealed) return;
|
|
1411
1416
|
const summary = extra["autter.event.type"] === "operation";
|
|
1412
1417
|
if (!summary) recordLogBreadcrumb(level, message, attributes, state);
|
|
1413
|
-
if (!summary && LEVEL_SEVERITY[level] < LEVEL_SEVERITY[config?.options?.minLevel ?? "debug"])
|
|
1418
|
+
if (!summary && LEVEL_SEVERITY[level] < LEVEL_SEVERITY[shared.config?.options?.minLevel ?? "debug"])
|
|
1414
1419
|
return;
|
|
1415
|
-
if (!summary && state && config?.options?.inline !== false) {
|
|
1420
|
+
if (!summary && state && shared.config?.options?.inline !== false) {
|
|
1416
1421
|
const { "exception.stacktrace": _stack, ...inlineAttrs } = userContext(
|
|
1417
1422
|
attributes,
|
|
1418
1423
|
redact
|
|
@@ -1432,7 +1437,7 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1432
1437
|
...operationAttributes(state),
|
|
1433
1438
|
...user
|
|
1434
1439
|
};
|
|
1435
|
-
const enrichers = config?.options?.enrich;
|
|
1440
|
+
const enrichers = shared.config?.options?.enrich;
|
|
1436
1441
|
if (summary && state && enrichers?.length) {
|
|
1437
1442
|
const event2 = { level, message, attributes: raw };
|
|
1438
1443
|
for (const enrich of enrichers) {
|
|
@@ -1460,9 +1465,9 @@ function emit(level, message, attributes, extra = {}, options = {}) {
|
|
|
1460
1465
|
}
|
|
1461
1466
|
}
|
|
1462
1467
|
function configureRuntimeLogger(next) {
|
|
1463
|
-
config = next;
|
|
1464
|
-
sinks = defaultSinks(next);
|
|
1465
|
-
for (const sink of sinks) {
|
|
1468
|
+
shared.config = next;
|
|
1469
|
+
shared.sinks = defaultSinks(next);
|
|
1470
|
+
for (const sink of shared.sinks) {
|
|
1466
1471
|
try {
|
|
1467
1472
|
sink.start?.({
|
|
1468
1473
|
endpoint: next.endpoint,
|
|
@@ -1477,14 +1482,14 @@ function configureRuntimeLogger(next) {
|
|
|
1477
1482
|
}
|
|
1478
1483
|
}
|
|
1479
1484
|
function loggerConfigured() {
|
|
1480
|
-
return config;
|
|
1485
|
+
return shared.config;
|
|
1481
1486
|
}
|
|
1482
1487
|
function addRuntimeSink(sink) {
|
|
1483
1488
|
extraSinks.add(sink);
|
|
1484
1489
|
return () => extraSinks.delete(sink);
|
|
1485
1490
|
}
|
|
1486
1491
|
function notifyException(error, attributes = {}) {
|
|
1487
|
-
if (!extraSinks.size && !sinks.some((sink) => sink.exception)) return;
|
|
1492
|
+
if (!extraSinks.size && !shared.sinks.some((sink) => sink.exception)) return;
|
|
1488
1493
|
const state = local.getStore();
|
|
1489
1494
|
const record = {
|
|
1490
1495
|
time: Date.now(),
|
|
@@ -1495,7 +1500,7 @@ function notifyException(error, attributes = {}) {
|
|
|
1495
1500
|
...state ? { operationId: state.id } : {},
|
|
1496
1501
|
...state?.requestId ? { requestId: state.requestId } : {}
|
|
1497
1502
|
};
|
|
1498
|
-
for (const sink of [...sinks, ...extraSinks]) {
|
|
1503
|
+
for (const sink of [...shared.sinks, ...extraSinks]) {
|
|
1499
1504
|
try {
|
|
1500
1505
|
sink.exception?.(record);
|
|
1501
1506
|
} catch {
|
|
@@ -1504,25 +1509,25 @@ function notifyException(error, attributes = {}) {
|
|
|
1504
1509
|
}
|
|
1505
1510
|
function runtimeLogStats() {
|
|
1506
1511
|
return {
|
|
1507
|
-
buffered: sinks.reduce((sum, sink) => sum + (sink.buffered?.() ?? 0), 0),
|
|
1512
|
+
buffered: shared.sinks.reduce((sum, sink) => sum + (sink.buffered?.() ?? 0), 0),
|
|
1508
1513
|
dropped: sinkStats.dropped
|
|
1509
1514
|
};
|
|
1510
1515
|
}
|
|
1511
1516
|
async function flushRuntimeLogs() {
|
|
1512
|
-
if (!config) return;
|
|
1517
|
+
if (!shared.config) return;
|
|
1513
1518
|
const results = await Promise.allSettled(
|
|
1514
|
-
sinks.map((sink) => Promise.resolve().then(() => sink.flush?.()))
|
|
1519
|
+
shared.sinks.map((sink) => Promise.resolve().then(() => sink.flush?.()))
|
|
1515
1520
|
);
|
|
1516
1521
|
const failed = results.find((result) => result.status === "rejected");
|
|
1517
1522
|
if (failed) throw failed.reason;
|
|
1518
1523
|
}
|
|
1519
1524
|
async function shutdownRuntimeLogger() {
|
|
1520
|
-
const active = sinks;
|
|
1525
|
+
const active = shared.sinks;
|
|
1521
1526
|
const results = await Promise.allSettled(
|
|
1522
1527
|
active.map((sink) => Promise.resolve().then(() => sink.shutdown?.()))
|
|
1523
1528
|
);
|
|
1524
|
-
config = null;
|
|
1525
|
-
sinks = [];
|
|
1529
|
+
shared.config = null;
|
|
1530
|
+
shared.sinks = [];
|
|
1526
1531
|
const failed = results.find((result) => result.status === "rejected");
|
|
1527
1532
|
if (failed) throw failed.reason;
|
|
1528
1533
|
}
|
|
@@ -1674,7 +1679,7 @@ function emitSummary(state, options = {}) {
|
|
|
1674
1679
|
}
|
|
1675
1680
|
function reportExplicitFailure(state) {
|
|
1676
1681
|
if (state.outcome === "failed" && state.explicitOutcome && !state.errorThrown)
|
|
1677
|
-
config?.reportOutcome(state.name, state.message ?? "Operation failed", {
|
|
1682
|
+
shared.config?.reportOutcome(state.name, state.message ?? "Operation failed", {
|
|
1678
1683
|
...traceAttributes(state),
|
|
1679
1684
|
"autter.outcome.stack": state.reportingStack ?? ""
|
|
1680
1685
|
});
|
|
@@ -1708,7 +1713,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1708
1713
|
thrown = error;
|
|
1709
1714
|
noteOperationError(error, true, state);
|
|
1710
1715
|
rememberThrownBreadcrumbs(error, state);
|
|
1711
|
-
config?.captureThrown?.(error);
|
|
1716
|
+
shared.config?.captureThrown?.(error);
|
|
1712
1717
|
throw error;
|
|
1713
1718
|
} finally {
|
|
1714
1719
|
trace.getActiveSpan()?.setAttributes({
|
|
@@ -1717,7 +1722,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1717
1722
|
"autter.operation.kind": state.kind
|
|
1718
1723
|
});
|
|
1719
1724
|
if (state.outcome === "failed" && !thrown)
|
|
1720
|
-
config?.reportOutcome(
|
|
1725
|
+
shared.config?.reportOutcome(
|
|
1721
1726
|
state.name,
|
|
1722
1727
|
state.message ?? "Operation failed",
|
|
1723
1728
|
{
|
|
@@ -1738,7 +1743,7 @@ function startOperation(name, fn, attributes, options, internal = {}) {
|
|
|
1738
1743
|
}
|
|
1739
1744
|
}
|
|
1740
1745
|
] : [];
|
|
1741
|
-
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();
|
|
1742
1747
|
if (!options.waitUntil) return promise;
|
|
1743
1748
|
const waitUntil = options.waitUntil;
|
|
1744
1749
|
return promise.finally(() => {
|
|
@@ -1815,9 +1820,14 @@ var runtimeContext = {
|
|
|
1815
1820
|
// src/breadcrumbs.ts
|
|
1816
1821
|
var INVALID_TRACE_ID = "00000000000000000000000000000000";
|
|
1817
1822
|
var MAX_TRACE_TRAILS = 200;
|
|
1818
|
-
var
|
|
1819
|
-
|
|
1820
|
-
|
|
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;
|
|
1821
1831
|
function redact2(attributes) {
|
|
1822
1832
|
return loggerConfigured()?.redact(attributes) ?? redactAttributes(attributes);
|
|
1823
1833
|
}
|
|
@@ -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
|
|