@telorun/kernel 0.49.0 → 0.50.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/dist/controller-loader.d.ts +6 -1
- package/dist/controller-loader.d.ts.map +1 -1
- package/dist/controller-loader.js +2 -0
- package/dist/controller-loader.js.map +1 -1
- package/dist/controller-loaders/bundle-builder.d.ts +2 -1
- package/dist/controller-loaders/bundle-builder.d.ts.map +1 -1
- package/dist/controller-loaders/bundle-builder.js +14 -9
- package/dist/controller-loaders/bundle-builder.js.map +1 -1
- package/dist/controller-loaders/npm-loader.d.ts +8 -2
- package/dist/controller-loaders/npm-loader.d.ts.map +1 -1
- package/dist/controller-loaders/npm-loader.js +19 -10
- package/dist/controller-loaders/npm-loader.js.map +1 -1
- package/dist/controllers/logging/console-sink-controller.d.ts +15 -0
- package/dist/controllers/logging/console-sink-controller.d.ts.map +1 -0
- package/dist/controllers/logging/console-sink-controller.js +40 -0
- package/dist/controllers/logging/console-sink-controller.js.map +1 -0
- package/dist/controllers/logging/file-sink-controller.d.ts +11 -0
- package/dist/controllers/logging/file-sink-controller.d.ts.map +1 -0
- package/dist/controllers/logging/file-sink-controller.js +33 -0
- package/dist/controllers/logging/file-sink-controller.js.map +1 -0
- package/dist/controllers/logging/sink-identity.d.ts +37 -0
- package/dist/controllers/logging/sink-identity.d.ts.map +1 -0
- package/dist/controllers/logging/sink-identity.js +40 -0
- package/dist/controllers/logging/sink-identity.js.map +1 -0
- package/dist/controllers/module/import-controller.d.ts.map +1 -1
- package/dist/controllers/module/import-controller.js +25 -0
- package/dist/controllers/module/import-controller.js.map +1 -1
- package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
- package/dist/controllers/resource-definition/resource-definition-controller.js +1 -0
- package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
- package/dist/evaluation-context.d.ts +27 -1
- package/dist/evaluation-context.d.ts.map +1 -1
- package/dist/evaluation-context.js +84 -16
- package/dist/evaluation-context.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/internal-context.d.ts +4 -0
- package/dist/internal-context.d.ts.map +1 -1
- package/dist/kernel.d.ts +26 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +78 -5
- package/dist/kernel.js.map +1 -1
- package/dist/logging/bootstrap-writer.d.ts +23 -0
- package/dist/logging/bootstrap-writer.d.ts.map +1 -0
- package/dist/logging/bootstrap-writer.js +31 -0
- package/dist/logging/bootstrap-writer.js.map +1 -0
- package/dist/logging/color-precedence.d.ts +27 -0
- package/dist/logging/color-precedence.d.ts.map +1 -0
- package/dist/logging/color-precedence.js +47 -0
- package/dist/logging/color-precedence.js.map +1 -0
- package/dist/logging/console-sink.d.ts +45 -0
- package/dist/logging/console-sink.d.ts.map +1 -0
- package/dist/logging/console-sink.js +56 -0
- package/dist/logging/console-sink.js.map +1 -0
- package/dist/logging/debug-wire-sink.d.ts +38 -0
- package/dist/logging/debug-wire-sink.d.ts.map +1 -0
- package/dist/logging/debug-wire-sink.js +85 -0
- package/dist/logging/debug-wire-sink.js.map +1 -0
- package/dist/logging/drop-accounting.d.ts +34 -0
- package/dist/logging/drop-accounting.d.ts.map +1 -0
- package/dist/logging/drop-accounting.js +98 -0
- package/dist/logging/drop-accounting.js.map +1 -0
- package/dist/logging/encode-json.d.ts +28 -0
- package/dist/logging/encode-json.d.ts.map +1 -0
- package/dist/logging/encode-json.js +86 -0
- package/dist/logging/encode-json.js.map +1 -0
- package/dist/logging/encode-pretty.d.ts +7 -0
- package/dist/logging/encode-pretty.d.ts.map +1 -0
- package/dist/logging/encode-pretty.js +104 -0
- package/dist/logging/encode-pretty.js.map +1 -0
- package/dist/logging/file-sink.d.ts +33 -0
- package/dist/logging/file-sink.d.ts.map +1 -0
- package/dist/logging/file-sink.js +72 -0
- package/dist/logging/file-sink.js.map +1 -0
- package/dist/logging/index.d.ts +39 -0
- package/dist/logging/index.d.ts.map +1 -0
- package/dist/logging/index.js +27 -0
- package/dist/logging/index.js.map +1 -0
- package/dist/logging/kernel-logging.d.ts +110 -0
- package/dist/logging/kernel-logging.d.ts.map +1 -0
- package/dist/logging/kernel-logging.js +199 -0
- package/dist/logging/kernel-logging.js.map +1 -0
- package/dist/logging/log-sink.d.ts +9 -0
- package/dist/logging/log-sink.d.ts.map +1 -0
- package/dist/logging/log-sink.js +8 -0
- package/dist/logging/log-sink.js.map +1 -0
- package/dist/logging/logging-host.d.ts +14 -0
- package/dist/logging/logging-host.d.ts.map +1 -0
- package/dist/logging/logging-host.js +27 -0
- package/dist/logging/logging-host.js.map +1 -0
- package/dist/logging/logging-pipeline.d.ts +89 -0
- package/dist/logging/logging-pipeline.d.ts.map +1 -0
- package/dist/logging/logging-pipeline.js +349 -0
- package/dist/logging/logging-pipeline.js.map +1 -0
- package/dist/logging/normalize-attributes.d.ts +48 -0
- package/dist/logging/normalize-attributes.d.ts.map +1 -0
- package/dist/logging/normalize-attributes.js +140 -0
- package/dist/logging/normalize-attributes.js.map +1 -0
- package/dist/logging/record-buffer.d.ts +24 -0
- package/dist/logging/record-buffer.d.ts.map +1 -0
- package/dist/logging/record-buffer.js +78 -0
- package/dist/logging/record-buffer.js.map +1 -0
- package/dist/logging/redact-attributes.d.ts +45 -0
- package/dist/logging/redact-attributes.d.ts.map +1 -0
- package/dist/logging/redact-attributes.js +152 -0
- package/dist/logging/redact-attributes.js.map +1 -0
- package/dist/logging/sampler.d.ts +34 -0
- package/dist/logging/sampler.d.ts.map +1 -0
- package/dist/logging/sampler.js +52 -0
- package/dist/logging/sampler.js.map +1 -0
- package/dist/logging/scope-config.d.ts +32 -0
- package/dist/logging/scope-config.d.ts.map +1 -0
- package/dist/logging/scope-config.js +2 -0
- package/dist/logging/scope-config.js.map +1 -0
- package/dist/logging/span-id.d.ts +24 -0
- package/dist/logging/span-id.d.ts.map +1 -0
- package/dist/logging/span-id.js +85 -0
- package/dist/logging/span-id.js.map +1 -0
- package/dist/logging/to-error-value.d.ts +3 -0
- package/dist/logging/to-error-value.d.ts.map +1 -0
- package/dist/logging/to-error-value.js +79 -0
- package/dist/logging/to-error-value.js.map +1 -0
- package/dist/logging/trace-parent.d.ts +54 -0
- package/dist/logging/trace-parent.d.ts.map +1 -0
- package/dist/logging/trace-parent.js +92 -0
- package/dist/logging/trace-parent.js.map +1 -0
- package/dist/manifest-schemas.d.ts +1 -1
- package/dist/manifest-schemas.d.ts.map +1 -1
- package/dist/manifest-schemas.js +12 -0
- package/dist/manifest-schemas.js.map +1 -1
- package/dist/module-context.d.ts +16 -0
- package/dist/module-context.d.ts.map +1 -1
- package/dist/module-context.js +6 -0
- package/dist/module-context.js.map +1 -1
- package/dist/resource-context.d.ts +15 -1
- package/dist/resource-context.d.ts.map +1 -1
- package/dist/resource-context.js +45 -0
- package/dist/resource-context.js.map +1 -1
- package/dist/schema-compiled-values.d.ts.map +1 -1
- package/dist/schema-compiled-values.js +7 -0
- package/dist/schema-compiled-values.js.map +1 -1
- package/dist/schema-validator.d.ts +8 -1
- package/dist/schema-validator.d.ts.map +1 -1
- package/dist/schema-validator.js +13 -3
- package/dist/schema-validator.js.map +1 -1
- package/package.json +3 -3
- package/src/controller-loader.ts +7 -1
- package/src/controller-loaders/bundle-builder.ts +18 -10
- package/src/controller-loaders/npm-loader.ts +32 -11
- package/src/controllers/logging/console-sink-controller.ts +46 -0
- package/src/controllers/logging/file-sink-controller.ts +40 -0
- package/src/controllers/logging/sink-identity.ts +53 -0
- package/src/controllers/module/import-controller.ts +27 -0
- package/src/controllers/resource-definition/resource-definition-controller.ts +1 -0
- package/src/evaluation-context.ts +93 -15
- package/src/index.ts +54 -0
- package/src/internal-context.ts +4 -0
- package/src/kernel.ts +98 -8
- package/src/logging/bootstrap-writer.ts +38 -0
- package/src/logging/color-precedence.ts +62 -0
- package/src/logging/console-sink.ts +86 -0
- package/src/logging/debug-wire-sink.ts +85 -0
- package/src/logging/drop-accounting.ts +108 -0
- package/src/logging/encode-json.ts +98 -0
- package/src/logging/encode-pretty.ts +117 -0
- package/src/logging/file-sink.ts +87 -0
- package/src/logging/index.ts +65 -0
- package/src/logging/kernel-logging.ts +266 -0
- package/src/logging/log-sink.ts +18 -0
- package/src/logging/logging-host.ts +33 -0
- package/src/logging/logging-pipeline.ts +465 -0
- package/src/logging/normalize-attributes.ts +228 -0
- package/src/logging/record-buffer.ts +72 -0
- package/src/logging/redact-attributes.ts +168 -0
- package/src/logging/sampler.ts +76 -0
- package/src/logging/scope-config.ts +32 -0
- package/src/logging/span-id.ts +84 -0
- package/src/logging/to-error-value.ts +89 -0
- package/src/logging/trace-parent.ts +110 -0
- package/src/manifest-schemas.ts +12 -0
- package/src/module-context.ts +23 -0
- package/src/resource-context.ts +48 -0
- package/src/schema-compiled-values.ts +6 -0
- package/src/schema-validator.ts +20 -5
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { isLogValuer } from "@telorun/sdk";
|
|
2
|
+
export const DEFAULT_ATTRIBUTE_LIMITS = {
|
|
3
|
+
attributeCount: 128,
|
|
4
|
+
valueLength: undefined,
|
|
5
|
+
depth: 10,
|
|
6
|
+
collectionElements: 1000,
|
|
7
|
+
deferredSteps: 100,
|
|
8
|
+
};
|
|
9
|
+
export const DEPTH_EXCEEDED = "[depth exceeded]";
|
|
10
|
+
export const CIRCULAR = "[circular]";
|
|
11
|
+
export function normalizeAttributes(input, options = {}) {
|
|
12
|
+
if (!input)
|
|
13
|
+
return { attributes: undefined, droppedCount: 0 };
|
|
14
|
+
const limits = options.limits ?? DEFAULT_ATTRIBUTE_LIMITS;
|
|
15
|
+
const censor = options.censor ?? "[redacted]";
|
|
16
|
+
const secrets = options.secretValues;
|
|
17
|
+
const root = {};
|
|
18
|
+
let droppedCount = 0;
|
|
19
|
+
let deferredBudget = limits.deferredSteps;
|
|
20
|
+
const keys = Object.keys(input);
|
|
21
|
+
const kept = keys.length > limits.attributeCount ? limits.attributeCount : keys.length;
|
|
22
|
+
droppedCount += keys.length - kept;
|
|
23
|
+
const stack = [];
|
|
24
|
+
for (let i = kept - 1; i >= 0; i -= 1) {
|
|
25
|
+
const key = keys[i];
|
|
26
|
+
stack.push({ source: input[key], parent: root, key, depth: 1, ancestors: [] });
|
|
27
|
+
}
|
|
28
|
+
while (stack.length > 0) {
|
|
29
|
+
const task = stack.pop();
|
|
30
|
+
let value = task.source;
|
|
31
|
+
if (isLogValuer(value)) {
|
|
32
|
+
if (deferredBudget <= 0) {
|
|
33
|
+
write(task, "[deferred limit exceeded]");
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
deferredBudget -= 1;
|
|
37
|
+
try {
|
|
38
|
+
value = value.toLogValue();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
write(task, `[deferred value threw: ${describeThrown(err)}]`);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (value === null || value === undefined) {
|
|
46
|
+
// `null` is a valid attribute value and is preserved (§6.1). `undefined`
|
|
47
|
+
// has no AnyValue variant, so it normalizes to the empty variant.
|
|
48
|
+
write(task, null);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const type = typeof value;
|
|
52
|
+
if (type === "string") {
|
|
53
|
+
write(task, scrubString(value, secrets, censor, limits.valueLength));
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (type === "boolean" || type === "bigint") {
|
|
57
|
+
write(task, value);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (type === "number") {
|
|
61
|
+
const num = value;
|
|
62
|
+
// JSON has no representation for these; emitting them raw produces
|
|
63
|
+
// invalid output, so they render as their spelling instead.
|
|
64
|
+
write(task, Number.isFinite(num) ? num : String(num));
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (value instanceof Uint8Array) {
|
|
68
|
+
write(task, value);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (type !== "object") {
|
|
72
|
+
// Functions and symbols have no AnyValue variant.
|
|
73
|
+
write(task, `[${type}]`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const object = value;
|
|
77
|
+
if (task.ancestors.includes(object)) {
|
|
78
|
+
write(task, CIRCULAR);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (task.depth >= limits.depth) {
|
|
82
|
+
write(task, DEPTH_EXCEEDED);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const ancestors = [...task.ancestors, object];
|
|
86
|
+
if (Array.isArray(value)) {
|
|
87
|
+
const total = value.length;
|
|
88
|
+
const keep = total > limits.collectionElements ? limits.collectionElements : total;
|
|
89
|
+
const array = new Array(keep);
|
|
90
|
+
write(task, array);
|
|
91
|
+
if (keep < total)
|
|
92
|
+
array.push(`[truncated: ${keep} of ${total} elements]`);
|
|
93
|
+
for (let i = keep - 1; i >= 0; i -= 1) {
|
|
94
|
+
stack.push({ source: value[i], parent: array, key: i, depth: task.depth + 1, ancestors });
|
|
95
|
+
}
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (value instanceof Date) {
|
|
99
|
+
write(task, value.toISOString());
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
const record = value;
|
|
103
|
+
const entryKeys = Object.keys(record);
|
|
104
|
+
const keepKeys = entryKeys.length > limits.collectionElements ? limits.collectionElements : entryKeys.length;
|
|
105
|
+
const map = {};
|
|
106
|
+
write(task, map);
|
|
107
|
+
if (keepKeys < entryKeys.length) {
|
|
108
|
+
map["[truncated]"] = `${keepKeys} of ${entryKeys.length} entries`;
|
|
109
|
+
}
|
|
110
|
+
for (let i = keepKeys - 1; i >= 0; i -= 1) {
|
|
111
|
+
const key = entryKeys[i];
|
|
112
|
+
stack.push({
|
|
113
|
+
source: record[key],
|
|
114
|
+
parent: map,
|
|
115
|
+
key,
|
|
116
|
+
depth: task.depth + 1,
|
|
117
|
+
ancestors,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return { attributes: root, droppedCount };
|
|
122
|
+
}
|
|
123
|
+
function write(task, value) {
|
|
124
|
+
if (Array.isArray(task.parent))
|
|
125
|
+
task.parent[task.key] = value;
|
|
126
|
+
else
|
|
127
|
+
task.parent[task.key] = value;
|
|
128
|
+
}
|
|
129
|
+
function scrubString(value, secrets, censor, maxLength) {
|
|
130
|
+
const scrubbed = secrets?.has(value) ? censor : value;
|
|
131
|
+
if (maxLength === undefined || scrubbed.length <= maxLength)
|
|
132
|
+
return scrubbed;
|
|
133
|
+
return `${scrubbed.slice(0, maxLength)}[truncated ${scrubbed.length - maxLength} chars]`;
|
|
134
|
+
}
|
|
135
|
+
function describeThrown(err) {
|
|
136
|
+
if (err instanceof Error)
|
|
137
|
+
return `${err.name}: ${err.message}`;
|
|
138
|
+
return String(err);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=normalize-attributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize-attributes.js","sourceRoot":"","sources":["../../src/logging/normalize-attributes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LogRecord } from "@telorun/sdk";
|
|
2
|
+
import type { SinkBufferPolicy } from "./log-sink.js";
|
|
3
|
+
/**
|
|
4
|
+
* The bounded buffer every asynchronous sink composes — `kernel/specs/logging.md`
|
|
5
|
+
* §10.3.
|
|
6
|
+
*
|
|
7
|
+
* The ecosystems disagree by default: Rust's `tracing-appender` drops, zap
|
|
8
|
+
* buffers 256 kB / 30 s, and pino has no bound at all. Telo therefore makes the
|
|
9
|
+
* policy explicit and required, and the buffer is never unbounded.
|
|
10
|
+
*
|
|
11
|
+
* `drop_old` has no precedent among the surveyed libraries, so it is implemented
|
|
12
|
+
* as specified — true ring-buffer semantics, evicting the oldest record — rather
|
|
13
|
+
* than by analogy to something else.
|
|
14
|
+
*/
|
|
15
|
+
export declare class RecordBuffer {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(policy: SinkBufferPolicy, onDrop: () => void);
|
|
18
|
+
get size(): number;
|
|
19
|
+
get isFull(): boolean;
|
|
20
|
+
push(record: LogRecord): void;
|
|
21
|
+
/** Take everything buffered, leaving the buffer empty. */
|
|
22
|
+
drain(): LogRecord[];
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=record-buffer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-buffer.d.ts","sourceRoot":"","sources":["../../src/logging/record-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;;gBASX,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,IAAI;IAMxD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAiB7B,0DAA0D;IAC1D,KAAK,IAAI,SAAS,EAAE;CAerB"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _RecordBuffer_instances, _RecordBuffer_capacity, _RecordBuffer_policy, _RecordBuffer_onDrop, _RecordBuffer_items, _RecordBuffer_head, _RecordBuffer_compact;
|
|
13
|
+
/**
|
|
14
|
+
* The bounded buffer every asynchronous sink composes — `kernel/specs/logging.md`
|
|
15
|
+
* §10.3.
|
|
16
|
+
*
|
|
17
|
+
* The ecosystems disagree by default: Rust's `tracing-appender` drops, zap
|
|
18
|
+
* buffers 256 kB / 30 s, and pino has no bound at all. Telo therefore makes the
|
|
19
|
+
* policy explicit and required, and the buffer is never unbounded.
|
|
20
|
+
*
|
|
21
|
+
* `drop_old` has no precedent among the surveyed libraries, so it is implemented
|
|
22
|
+
* as specified — true ring-buffer semantics, evicting the oldest record — rather
|
|
23
|
+
* than by analogy to something else.
|
|
24
|
+
*/
|
|
25
|
+
export class RecordBuffer {
|
|
26
|
+
constructor(policy, onDrop) {
|
|
27
|
+
_RecordBuffer_instances.add(this);
|
|
28
|
+
_RecordBuffer_capacity.set(this, void 0);
|
|
29
|
+
_RecordBuffer_policy.set(this, void 0);
|
|
30
|
+
_RecordBuffer_onDrop.set(this, void 0);
|
|
31
|
+
_RecordBuffer_items.set(this, []);
|
|
32
|
+
/** Index of the oldest record, so `drop_old` evicts in O(1) instead of
|
|
33
|
+
* shifting the whole array on every overflow. */
|
|
34
|
+
_RecordBuffer_head.set(this, 0);
|
|
35
|
+
__classPrivateFieldSet(this, _RecordBuffer_capacity, Math.max(1, policy.buffer), "f");
|
|
36
|
+
__classPrivateFieldSet(this, _RecordBuffer_policy, policy, "f");
|
|
37
|
+
__classPrivateFieldSet(this, _RecordBuffer_onDrop, onDrop, "f");
|
|
38
|
+
}
|
|
39
|
+
get size() {
|
|
40
|
+
return __classPrivateFieldGet(this, _RecordBuffer_items, "f").length - __classPrivateFieldGet(this, _RecordBuffer_head, "f");
|
|
41
|
+
}
|
|
42
|
+
get isFull() {
|
|
43
|
+
return this.size >= __classPrivateFieldGet(this, _RecordBuffer_capacity, "f");
|
|
44
|
+
}
|
|
45
|
+
push(record) {
|
|
46
|
+
if (this.isFull) {
|
|
47
|
+
if (__classPrivateFieldGet(this, _RecordBuffer_policy, "f").onFull === "drop_old") {
|
|
48
|
+
__classPrivateFieldSet(this, _RecordBuffer_head, __classPrivateFieldGet(this, _RecordBuffer_head, "f") + 1, "f");
|
|
49
|
+
__classPrivateFieldGet(this, _RecordBuffer_instances, "m", _RecordBuffer_compact).call(this);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
// `drop_new` — and `block`, which never reaches here because a runtime
|
|
53
|
+
// that cannot honour it rejects the manifest at load rather than
|
|
54
|
+
// silently degrading to a dropping policy.
|
|
55
|
+
__classPrivateFieldGet(this, _RecordBuffer_onDrop, "f").call(this);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
__classPrivateFieldGet(this, _RecordBuffer_onDrop, "f").call(this);
|
|
59
|
+
}
|
|
60
|
+
__classPrivateFieldGet(this, _RecordBuffer_items, "f").push(record);
|
|
61
|
+
}
|
|
62
|
+
/** Take everything buffered, leaving the buffer empty. */
|
|
63
|
+
drain() {
|
|
64
|
+
const drained = __classPrivateFieldGet(this, _RecordBuffer_head, "f") === 0 ? __classPrivateFieldGet(this, _RecordBuffer_items, "f") : __classPrivateFieldGet(this, _RecordBuffer_items, "f").slice(__classPrivateFieldGet(this, _RecordBuffer_head, "f"));
|
|
65
|
+
__classPrivateFieldSet(this, _RecordBuffer_items, [], "f");
|
|
66
|
+
__classPrivateFieldSet(this, _RecordBuffer_head, 0, "f");
|
|
67
|
+
return drained;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
_RecordBuffer_capacity = new WeakMap(), _RecordBuffer_policy = new WeakMap(), _RecordBuffer_onDrop = new WeakMap(), _RecordBuffer_items = new WeakMap(), _RecordBuffer_head = new WeakMap(), _RecordBuffer_instances = new WeakSet(), _RecordBuffer_compact = function _RecordBuffer_compact() {
|
|
71
|
+
// Reclaim the consumed prefix once it dominates the array, so a long-lived
|
|
72
|
+
// ring does not grow its backing store without bound.
|
|
73
|
+
if (__classPrivateFieldGet(this, _RecordBuffer_head, "f") > 32 && __classPrivateFieldGet(this, _RecordBuffer_head, "f") * 2 >= __classPrivateFieldGet(this, _RecordBuffer_items, "f").length) {
|
|
74
|
+
__classPrivateFieldSet(this, _RecordBuffer_items, __classPrivateFieldGet(this, _RecordBuffer_items, "f").slice(__classPrivateFieldGet(this, _RecordBuffer_head, "f")), "f");
|
|
75
|
+
__classPrivateFieldSet(this, _RecordBuffer_head, 0, "f");
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//# sourceMappingURL=record-buffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"record-buffer.js","sourceRoot":"","sources":["../../src/logging/record-buffer.ts"],"names":[],"mappings":";;;;;;;;;;;;AAGA;;;;;;;;;;;GAWG;AACH,MAAM,OAAO,YAAY;IASvB,YAAY,MAAwB,EAAE,MAAkB;;QAR/C,yCAAkB;QAClB,uCAA0B;QAC1B,uCAAoB;QAC7B,8BAAsB,EAAE,EAAC;QACzB;0DACkD;QAClD,6BAAQ,CAAC,EAAC;QAGR,uBAAA,IAAI,0BAAa,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,MAAA,CAAC;QAC5C,uBAAA,IAAI,wBAAW,MAAM,MAAA,CAAC;QACtB,uBAAA,IAAI,wBAAW,MAAM,MAAA,CAAC;IACxB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,uBAAA,IAAI,2BAAO,CAAC,MAAM,GAAG,uBAAA,IAAI,0BAAM,CAAC;IACzC,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,IAAI,IAAI,uBAAA,IAAI,8BAAU,CAAC;IACrC,CAAC;IAED,IAAI,CAAC,MAAiB;QACpB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,uBAAA,IAAI,4BAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACvC,yGAAc,CAAC,MAAA,CAAC;gBAChB,uBAAA,IAAI,sDAAS,MAAb,IAAI,CAAW,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,uEAAuE;gBACvE,iEAAiE;gBACjE,2CAA2C;gBAC3C,uBAAA,IAAI,4BAAQ,MAAZ,IAAI,CAAU,CAAC;gBACf,OAAO;YACT,CAAC;YACD,uBAAA,IAAI,4BAAQ,MAAZ,IAAI,CAAU,CAAC;QACjB,CAAC;QACD,uBAAA,IAAI,2BAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,0DAA0D;IAC1D,KAAK;QACH,MAAM,OAAO,GAAG,uBAAA,IAAI,0BAAM,KAAK,CAAC,CAAC,CAAC,CAAC,uBAAA,IAAI,2BAAO,CAAC,CAAC,CAAC,uBAAA,IAAI,2BAAO,CAAC,KAAK,CAAC,uBAAA,IAAI,0BAAM,CAAC,CAAC;QAC/E,uBAAA,IAAI,uBAAU,EAAE,MAAA,CAAC;QACjB,uBAAA,IAAI,sBAAS,CAAC,MAAA,CAAC;QACf,OAAO,OAAO,CAAC;IACjB,CAAC;CAUF;;IAPG,2EAA2E;IAC3E,sDAAsD;IACtD,IAAI,uBAAA,IAAI,0BAAM,GAAG,EAAE,IAAI,uBAAA,IAAI,0BAAM,GAAG,CAAC,IAAI,uBAAA,IAAI,2BAAO,CAAC,MAAM,EAAE,CAAC;QAC5D,uBAAA,IAAI,uBAAU,uBAAA,IAAI,2BAAO,CAAC,KAAK,CAAC,uBAAA,IAAI,0BAAM,CAAC,MAAA,CAAC;QAC5C,uBAAA,IAAI,sBAAS,CAAC,MAAA,CAAC;IACjB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type RedactionSegment } from "@telorun/analyzer";
|
|
2
|
+
import type { ErrorValue, LogAttributes } from "@telorun/sdk";
|
|
3
|
+
/**
|
|
4
|
+
* Path-based redaction — `kernel/specs/logging.md` §14.
|
|
5
|
+
*
|
|
6
|
+
* Only path-based redaction is portable across Node, Rust, and Go, so it is the
|
|
7
|
+
* only form specified normatively. Paths are compiled once at configuration
|
|
8
|
+
* time by the analyzer's hand-written parser (never by compiling source in the
|
|
9
|
+
* host language, §14.1) and applied here by *navigating* to each path rather
|
|
10
|
+
* than walking the whole value tree — which is what keeps an explicit path at
|
|
11
|
+
* §14.2's 1–2% cost instead of the 25–55% an intermediate wildcard pays.
|
|
12
|
+
*
|
|
13
|
+
* The key is always preserved and only the value replaced. Deletion destroys
|
|
14
|
+
* schema stability and hides that a field was present at all, so `remove` is
|
|
15
|
+
* offered for the cases that genuinely need it but is never the default.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_CENSOR = "[redacted]";
|
|
18
|
+
export interface RedactionPolicy {
|
|
19
|
+
paths: readonly CompiledRedactionPath[];
|
|
20
|
+
censor: string;
|
|
21
|
+
remove: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface CompiledRedactionPath {
|
|
24
|
+
/** The path as written, kept for diagnostics. */
|
|
25
|
+
source: string;
|
|
26
|
+
segments: readonly RedactionSegment[];
|
|
27
|
+
}
|
|
28
|
+
/** Compile a policy's paths once, at configuration time. Throws
|
|
29
|
+
* `RedactionPathError` with the offending offset, so a bad path fails the
|
|
30
|
+
* manifest rather than silently failing to redact at runtime. */
|
|
31
|
+
export declare function compileRedactionPolicy(config: {
|
|
32
|
+
paths?: readonly string[];
|
|
33
|
+
censor?: string;
|
|
34
|
+
remove?: boolean;
|
|
35
|
+
}): RedactionPolicy;
|
|
36
|
+
export declare const EMPTY_REDACTION_POLICY: RedactionPolicy;
|
|
37
|
+
/** Apply the policy to a record's attributes in place. The attributes have
|
|
38
|
+
* already been normalized (§6.3), so collections are bounded and no cycle can
|
|
39
|
+
* make the navigation diverge. */
|
|
40
|
+
export declare function redactAttributes(attributes: LogAttributes | undefined, policy: RedactionPolicy): void;
|
|
41
|
+
/** Redaction applies to the error as well as the attributes (§14). The error's
|
|
42
|
+
* own fields are structural rather than user data, so a path addresses them by
|
|
43
|
+
* their record spelling — `error.message`, `error.cause.message`. */
|
|
44
|
+
export declare function redactError(error: ErrorValue | undefined, policy: RedactionPolicy): void;
|
|
45
|
+
//# sourceMappingURL=redact-attributes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-attributes.d.ts","sourceRoot":"","sources":["../../src/logging/redact-attributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAY,UAAU,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAExE;;;;;;;;;;;;;GAaG;AAEH,eAAO,MAAM,cAAc,eAAe,CAAC;AAE3C,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,qBAAqB,EAAE,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACvC;AAED;;kEAEkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,GAAG,eAAe,CASlB;AAED,eAAO,MAAM,sBAAsB,EAAE,eAIpC,CAAC;AAEF;;mCAEmC;AACnC,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,aAAa,GAAG,SAAS,EACrC,MAAM,EAAE,eAAe,GACtB,IAAI,CAGN;AAED;;sEAEsE;AACtE,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAIxF"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { parseRedactionPath } from "@telorun/analyzer";
|
|
2
|
+
/**
|
|
3
|
+
* Path-based redaction — `kernel/specs/logging.md` §14.
|
|
4
|
+
*
|
|
5
|
+
* Only path-based redaction is portable across Node, Rust, and Go, so it is the
|
|
6
|
+
* only form specified normatively. Paths are compiled once at configuration
|
|
7
|
+
* time by the analyzer's hand-written parser (never by compiling source in the
|
|
8
|
+
* host language, §14.1) and applied here by *navigating* to each path rather
|
|
9
|
+
* than walking the whole value tree — which is what keeps an explicit path at
|
|
10
|
+
* §14.2's 1–2% cost instead of the 25–55% an intermediate wildcard pays.
|
|
11
|
+
*
|
|
12
|
+
* The key is always preserved and only the value replaced. Deletion destroys
|
|
13
|
+
* schema stability and hides that a field was present at all, so `remove` is
|
|
14
|
+
* offered for the cases that genuinely need it but is never the default.
|
|
15
|
+
*/
|
|
16
|
+
export const DEFAULT_CENSOR = "[redacted]";
|
|
17
|
+
/** Compile a policy's paths once, at configuration time. Throws
|
|
18
|
+
* `RedactionPathError` with the offending offset, so a bad path fails the
|
|
19
|
+
* manifest rather than silently failing to redact at runtime. */
|
|
20
|
+
export function compileRedactionPolicy(config) {
|
|
21
|
+
return {
|
|
22
|
+
paths: (config.paths ?? []).map((source) => ({
|
|
23
|
+
source,
|
|
24
|
+
segments: parseRedactionPath(source),
|
|
25
|
+
})),
|
|
26
|
+
censor: config.censor ?? DEFAULT_CENSOR,
|
|
27
|
+
remove: config.remove ?? false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export const EMPTY_REDACTION_POLICY = {
|
|
31
|
+
paths: [],
|
|
32
|
+
censor: DEFAULT_CENSOR,
|
|
33
|
+
remove: false,
|
|
34
|
+
};
|
|
35
|
+
/** Apply the policy to a record's attributes in place. The attributes have
|
|
36
|
+
* already been normalized (§6.3), so collections are bounded and no cycle can
|
|
37
|
+
* make the navigation diverge. */
|
|
38
|
+
export function redactAttributes(attributes, policy) {
|
|
39
|
+
if (!attributes || policy.paths.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
for (const path of policy.paths)
|
|
42
|
+
applyPath(attributes, path.segments, policy);
|
|
43
|
+
}
|
|
44
|
+
/** Redaction applies to the error as well as the attributes (§14). The error's
|
|
45
|
+
* own fields are structural rather than user data, so a path addresses them by
|
|
46
|
+
* their record spelling — `error.message`, `error.cause.message`. */
|
|
47
|
+
export function redactError(error, policy) {
|
|
48
|
+
if (!error || policy.paths.length === 0)
|
|
49
|
+
return;
|
|
50
|
+
const wrapper = { error: error };
|
|
51
|
+
for (const path of policy.paths)
|
|
52
|
+
applyPath(wrapper, path.segments, policy);
|
|
53
|
+
}
|
|
54
|
+
function applyPath(root, segments, policy) {
|
|
55
|
+
if (segments.length === 0)
|
|
56
|
+
return;
|
|
57
|
+
let frontier = [root];
|
|
58
|
+
for (let i = 0; i < segments.length - 1; i += 1) {
|
|
59
|
+
const segment = segments[i];
|
|
60
|
+
const next = [];
|
|
61
|
+
for (const container of frontier) {
|
|
62
|
+
if (segment.kind === "wildcard") {
|
|
63
|
+
for (const child of childrenOf(container))
|
|
64
|
+
next.push(child);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const child = readKey(container, segment.name);
|
|
68
|
+
if (child !== undefined)
|
|
69
|
+
next.push(child);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (next.length === 0)
|
|
73
|
+
return;
|
|
74
|
+
frontier = next;
|
|
75
|
+
}
|
|
76
|
+
const last = segments[segments.length - 1];
|
|
77
|
+
for (const container of frontier) {
|
|
78
|
+
if (last.kind === "wildcard") {
|
|
79
|
+
// Descending so that `remove: true` over an array — which splices each
|
|
80
|
+
// matched index — does not shift the indices still to be visited. Without
|
|
81
|
+
// this, `items[*]` with remove leaves every other element behind, which
|
|
82
|
+
// for the §14 security control means a secret is only partially removed.
|
|
83
|
+
// Order is irrelevant for the censor path.
|
|
84
|
+
const keys = keysOf(container);
|
|
85
|
+
for (let i = keys.length - 1; i >= 0; i -= 1)
|
|
86
|
+
writeKey(container, keys[i], policy);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
if (readKey(container, last.name) === undefined && !hasKey(container, last.name))
|
|
90
|
+
continue;
|
|
91
|
+
writeKey(container, last.name, policy);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function childrenOf(container) {
|
|
96
|
+
if (Array.isArray(container))
|
|
97
|
+
return container;
|
|
98
|
+
if (isPlainContainer(container))
|
|
99
|
+
return Object.values(container);
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
function keysOf(container) {
|
|
103
|
+
if (Array.isArray(container))
|
|
104
|
+
return container.map((_item, index) => index);
|
|
105
|
+
if (isPlainContainer(container))
|
|
106
|
+
return Object.keys(container);
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
function readKey(container, key) {
|
|
110
|
+
if (Array.isArray(container)) {
|
|
111
|
+
const index = Number(key);
|
|
112
|
+
return Number.isInteger(index) ? container[index] : undefined;
|
|
113
|
+
}
|
|
114
|
+
if (isPlainContainer(container))
|
|
115
|
+
return container[key];
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
function hasKey(container, key) {
|
|
119
|
+
if (Array.isArray(container)) {
|
|
120
|
+
const index = Number(key);
|
|
121
|
+
return Number.isInteger(index) && index >= 0 && index < container.length;
|
|
122
|
+
}
|
|
123
|
+
return isPlainContainer(container) && hasOwn(container, key);
|
|
124
|
+
}
|
|
125
|
+
function hasOwn(container, key) {
|
|
126
|
+
return Object.prototype.hasOwnProperty.call(container, key);
|
|
127
|
+
}
|
|
128
|
+
function writeKey(container, key, policy) {
|
|
129
|
+
if (Array.isArray(container)) {
|
|
130
|
+
const index = typeof key === "number" ? key : Number(key);
|
|
131
|
+
if (!Number.isInteger(index))
|
|
132
|
+
return;
|
|
133
|
+
if (policy.remove)
|
|
134
|
+
container.splice(index, 1);
|
|
135
|
+
else
|
|
136
|
+
container[index] = policy.censor;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!isPlainContainer(container))
|
|
140
|
+
return;
|
|
141
|
+
const name = String(key);
|
|
142
|
+
if (!hasOwn(container, name))
|
|
143
|
+
return;
|
|
144
|
+
if (policy.remove)
|
|
145
|
+
delete container[name];
|
|
146
|
+
else
|
|
147
|
+
container[name] = policy.censor;
|
|
148
|
+
}
|
|
149
|
+
function isPlainContainer(value) {
|
|
150
|
+
return typeof value === "object" && value !== null && !(value instanceof Uint8Array);
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=redact-attributes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact-attributes.js","sourceRoot":"","sources":["../../src/logging/redact-attributes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAyB,MAAM,mBAAmB,CAAC;AAG9E;;;;;;;;;;;;;GAaG;AAEH,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAc3C;;kEAEkE;AAClE,MAAM,UAAU,sBAAsB,CAAC,MAItC;IACC,OAAO;QACL,KAAK,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC3C,MAAM;YACN,QAAQ,EAAE,kBAAkB,CAAC,MAAM,CAAC;SACrC,CAAC,CAAC;QACH,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,cAAc;QACvC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,KAAK;KAC/B,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAoB;IACrD,KAAK,EAAE,EAAE;IACT,MAAM,EAAE,cAAc;IACtB,MAAM,EAAE,KAAK;CACd,CAAC;AAEF;;mCAEmC;AACnC,MAAM,UAAU,gBAAgB,CAC9B,UAAqC,EACrC,MAAuB;IAEvB,IAAI,CAAC,UAAU,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACrD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAChF,CAAC;AAED;;sEAEsE;AACtE,MAAM,UAAU,WAAW,CAAC,KAA6B,EAAE,MAAuB;IAChF,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAChD,MAAM,OAAO,GAAkB,EAAE,KAAK,EAAE,KAA4B,EAAE,CAAC;IACvE,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK;QAAE,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC7E,CAAC;AAED,SAAS,SAAS,CAChB,IAAmB,EACnB,QAAqC,EACrC,MAAuB;IAEvB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAElC,IAAI,QAAQ,GAAc,CAAC,IAAI,CAAC,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC;QAC7B,MAAM,IAAI,GAAc,EAAE,CAAC;QAC3B,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gBAChC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,SAAS,CAAC;oBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9D,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,KAAK,KAAK,SAAS;oBAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAC9B,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IAC5C,KAAK,MAAM,SAAS,IAAI,QAAQ,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC7B,uEAAuE;YACvE,0EAA0E;YAC1E,wEAAwE;YACxE,yEAAyE;YACzE,2CAA2C;YAC3C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;YAC/B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;gBAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,IAAI,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAC3F,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,SAAkB;IACpC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/C,IAAI,gBAAgB,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACjE,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,MAAM,CAAC,SAAkB;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC5E,IAAI,gBAAgB,CAAC,SAAS,CAAC;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/D,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,OAAO,CAAC,SAAkB,EAAE,GAAW;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChE,CAAC;IACD,IAAI,gBAAgB,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,MAAM,CAAC,SAAkB,EAAE,GAAW;IAC7C,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,OAAO,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAC3E,CAAC;IACD,OAAO,gBAAgB,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,MAAM,CAAC,SAAkC,EAAE,GAAW;IAC7D,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,QAAQ,CAAC,SAAkB,EAAE,GAAoB,EAAE,MAAuB;IACjF,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE,OAAO;QACrC,IAAI,MAAM,CAAC,MAAM;YAAE,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;;YACzC,SAAS,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;QACtC,OAAO;IACT,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAAC;QAAE,OAAO;IACzC,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC;QAAE,OAAO;IACrC,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;;QACrC,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;AACvC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC,CAAC;AACvF,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type LogRecord } from "@telorun/sdk";
|
|
2
|
+
/**
|
|
3
|
+
* Sampling — `kernel/specs/logging.md` §15. Off by default.
|
|
4
|
+
*
|
|
5
|
+
* The dedup key is (`severity_number`, `message`) rather than the attributes,
|
|
6
|
+
* which is what keeps it cheap: a repeated message throttles regardless of the
|
|
7
|
+
* per-occurrence data hanging off it.
|
|
8
|
+
*
|
|
9
|
+
* §15 permits a fixed-size counter table that accepts collisions, trading
|
|
10
|
+
* precision for speed. This implementation instead keeps an
|
|
11
|
+
* **insertion-ordered map bounded by an entry cap**, evicting the least recently
|
|
12
|
+
* created key on overflow. Memory stays bounded either way, but a collision can
|
|
13
|
+
* only ever *lose* a record that should have been emitted, and no throughput
|
|
14
|
+
* gain justified that.
|
|
15
|
+
*/
|
|
16
|
+
export interface SamplingConfig {
|
|
17
|
+
/** Records emitted unconditionally at the start of each window. */
|
|
18
|
+
first: number;
|
|
19
|
+
/** Thereafter every Nth record is emitted. `0` drops everything after the
|
|
20
|
+
* first `first` in the window. */
|
|
21
|
+
thereafter: number;
|
|
22
|
+
/** Window length in milliseconds. */
|
|
23
|
+
tickMs: number;
|
|
24
|
+
/** Records at ERROR and above are not sampled by default (§15). */
|
|
25
|
+
sampleErrors?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare class Sampler {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(config: SamplingConfig);
|
|
30
|
+
/** `true` when the record should be emitted, `false` when it is sampled out.
|
|
31
|
+
* A `false` result is counted under cause `sampled` by the caller. */
|
|
32
|
+
shouldEmit(record: LogRecord, now: number): boolean;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=sampler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler.d.ts","sourceRoot":"","sources":["../../src/logging/sampler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,cAAc;IAC7B,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd;uCACmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,qCAAqC;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AASD,qBAAa,OAAO;;gBAIN,MAAM,EAAE,cAAc;IAIlC;2EACuE;IACvE,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO;CA6BpD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
6
|
+
};
|
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
11
|
+
};
|
|
12
|
+
var _Sampler_instances, _Sampler_config, _Sampler_windows, _Sampler_evictOverflow;
|
|
13
|
+
import { isErrorSeverity } from "@telorun/sdk";
|
|
14
|
+
const MAX_TRACKED_KEYS = 4096;
|
|
15
|
+
export class Sampler {
|
|
16
|
+
constructor(config) {
|
|
17
|
+
_Sampler_instances.add(this);
|
|
18
|
+
_Sampler_config.set(this, void 0);
|
|
19
|
+
_Sampler_windows.set(this, new Map());
|
|
20
|
+
__classPrivateFieldSet(this, _Sampler_config, config, "f");
|
|
21
|
+
}
|
|
22
|
+
/** `true` when the record should be emitted, `false` when it is sampled out.
|
|
23
|
+
* A `false` result is counted under cause `sampled` by the caller. */
|
|
24
|
+
shouldEmit(record, now) {
|
|
25
|
+
if (!__classPrivateFieldGet(this, _Sampler_config, "f").sampleErrors && isErrorSeverity(record.severityNumber))
|
|
26
|
+
return true;
|
|
27
|
+
const key = `${record.severityNumber}\x00${record.message}`;
|
|
28
|
+
let window = __classPrivateFieldGet(this, _Sampler_windows, "f").get(key);
|
|
29
|
+
if (!window || now - window.start >= __classPrivateFieldGet(this, _Sampler_config, "f").tickMs) {
|
|
30
|
+
window = { start: now, count: 0 };
|
|
31
|
+
__classPrivateFieldGet(this, _Sampler_windows, "f").delete(key);
|
|
32
|
+
__classPrivateFieldGet(this, _Sampler_windows, "f").set(key, window);
|
|
33
|
+
__classPrivateFieldGet(this, _Sampler_instances, "m", _Sampler_evictOverflow).call(this);
|
|
34
|
+
}
|
|
35
|
+
window.count += 1;
|
|
36
|
+
if (window.count <= __classPrivateFieldGet(this, _Sampler_config, "f").first)
|
|
37
|
+
return true;
|
|
38
|
+
if (__classPrivateFieldGet(this, _Sampler_config, "f").thereafter <= 0)
|
|
39
|
+
return false;
|
|
40
|
+
const sinceFirst = window.count - __classPrivateFieldGet(this, _Sampler_config, "f").first;
|
|
41
|
+
return sinceFirst % __classPrivateFieldGet(this, _Sampler_config, "f").thereafter === 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
_Sampler_config = new WeakMap(), _Sampler_windows = new WeakMap(), _Sampler_instances = new WeakSet(), _Sampler_evictOverflow = function _Sampler_evictOverflow() {
|
|
45
|
+
while (__classPrivateFieldGet(this, _Sampler_windows, "f").size > MAX_TRACKED_KEYS) {
|
|
46
|
+
const oldest = __classPrivateFieldGet(this, _Sampler_windows, "f").keys().next();
|
|
47
|
+
if (oldest.done)
|
|
48
|
+
return;
|
|
49
|
+
__classPrivateFieldGet(this, _Sampler_windows, "f").delete(oldest.value);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=sampler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sampler.js","sourceRoot":"","sources":["../../src/logging/sampler.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,cAAc,CAAC;AA6B/D,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAO9B,MAAM,OAAO,OAAO;IAIlB,YAAY,MAAsB;;QAHzB,kCAAwB;QACxB,2BAAW,IAAI,GAAG,EAAkB,EAAC;QAG5C,uBAAA,IAAI,mBAAW,MAAM,MAAA,CAAC;IACxB,CAAC;IAED;2EACuE;IACvE,UAAU,CAAC,MAAiB,EAAE,GAAW;QACvC,IAAI,CAAC,uBAAA,IAAI,uBAAQ,CAAC,YAAY,IAAI,eAAe,CAAC,MAAM,CAAC,cAAc,CAAC;YAAE,OAAO,IAAI,CAAC;QAEtF,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,cAAc,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;QAC5D,IAAI,MAAM,GAAG,uBAAA,IAAI,wBAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAEpC,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,uBAAA,IAAI,uBAAQ,CAAC,MAAM,EAAE,CAAC;YACzD,MAAM,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAClC,uBAAA,IAAI,wBAAS,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC1B,uBAAA,IAAI,wBAAS,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC/B,uBAAA,IAAI,kDAAe,MAAnB,IAAI,CAAiB,CAAC;QACxB,CAAC;QAED,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC;QAElB,IAAI,MAAM,CAAC,KAAK,IAAI,uBAAA,IAAI,uBAAQ,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACpD,IAAI,uBAAA,IAAI,uBAAQ,CAAC,UAAU,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAE/C,MAAM,UAAU,GAAG,MAAM,CAAC,KAAK,GAAG,uBAAA,IAAI,uBAAQ,CAAC,KAAK,CAAC;QACrD,OAAO,UAAU,GAAG,uBAAA,IAAI,uBAAQ,CAAC,UAAU,KAAK,CAAC,CAAC;IACpD,CAAC;CASF;;IANG,OAAO,uBAAA,IAAI,wBAAS,CAAC,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAC7C,MAAM,MAAM,GAAG,uBAAA,IAAI,wBAAS,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO;QACxB,uBAAA,IAAI,wBAAS,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { LogAttributes } from "@telorun/sdk";
|
|
2
|
+
import type { RedactionPolicy } from "./redact-attributes.js";
|
|
3
|
+
import type { SamplingConfig } from "./sampler.js";
|
|
4
|
+
/**
|
|
5
|
+
* Per-module-context logging configuration — `kernel/specs/logging.md` §12.2.
|
|
6
|
+
*
|
|
7
|
+
* Resolved once when the import graph is built and held as plain values: there
|
|
8
|
+
* is no per-record lookup and no walk up the import chain at emit time.
|
|
9
|
+
*
|
|
10
|
+
* This is a **leaf type module** on purpose. `ScopeConfig` is stamped onto the
|
|
11
|
+
* generic `ModuleContext` and read by `internal-context` / `resource-context`,
|
|
12
|
+
* so having those import it from the 400-line `logging-pipeline` would point
|
|
13
|
+
* generic core plumbing at a specific subsystem's implementation. Keeping the
|
|
14
|
+
* type here — depending only on the two policy leaves and the SDK — keeps that
|
|
15
|
+
* dependency pointing at a type, not at the pipeline.
|
|
16
|
+
*/
|
|
17
|
+
export interface ScopeConfig {
|
|
18
|
+
/** The resolved level for this module context. Also the default a sink's own
|
|
19
|
+
* `level` falls back to (§12.1). */
|
|
20
|
+
threshold: number;
|
|
21
|
+
redaction: RedactionPolicy;
|
|
22
|
+
sampling?: SamplingConfig;
|
|
23
|
+
/** Values bound to the manifest's `secrets:`, redacted with no configuration
|
|
24
|
+
* (§14). Cascades down the import graph exactly as the threshold does. */
|
|
25
|
+
secretValues?: ReadonlySet<string>;
|
|
26
|
+
/** Dotted import-alias path of the emitting module context. Absent at root. */
|
|
27
|
+
scope?: string;
|
|
28
|
+
module?: string;
|
|
29
|
+
/** Resource-level attributes merged into every record from this scope. */
|
|
30
|
+
attributes?: LogAttributes;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=scope-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-config.d.ts","sourceRoot":"","sources":["../../src/logging/scope-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B;yCACqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,eAAe,CAAC;IAC3B,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;+EAC2E;IAC3E,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope-config.js","sourceRoot":"","sources":["../../src/logging/scope-config.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Apply the process salt to a raw counter. Bijective, so uniqueness within the
|
|
2
|
+
* process is preserved exactly. */
|
|
3
|
+
export declare function saltSpanId(counter: number | bigint): bigint;
|
|
4
|
+
/**
|
|
5
|
+
* Render a span id as exactly 16 lowercase hex characters. An all-zero id is
|
|
6
|
+
* invalid and is treated as absent rather than emitted, so this returns
|
|
7
|
+
* `undefined` for zero.
|
|
8
|
+
*/
|
|
9
|
+
export declare function formatSpanId(value: bigint | number): string | undefined;
|
|
10
|
+
/** Format the salted form of a raw counter — the two steps a record emission
|
|
11
|
+
* performs together. */
|
|
12
|
+
export declare function formatSpanCounter(counter: number | bigint): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* Normalize a trace id for emission: exactly 32 lowercase hex characters. Ids
|
|
15
|
+
* are accepted in either case on ingest and always emitted lowercase. An
|
|
16
|
+
* all-zero or malformed id is treated as absent.
|
|
17
|
+
*/
|
|
18
|
+
export declare function normalizeTraceId(value: string | undefined): string | undefined;
|
|
19
|
+
/** The `span_id` counterpart of {@link normalizeTraceId}, for ids arriving as
|
|
20
|
+
* hex from an upstream rather than as a local counter. */
|
|
21
|
+
export declare function normalizeSpanId(value: string | undefined): string | undefined;
|
|
22
|
+
/** A fresh W3C-compatible 16-byte trace id. */
|
|
23
|
+
export declare function newTraceId(): string;
|
|
24
|
+
//# sourceMappingURL=span-id.d.ts.map
|