@nodii/telemetry 0.0.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -1
- package/dist/active-span.d.ts +12 -0
- package/dist/active-span.d.ts.map +1 -0
- package/dist/active-span.js +20 -0
- package/dist/active-span.js.map +1 -0
- package/dist/agent-invocable.d.ts +24 -0
- package/dist/agent-invocable.d.ts.map +1 -0
- package/dist/agent-invocable.js +64 -0
- package/dist/agent-invocable.js.map +1 -0
- package/dist/audit-types.d.ts +15 -0
- package/dist/audit-types.d.ts.map +1 -0
- package/dist/audit-types.js +39 -0
- package/dist/audit-types.js.map +1 -0
- package/dist/audit.d.ts +226 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +255 -0
- package/dist/audit.js.map +1 -0
- package/dist/configure.d.ts +34 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +23 -0
- package/dist/configure.js.map +1 -0
- package/dist/context.d.ts +40 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +70 -0
- package/dist/context.js.map +1 -0
- package/dist/drizzle/audit-schema.d.ts +884 -0
- package/dist/drizzle/audit-schema.d.ts.map +1 -0
- package/dist/drizzle/audit-schema.js +268 -0
- package/dist/drizzle/audit-schema.js.map +1 -0
- package/dist/drizzle/index.d.ts +3 -0
- package/dist/drizzle/index.d.ts.map +1 -0
- package/dist/drizzle/index.js +5 -0
- package/dist/drizzle/index.js.map +1 -0
- package/dist/index.d.ts +21 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -5
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +39 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +114 -0
- package/dist/init.js.map +1 -0
- package/dist/intent.d.ts +21 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +123 -0
- package/dist/intent.js.map +1 -0
- package/dist/logger.d.ts +19 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +99 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.d.ts +53 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +152 -0
- package/dist/metrics.js.map +1 -0
- package/dist/otlp-adapter.d.ts +44 -0
- package/dist/otlp-adapter.d.ts.map +1 -0
- package/dist/otlp-adapter.js +351 -0
- package/dist/otlp-adapter.js.map +1 -0
- package/dist/outbox-emit.d.ts +34 -0
- package/dist/outbox-emit.d.ts.map +1 -0
- package/dist/outbox-emit.js +58 -0
- package/dist/outbox-emit.js.map +1 -0
- package/dist/redaction.d.ts +51 -0
- package/dist/redaction.d.ts.map +1 -0
- package/dist/redaction.js +173 -0
- package/dist/redaction.js.map +1 -0
- package/dist/sdk-counters.d.ts +14 -0
- package/dist/sdk-counters.d.ts.map +1 -0
- package/dist/sdk-counters.js +42 -0
- package/dist/sdk-counters.js.map +1 -0
- package/dist/tracer.d.ts +63 -0
- package/dist/tracer.d.ts.map +1 -0
- package/dist/tracer.js +214 -0
- package/dist/tracer.js.map +1 -0
- package/dist/types.d.ts +230 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +66 -0
- package/dist/types.js.map +1 -0
- package/dist/uuid.d.ts +5 -0
- package/dist/uuid.d.ts.map +1 -0
- package/dist/uuid.js +34 -0
- package/dist/uuid.js.map +1 -0
- package/package.json +44 -7
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
// PII redaction per D15. SDK-side canonical, fail-closed. Two passes:
|
|
2
|
+
// 1. Structured-field-key match against D2 PII list.
|
|
3
|
+
// 2. Regex pass on the message string.
|
|
4
|
+
//
|
|
5
|
+
// On exception during redaction: the line is DROPPED and a
|
|
6
|
+
// `telemetry.sdk.redaction_failure_total{reason}` counter increments. We
|
|
7
|
+
// surface that counter via the metrics module (§ 5.4); this module just
|
|
8
|
+
// reports the drop + reason via `attemptRedaction` returning a tagged
|
|
9
|
+
// result. The collector-side pass (D59) is defense-in-depth — the
|
|
10
|
+
// SDK-side pass is canonical.
|
|
11
|
+
const REDACTED = "[REDACTED]";
|
|
12
|
+
/**
|
|
13
|
+
* D2 PII field-name allowlist. Keys whose name matches one of these
|
|
14
|
+
* (case-insensitive) get their value stripped to `[REDACTED]` before
|
|
15
|
+
* the log/span attribute is emitted.
|
|
16
|
+
*
|
|
17
|
+
* Source: the legacy telemetry doctrine D2 PII list, transcribed for
|
|
18
|
+
* v0.1.0. Adding new keys is an ADR-gated change.
|
|
19
|
+
*/
|
|
20
|
+
export const PII_FIELD_NAMES = [
|
|
21
|
+
"password",
|
|
22
|
+
"passwd",
|
|
23
|
+
"secret",
|
|
24
|
+
"token",
|
|
25
|
+
"access_token",
|
|
26
|
+
"refresh_token",
|
|
27
|
+
"id_token",
|
|
28
|
+
"api_key",
|
|
29
|
+
"apikey",
|
|
30
|
+
"private_key",
|
|
31
|
+
"client_secret",
|
|
32
|
+
"session_id",
|
|
33
|
+
"cookie",
|
|
34
|
+
"authorization",
|
|
35
|
+
"ssn",
|
|
36
|
+
"tax_id",
|
|
37
|
+
"pan",
|
|
38
|
+
"aadhaar",
|
|
39
|
+
"credit_card",
|
|
40
|
+
"card_number",
|
|
41
|
+
"cvv",
|
|
42
|
+
"iban",
|
|
43
|
+
"account_number",
|
|
44
|
+
"routing_number",
|
|
45
|
+
"phone",
|
|
46
|
+
"phone_number",
|
|
47
|
+
"mobile",
|
|
48
|
+
"email",
|
|
49
|
+
"email_address",
|
|
50
|
+
"address",
|
|
51
|
+
"street",
|
|
52
|
+
"postal_code",
|
|
53
|
+
"zip",
|
|
54
|
+
"dob",
|
|
55
|
+
"date_of_birth",
|
|
56
|
+
"first_name",
|
|
57
|
+
"last_name",
|
|
58
|
+
"full_name",
|
|
59
|
+
"passport",
|
|
60
|
+
"drivers_license",
|
|
61
|
+
];
|
|
62
|
+
const PII_FIELD_SET = new Set(PII_FIELD_NAMES.map((s) => s.toLowerCase()));
|
|
63
|
+
/**
|
|
64
|
+
* D15 regex pass — runs on `msg` strings (logs) and span attribute
|
|
65
|
+
* values when their key doesn't match a structured PII key but the
|
|
66
|
+
* value looks like a known PII pattern.
|
|
67
|
+
*
|
|
68
|
+
* Each regex is anchored loosely; matches are replaced with [REDACTED].
|
|
69
|
+
* Order matters: more-specific patterns first.
|
|
70
|
+
*/
|
|
71
|
+
const REGEX_PATTERNS = [
|
|
72
|
+
// Bearer tokens / JWT-shaped: 3 base64-ish segments separated by dots.
|
|
73
|
+
{
|
|
74
|
+
name: "jwt",
|
|
75
|
+
re: /\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b/g,
|
|
76
|
+
},
|
|
77
|
+
// Credit-card-like: 13–19 digits, possibly grouped by spaces or dashes.
|
|
78
|
+
{
|
|
79
|
+
name: "credit_card",
|
|
80
|
+
re: /\b(?:\d[ -]?){13,19}\b/g,
|
|
81
|
+
},
|
|
82
|
+
// Email addresses.
|
|
83
|
+
{
|
|
84
|
+
name: "email",
|
|
85
|
+
re: /\b[\w.!#$%&'*+/=?^`{|}~-]+@[\w-]+(?:\.[\w-]+)+\b/g,
|
|
86
|
+
},
|
|
87
|
+
// SSN-like: NNN-NN-NNNN.
|
|
88
|
+
{
|
|
89
|
+
name: "ssn",
|
|
90
|
+
re: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
91
|
+
},
|
|
92
|
+
// Phone-like (loose, intl): + then 10–15 digits with optional dashes/spaces.
|
|
93
|
+
{
|
|
94
|
+
name: "phone_intl",
|
|
95
|
+
re: /\+(?:\d[ -]?){10,15}\b/g,
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Returns true iff the key name matches the D2 PII field-name list.
|
|
100
|
+
* Comparison is case-insensitive on the bare key (no normalization
|
|
101
|
+
* beyond `toLowerCase()`).
|
|
102
|
+
*/
|
|
103
|
+
export function isPiiFieldName(key) {
|
|
104
|
+
return PII_FIELD_SET.has(key.toLowerCase());
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Redacts an arbitrary record by replacing values whose keys match the
|
|
108
|
+
* D2 PII list with `[REDACTED]`. Nested records are walked recursively.
|
|
109
|
+
* Arrays are walked element-by-element. Primitives at the top level are
|
|
110
|
+
* returned untouched (this function is for records only).
|
|
111
|
+
*
|
|
112
|
+
* Throws nothing under normal input; if a value is a non-serializable
|
|
113
|
+
* object (e.g. circular reference encountered via JSON.stringify
|
|
114
|
+
* elsewhere) the caller wraps this in `attemptRedaction()` to catch.
|
|
115
|
+
*/
|
|
116
|
+
export function redactFields(input) {
|
|
117
|
+
const out = {};
|
|
118
|
+
for (const [k, v] of Object.entries(input)) {
|
|
119
|
+
if (isPiiFieldName(k)) {
|
|
120
|
+
out[k] = REDACTED;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
out[k] = redactValue(v);
|
|
124
|
+
}
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
function redactValue(v) {
|
|
128
|
+
if (v === null || v === undefined)
|
|
129
|
+
return v;
|
|
130
|
+
if (typeof v === "string")
|
|
131
|
+
return redactString(v);
|
|
132
|
+
if (Array.isArray(v))
|
|
133
|
+
return v.map(redactValue);
|
|
134
|
+
if (typeof v === "object") {
|
|
135
|
+
return redactFields(v);
|
|
136
|
+
}
|
|
137
|
+
return v;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Apply the D15 regex pass to a string. Returns the redacted string.
|
|
141
|
+
* Each pattern that fires replaces its match with [REDACTED]; multiple
|
|
142
|
+
* matches per string are all replaced.
|
|
143
|
+
*/
|
|
144
|
+
export function redactString(s) {
|
|
145
|
+
let out = s;
|
|
146
|
+
for (const { re } of REGEX_PATTERNS) {
|
|
147
|
+
out = out.replace(re, REDACTED);
|
|
148
|
+
}
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
export function attemptRedactFields(input) {
|
|
152
|
+
try {
|
|
153
|
+
return { ok: true, redacted: redactFields(input) };
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
return {
|
|
157
|
+
ok: false,
|
|
158
|
+
reason: err instanceof Error ? err.name : "redaction_error",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
export function attemptRedactString(s) {
|
|
163
|
+
try {
|
|
164
|
+
return { ok: true, redacted: redactString(s) };
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
return {
|
|
168
|
+
ok: false,
|
|
169
|
+
reason: err instanceof Error ? err.name : "redaction_error",
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=redaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redaction.js","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type LabelMap = Record<string, string>;
|
|
2
|
+
interface CounterPoint {
|
|
3
|
+
name: string;
|
|
4
|
+
labels: LabelMap;
|
|
5
|
+
value: number;
|
|
6
|
+
}
|
|
7
|
+
/** Increment by 1 (default) or by `n`. Internal SDK use. */
|
|
8
|
+
export declare function incSdkCounter(name: string, labels?: LabelMap, n?: number): void;
|
|
9
|
+
/** Snapshot — used by the metrics flush path + tests. */
|
|
10
|
+
export declare function snapshotSdkCounters(): readonly CounterPoint[];
|
|
11
|
+
/** Test-only reset. NOT exported via the public barrel. */
|
|
12
|
+
export declare function _resetSdkCountersForTests(): void;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=sdk-counters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-counters.d.ts","sourceRoot":"","sources":["../src/sdk-counters.ts"],"names":[],"mappings":"AAWA,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEvC,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAYD,4DAA4D;AAC5D,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,QAAa,EACrB,CAAC,SAAI,GACJ,IAAI,CAQN;AAED,yDAAyD;AACzD,wBAAgB,mBAAmB,IAAI,SAAS,YAAY,EAAE,CAM7D;AAED,2DAA2D;AAC3D,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// SDK-internal observability counters. These exist BEFORE the public
|
|
2
|
+
// metrics API is wired (because the metrics module itself may report
|
|
3
|
+
// failures through them), so they are intentionally a tiny in-process
|
|
4
|
+
// map with a flush hook the metrics module reads.
|
|
5
|
+
//
|
|
6
|
+
// Counter names (locked):
|
|
7
|
+
// - `telemetry.sdk.redaction_failure_total{reason}` (D15 fail-closed drop)
|
|
8
|
+
// - `telemetry.sdk.cardinality_rejected_total{family, reason}` (D18)
|
|
9
|
+
// - `telemetry.sdk.export_failures_total{signal, reason}` (D153)
|
|
10
|
+
// - `telemetry.sdk.trace_propagation_missing_total` (§ 5.9)
|
|
11
|
+
const points = new Map();
|
|
12
|
+
function keyFor(name, labels) {
|
|
13
|
+
const labelStr = Object.entries(labels)
|
|
14
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
15
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
16
|
+
.join(",");
|
|
17
|
+
return `${name}|${labelStr}`;
|
|
18
|
+
}
|
|
19
|
+
/** Increment by 1 (default) or by `n`. Internal SDK use. */
|
|
20
|
+
export function incSdkCounter(name, labels = {}, n = 1) {
|
|
21
|
+
const k = keyFor(name, labels);
|
|
22
|
+
const existing = points.get(k);
|
|
23
|
+
if (existing) {
|
|
24
|
+
existing.value += n;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
points.set(k, { name, labels, value: n });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Snapshot — used by the metrics flush path + tests. */
|
|
31
|
+
export function snapshotSdkCounters() {
|
|
32
|
+
return Array.from(points.values()).map((p) => ({
|
|
33
|
+
name: p.name,
|
|
34
|
+
labels: { ...p.labels },
|
|
35
|
+
value: p.value,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
/** Test-only reset. NOT exported via the public barrel. */
|
|
39
|
+
export function _resetSdkCountersForTests() {
|
|
40
|
+
points.clear();
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=sdk-counters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sdk-counters.js","sourceRoot":"","sources":["../src/sdk-counters.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,qEAAqE;AACrE,sEAAsE;AACtE,kDAAkD;AAClD,EAAE;AACF,0BAA0B;AAC1B,6EAA6E;AAC7E,uEAAuE;AACvE,mEAAmE;AACnE,8DAA8D;AAU9D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAwB,CAAC;AAE/C,SAAS,MAAM,CAAC,IAAY,EAAE,MAAgB;IAC5C,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACpC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;SAC5B,IAAI,CAAC,GAAG,CAAC,CAAC;IACb,OAAO,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC;AAC/B,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,SAAmB,EAAE,EACrB,CAAC,GAAG,CAAC;IAEL,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,KAAK,IAAI,CAAC,CAAC;IACtB,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;AACH,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,mBAAmB;IACjC,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,MAAM,EAAE;QACvB,KAAK,EAAE,CAAC,CAAC,KAAK;KACf,CAAC,CAAC,CAAC;AACN,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,yBAAyB;IACvC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjB,CAAC"}
|
package/dist/tracer.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type SpanKind = "INTERNAL" | "SERVER" | "CLIENT" | "PRODUCER" | "CONSUMER";
|
|
2
|
+
export type SpanStatus = "UNSET" | "OK" | "ERROR";
|
|
3
|
+
export interface SpanRecord {
|
|
4
|
+
trace_id: string;
|
|
5
|
+
span_id: string;
|
|
6
|
+
parent_span_id: string | null;
|
|
7
|
+
name: string;
|
|
8
|
+
kind: SpanKind;
|
|
9
|
+
start_ns: bigint;
|
|
10
|
+
end_ns: bigint;
|
|
11
|
+
attributes: Record<string, unknown>;
|
|
12
|
+
status: SpanStatus;
|
|
13
|
+
status_message?: string;
|
|
14
|
+
events: SpanEvent[];
|
|
15
|
+
}
|
|
16
|
+
export interface SpanEvent {
|
|
17
|
+
name: string;
|
|
18
|
+
ts_ns: bigint;
|
|
19
|
+
attributes?: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
/** Per-span handle the caller manipulates while the span is live. */
|
|
22
|
+
export interface Span {
|
|
23
|
+
readonly trace_id: string;
|
|
24
|
+
readonly span_id: string;
|
|
25
|
+
setAttribute(key: string, value: unknown): void;
|
|
26
|
+
setAttributes(attrs: Record<string, unknown>): void;
|
|
27
|
+
addEvent(name: string, attributes?: Record<string, unknown>): void;
|
|
28
|
+
recordException(err: unknown): void;
|
|
29
|
+
setStatus(status: SpanStatus, message?: string): void;
|
|
30
|
+
}
|
|
31
|
+
/** Backend hook. TS-12 replaces the no-op with the OTel emitter. */
|
|
32
|
+
export interface SpanEmitter {
|
|
33
|
+
emit(record: SpanRecord): void;
|
|
34
|
+
}
|
|
35
|
+
export declare function _setSpanEmitter(e: SpanEmitter): void;
|
|
36
|
+
export declare function _resetSpanEmitterForTests(): void;
|
|
37
|
+
/**
|
|
38
|
+
* `tracer.span(name, fn)` opens a span, runs `fn`, then closes the
|
|
39
|
+
* span. Mandatory attributes stamped on start; D27 status mapping
|
|
40
|
+
* applied automatically.
|
|
41
|
+
*/
|
|
42
|
+
declare function span<T>(name: string, fn: (span: Span) => Promise<T> | T, opts?: {
|
|
43
|
+
kind?: SpanKind;
|
|
44
|
+
attributes?: Record<string, unknown>;
|
|
45
|
+
}): Promise<T>;
|
|
46
|
+
declare function withSpanAttributes<T>(attrs: Record<string, unknown>, fn: () => Promise<T> | T): Promise<T> | T;
|
|
47
|
+
/**
|
|
48
|
+
* `getSagaTracer()` — tactical hold per D149. Returns a tracer whose
|
|
49
|
+
* spans default to the SAGA shape (INTERNAL, parent=SERVER subtree).
|
|
50
|
+
* Sunsets at v0.2.0 when every service in D169 has adopted `@nodii/saga`.
|
|
51
|
+
*/
|
|
52
|
+
declare function getSagaTracer(): {
|
|
53
|
+
span<T>(name: string, fn: (span: Span) => Promise<T> | T, opts?: {
|
|
54
|
+
attributes?: Record<string, unknown>;
|
|
55
|
+
}): Promise<T>;
|
|
56
|
+
};
|
|
57
|
+
/** Test-only reset of active span stack. */
|
|
58
|
+
export declare function _resetTracerStackForTests(): void;
|
|
59
|
+
export declare const tracer: {
|
|
60
|
+
readonly span: typeof span;
|
|
61
|
+
};
|
|
62
|
+
export { withSpanAttributes, getSagaTracer };
|
|
63
|
+
//# sourceMappingURL=tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.d.ts","sourceRoot":"","sources":["../src/tracer.ts"],"names":[],"mappings":"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"}
|
package/dist/tracer.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Tracer per D26 / D27 / D28 / D30. Surface only; the real OTel wiring
|
|
2
|
+
// lands in TS-12 by replacing the in-process `SpanEmitter` via
|
|
3
|
+
// `_setSpanEmitter`. The default emitter is a no-op so tests can run
|
|
4
|
+
// without an OTLP endpoint.
|
|
5
|
+
//
|
|
6
|
+
// What's locked at v0.1.0:
|
|
7
|
+
// - `NodiiContextSpanProcessor` semantics in `_emitSpan`: stamps the
|
|
8
|
+
// three mandatory attributes (`tenant_id, request_id, intent_id`)
|
|
9
|
+
// onto every span on start (D26).
|
|
10
|
+
// - 4 KB per-value cap on attributes (truncates with `_truncated`
|
|
11
|
+
// marker). PII redaction applied to attribute values in `onEnd`
|
|
12
|
+
// (D26 + D15).
|
|
13
|
+
// - Status mapping (D27): if `recordException` ran or any error was
|
|
14
|
+
// attached, the span ends with status ERROR; otherwise UNSET.
|
|
15
|
+
// - `getSagaTracer()` ships as a tactical hold per D149; sunsets at
|
|
16
|
+
// v0.2.0.
|
|
17
|
+
import { getContext } from "./context";
|
|
18
|
+
import { _setActiveSpanGetter } from "./active-span";
|
|
19
|
+
import { attemptRedactFields } from "./redaction";
|
|
20
|
+
import { incSdkCounter } from "./sdk-counters";
|
|
21
|
+
import { uuidv7 } from "./uuid";
|
|
22
|
+
const noopEmitter = {
|
|
23
|
+
emit() {
|
|
24
|
+
/* no-op; TS-12 replaces */
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
let emitter = noopEmitter;
|
|
28
|
+
export function _setSpanEmitter(e) {
|
|
29
|
+
emitter = e;
|
|
30
|
+
}
|
|
31
|
+
export function _resetSpanEmitterForTests() {
|
|
32
|
+
emitter = noopEmitter;
|
|
33
|
+
}
|
|
34
|
+
const ATTR_VALUE_CAP_BYTES = 4 * 1024;
|
|
35
|
+
function capValue(v) {
|
|
36
|
+
if (typeof v !== "string")
|
|
37
|
+
return v;
|
|
38
|
+
if (Buffer.byteLength(v, "utf8") <= ATTR_VALUE_CAP_BYTES)
|
|
39
|
+
return v;
|
|
40
|
+
// Truncate by bytes — slice to the cap, mark.
|
|
41
|
+
const truncated = Buffer.from(v, "utf8")
|
|
42
|
+
.subarray(0, ATTR_VALUE_CAP_BYTES)
|
|
43
|
+
.toString("utf8");
|
|
44
|
+
return `${truncated}[_truncated=true]`;
|
|
45
|
+
}
|
|
46
|
+
function capAttributes(attrs) {
|
|
47
|
+
const out = {};
|
|
48
|
+
for (const [k, v] of Object.entries(attrs))
|
|
49
|
+
out[k] = capValue(v);
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Stack of active spans (per-async-scope discipline is ALS, not this stack). */
|
|
53
|
+
const activeStack = [];
|
|
54
|
+
// Wire the active-span getter so logger.ts can stamp trace_id / span_id.
|
|
55
|
+
_setActiveSpanGetter(() => {
|
|
56
|
+
const top = activeStack[activeStack.length - 1];
|
|
57
|
+
if (!top)
|
|
58
|
+
return null;
|
|
59
|
+
return { trace_id: top.trace_id, span_id: top.span_id };
|
|
60
|
+
});
|
|
61
|
+
/**
|
|
62
|
+
* `tracer.span(name, fn)` opens a span, runs `fn`, then closes the
|
|
63
|
+
* span. Mandatory attributes stamped on start; D27 status mapping
|
|
64
|
+
* applied automatically.
|
|
65
|
+
*/
|
|
66
|
+
async function span(name, fn, opts) {
|
|
67
|
+
const ctx = getContext();
|
|
68
|
+
const parent = activeStack[activeStack.length - 1];
|
|
69
|
+
const traceId = parent ? parent.trace_id : newTraceId();
|
|
70
|
+
const spanId = newSpanId();
|
|
71
|
+
const startNs = process.hrtime.bigint();
|
|
72
|
+
// D26 mandatory attributes envelope. tenant_id and request_id come
|
|
73
|
+
// from NodiiContext when present.
|
|
74
|
+
const record = {
|
|
75
|
+
trace_id: traceId,
|
|
76
|
+
span_id: spanId,
|
|
77
|
+
parent_span_id: parent?.span_id ?? null,
|
|
78
|
+
name,
|
|
79
|
+
kind: opts?.kind ?? "INTERNAL",
|
|
80
|
+
start_ns: startNs,
|
|
81
|
+
end_ns: 0n,
|
|
82
|
+
attributes: {
|
|
83
|
+
...(ctx
|
|
84
|
+
? {
|
|
85
|
+
tenant_id: ctx.tenant_id,
|
|
86
|
+
request_id: ctx.request_id,
|
|
87
|
+
intent_id: ctx.intent_id,
|
|
88
|
+
}
|
|
89
|
+
: {}),
|
|
90
|
+
...(opts?.attributes ? capAttributes(opts.attributes) : {}),
|
|
91
|
+
},
|
|
92
|
+
status: "UNSET",
|
|
93
|
+
events: [],
|
|
94
|
+
};
|
|
95
|
+
activeStack.push(record);
|
|
96
|
+
let recordedException = false;
|
|
97
|
+
const handle = {
|
|
98
|
+
trace_id: traceId,
|
|
99
|
+
span_id: spanId,
|
|
100
|
+
setAttribute(key, value) {
|
|
101
|
+
record.attributes[key] = capValue(value);
|
|
102
|
+
},
|
|
103
|
+
setAttributes(attrs) {
|
|
104
|
+
Object.assign(record.attributes, capAttributes(attrs));
|
|
105
|
+
},
|
|
106
|
+
addEvent(eventName, attributes) {
|
|
107
|
+
record.events.push({
|
|
108
|
+
name: eventName,
|
|
109
|
+
ts_ns: process.hrtime.bigint(),
|
|
110
|
+
attributes,
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
recordException(err) {
|
|
114
|
+
recordedException = true;
|
|
115
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
116
|
+
const stack = err instanceof Error ? err.stack : undefined;
|
|
117
|
+
record.events.push({
|
|
118
|
+
name: "exception",
|
|
119
|
+
ts_ns: process.hrtime.bigint(),
|
|
120
|
+
attributes: {
|
|
121
|
+
"exception.message": capValue(message),
|
|
122
|
+
"exception.stacktrace": stack ? capValue(stack) : undefined,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
},
|
|
126
|
+
setStatus(status, message) {
|
|
127
|
+
record.status = status;
|
|
128
|
+
record.status_message = message;
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
try {
|
|
132
|
+
const result = await fn(handle);
|
|
133
|
+
if (record.status === "UNSET")
|
|
134
|
+
record.status = "OK";
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
handle.recordException(err);
|
|
139
|
+
record.status = "ERROR";
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
if (recordedException && record.status !== "ERROR") {
|
|
144
|
+
// D27: recordException auto-paired with ERROR.
|
|
145
|
+
record.status = "ERROR";
|
|
146
|
+
}
|
|
147
|
+
record.end_ns = process.hrtime.bigint();
|
|
148
|
+
// D26 onEnd: PII redaction over attribute values. Fail-closed: if
|
|
149
|
+
// redaction throws, drop the span by NOT emitting + bump the
|
|
150
|
+
// counter. (We still pop the stack regardless.)
|
|
151
|
+
const redacted = attemptRedactFields(record.attributes);
|
|
152
|
+
if (redacted.ok) {
|
|
153
|
+
record.attributes = redacted.redacted;
|
|
154
|
+
emitter.emit(record);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
incSdkCounter("telemetry.sdk.redaction_failure_total", {
|
|
158
|
+
reason: redacted.reason,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
activeStack.pop();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
function newTraceId() {
|
|
165
|
+
// OTel trace_id is 16 bytes (32 hex). Reuse uuidv7's randomness path
|
|
166
|
+
// by stripping dashes from a fresh v7.
|
|
167
|
+
return uuidv7().replace(/-/g, "");
|
|
168
|
+
}
|
|
169
|
+
function newSpanId() {
|
|
170
|
+
// OTel span_id is 8 bytes (16 hex). Take the trailing 16 hex chars
|
|
171
|
+
// of a uuidv7 (the random tail, not the timestamp).
|
|
172
|
+
return uuidv7().replace(/-/g, "").slice(16, 32);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* `withSpanAttributes` per D149 § 5.3 ergonomic helper. Wraps a block
|
|
176
|
+
* so that every span opened inside it gets the supplied attributes
|
|
177
|
+
* merged onto its attribute envelope. Implementation: stores the
|
|
178
|
+
* attributes on a stack consulted by `tracer.span` at start.
|
|
179
|
+
*/
|
|
180
|
+
const attrScope = [];
|
|
181
|
+
function withSpanAttributes(attrs, fn) {
|
|
182
|
+
attrScope.push(attrs);
|
|
183
|
+
try {
|
|
184
|
+
return fn();
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
attrScope.pop();
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* `getSagaTracer()` — tactical hold per D149. Returns a tracer whose
|
|
192
|
+
* spans default to the SAGA shape (INTERNAL, parent=SERVER subtree).
|
|
193
|
+
* Sunsets at v0.2.0 when every service in D169 has adopted `@nodii/saga`.
|
|
194
|
+
*/
|
|
195
|
+
function getSagaTracer() {
|
|
196
|
+
return {
|
|
197
|
+
span(name, fn, opts) {
|
|
198
|
+
return span(name, fn, {
|
|
199
|
+
kind: "INTERNAL",
|
|
200
|
+
attributes: { "saga.tactical_hold": true, ...(opts?.attributes ?? {}) },
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** Test-only reset of active span stack. */
|
|
206
|
+
export function _resetTracerStackForTests() {
|
|
207
|
+
activeStack.length = 0;
|
|
208
|
+
attrScope.length = 0;
|
|
209
|
+
}
|
|
210
|
+
export const tracer = {
|
|
211
|
+
span,
|
|
212
|
+
};
|
|
213
|
+
export { withSpanAttributes, getSagaTracer };
|
|
214
|
+
//# sourceMappingURL=tracer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracer.js","sourceRoot":"","sources":["../src/tracer.ts"],"names":[],"mappings":"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"}
|