@provide-io/telemetry 0.2.2
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 +247 -0
- package/dist/backpressure.d.ts +19 -0
- package/dist/backpressure.d.ts.map +1 -0
- package/dist/backpressure.js +51 -0
- package/dist/cardinality.d.ts +15 -0
- package/dist/cardinality.d.ts.map +1 -0
- package/dist/cardinality.js +69 -0
- package/dist/classification.d.ts +29 -0
- package/dist/classification.d.ts.map +1 -0
- package/dist/classification.js +58 -0
- package/dist/config.d.ts +156 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +350 -0
- package/dist/consent.d.ts +11 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/consent.js +50 -0
- package/dist/context.d.ts +60 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +127 -0
- package/dist/exceptions.d.ts +14 -0
- package/dist/exceptions.d.ts.map +1 -0
- package/dist/exceptions.js +21 -0
- package/dist/fingerprint.d.ts +5 -0
- package/dist/fingerprint.d.ts.map +1 -0
- package/dist/fingerprint.js +50 -0
- package/dist/hash.d.ts +8 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +102 -0
- package/dist/health.d.ts +54 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +102 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +59 -0
- package/dist/logger.d.ts +28 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +254 -0
- package/dist/metrics.d.ts +78 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +238 -0
- package/dist/otel-logs.d.ts +29 -0
- package/dist/otel-logs.d.ts.map +1 -0
- package/dist/otel-logs.js +127 -0
- package/dist/otel-noop.d.ts +13 -0
- package/dist/otel-noop.d.ts.map +1 -0
- package/dist/otel-noop.js +5 -0
- package/dist/otel.d.ts +20 -0
- package/dist/otel.d.ts.map +1 -0
- package/dist/otel.js +80 -0
- package/dist/pii.d.ts +43 -0
- package/dist/pii.d.ts.map +1 -0
- package/dist/pii.js +278 -0
- package/dist/pretty.d.ts +12 -0
- package/dist/pretty.d.ts.map +1 -0
- package/dist/pretty.js +85 -0
- package/dist/propagation.d.ts +52 -0
- package/dist/propagation.d.ts.map +1 -0
- package/dist/propagation.js +183 -0
- package/dist/react.d.ts +38 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +72 -0
- package/dist/receipts.d.ts +26 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/receipts.js +69 -0
- package/dist/resilience.d.ts +26 -0
- package/dist/resilience.d.ts.map +1 -0
- package/dist/resilience.js +183 -0
- package/dist/runtime.d.ts +33 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +133 -0
- package/dist/sampling.d.ts +9 -0
- package/dist/sampling.d.ts.map +1 -0
- package/dist/sampling.js +53 -0
- package/dist/sanitize.d.ts +6 -0
- package/dist/sanitize.d.ts.map +1 -0
- package/dist/sanitize.js +7 -0
- package/dist/schema.d.ts +41 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +109 -0
- package/dist/shutdown.d.ts +2 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +15 -0
- package/dist/slo.d.ts +25 -0
- package/dist/slo.d.ts.map +1 -0
- package/dist/slo.js +115 -0
- package/dist/testing.d.ts +10 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +51 -0
- package/dist/tracing.d.ts +51 -0
- package/dist/tracing.d.ts.map +1 -0
- package/dist/tracing.js +181 -0
- package/package.json +139 -0
- package/src/backpressure.ts +68 -0
- package/src/cardinality.ts +83 -0
- package/src/classification.ts +87 -0
- package/src/config.ts +589 -0
- package/src/consent.ts +61 -0
- package/src/context.ts +157 -0
- package/src/exceptions.ts +24 -0
- package/src/fingerprint.ts +53 -0
- package/src/hash.ts +118 -0
- package/src/health.ts +175 -0
- package/src/index.ts +183 -0
- package/src/logger.ts +287 -0
- package/src/metrics.ts +204 -0
- package/src/otel-logs.ts +161 -0
- package/src/otel-noop.ts +19 -0
- package/src/otel.ts +112 -0
- package/src/pii.ts +358 -0
- package/src/pretty.ts +93 -0
- package/src/propagation.ts +222 -0
- package/src/react.ts +98 -0
- package/src/receipts.ts +97 -0
- package/src/resilience.ts +220 -0
- package/src/runtime.ts +171 -0
- package/src/sampling.ts +68 -0
- package/src/sanitize.ts +8 -0
- package/src/schema.ts +135 -0
- package/src/shutdown.ts +18 -0
- package/src/slo.ts +156 -0
- package/src/testing.ts +56 -0
- package/src/tracing.ts +211 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Attribute cardinality guardrails with TTL pruning.
|
|
6
|
+
* Mirrors Python provide.telemetry.cardinality.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface CardinalityLimit {
|
|
10
|
+
maxValues: number;
|
|
11
|
+
ttlSeconds: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const OVERFLOW_VALUE = '__overflow__';
|
|
15
|
+
|
|
16
|
+
const _limits = new Map<string, CardinalityLimit>();
|
|
17
|
+
/** key → (value → expiresAt timestamp ms) */
|
|
18
|
+
const _seen = new Map<string, Map<string, number>>();
|
|
19
|
+
const _lastPrune = new Map<string, number>();
|
|
20
|
+
const PRUNE_INTERVAL_MS = 5000;
|
|
21
|
+
|
|
22
|
+
export function registerCardinalityLimit(key: string, limit: CardinalityLimit): void {
|
|
23
|
+
_limits.set(key, {
|
|
24
|
+
maxValues: Math.max(1, limit.maxValues),
|
|
25
|
+
ttlSeconds: Math.max(1, limit.ttlSeconds),
|
|
26
|
+
});
|
|
27
|
+
// Stryker disable next-line ConditionalExpression: equivalent mutant — guardAttributes line 64 has a ?? fallback that compensates if _seen entry is absent
|
|
28
|
+
if (!_seen.has(key)) _seen.set(key, new Map());
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function getCardinalityLimits(): Map<string, CardinalityLimit> {
|
|
32
|
+
return new Map(_limits);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function clearCardinalityLimits(): void {
|
|
36
|
+
_limits.clear();
|
|
37
|
+
_seen.clear();
|
|
38
|
+
_lastPrune.clear();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function _pruneExpired(key: string, now: number): void {
|
|
42
|
+
const limit = _limits.get(key);
|
|
43
|
+
const seen = _seen.get(key);
|
|
44
|
+
// Stryker disable next-line ConditionalExpression,LogicalOperator: defensive guard — _pruneExpired is only called from guardAttributes after _limits.get(key) succeeds
|
|
45
|
+
/* v8 ignore next 2 */
|
|
46
|
+
if (!limit || !seen) return;
|
|
47
|
+
const threshold = now - limit.ttlSeconds * 1000;
|
|
48
|
+
for (const [value, seenAt] of seen) {
|
|
49
|
+
if (seenAt < threshold) seen.delete(value);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function guardAttributes(attrs: Record<string, string>): Record<string, string> {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const result = { ...attrs };
|
|
56
|
+
for (const [key, value] of Object.entries(result)) {
|
|
57
|
+
const limit = _limits.get(key);
|
|
58
|
+
if (!limit) continue;
|
|
59
|
+
const lastPrune = _lastPrune.get(key) ?? 0;
|
|
60
|
+
// Stryker disable next-line ConditionalExpression,ArithmeticOperator: early prune is a no-op (only deletes expired values); now+lastPrune equivalent because fresh values are always within TTL
|
|
61
|
+
if (now - lastPrune >= PRUNE_INTERVAL_MS) {
|
|
62
|
+
_pruneExpired(key, now);
|
|
63
|
+
_lastPrune.set(key, now);
|
|
64
|
+
}
|
|
65
|
+
/* v8 ignore next */
|
|
66
|
+
const seen = _seen.get(key) ?? new Map<string, number>();
|
|
67
|
+
if (seen.has(value)) {
|
|
68
|
+
seen.set(value, now);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (seen.size >= limit.maxValues) {
|
|
72
|
+
result[key] = OVERFLOW_VALUE;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
seen.set(value, now);
|
|
76
|
+
_seen.set(key, seen);
|
|
77
|
+
}
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function _resetCardinalityForTests(): void {
|
|
82
|
+
clearCardinalityLimits();
|
|
83
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright (c) 2025-2026 provide.io llc. All rights reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Data classification engine — strippable governance module.
|
|
6
|
+
*
|
|
7
|
+
* Registers a classification hook on the PII engine when rules are configured.
|
|
8
|
+
* If this file is deleted, the PII engine runs unchanged (hook stays null).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { setClassificationHook } from './pii';
|
|
12
|
+
|
|
13
|
+
/** Data classification labels. */
|
|
14
|
+
export type DataClass = 'PUBLIC' | 'INTERNAL' | 'PII' | 'PHI' | 'PCI' | 'SECRET';
|
|
15
|
+
|
|
16
|
+
/** Maps a glob pattern to a DataClass label. */
|
|
17
|
+
export interface ClassificationRule {
|
|
18
|
+
pattern: string;
|
|
19
|
+
classification: DataClass;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Defines the action to take per DataClass. */
|
|
23
|
+
export interface ClassificationPolicy {
|
|
24
|
+
PUBLIC: string;
|
|
25
|
+
INTERNAL: string;
|
|
26
|
+
PII: string;
|
|
27
|
+
PHI: string;
|
|
28
|
+
PCI: string;
|
|
29
|
+
SECRET: string;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const _DEFAULT_POLICY: ClassificationPolicy = {
|
|
33
|
+
PUBLIC: 'pass',
|
|
34
|
+
INTERNAL: 'pass',
|
|
35
|
+
PII: 'redact',
|
|
36
|
+
PHI: 'drop',
|
|
37
|
+
PCI: 'hash',
|
|
38
|
+
SECRET: 'drop', // pragma: allowlist secret
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// Stryker disable next-line ArrayDeclaration
|
|
42
|
+
const _rules: ClassificationRule[] = [];
|
|
43
|
+
let _policy: ClassificationPolicy = { ..._DEFAULT_POLICY };
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Convert a glob pattern (supporting * wildcards) to a RegExp.
|
|
47
|
+
* Only * is treated as a wildcard; all other regex special chars are escaped.
|
|
48
|
+
*/
|
|
49
|
+
function matchGlob(pattern: string, key: string): boolean {
|
|
50
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
|
|
51
|
+
return new RegExp(`^${escaped}$`).test(key);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Register classification rules and install the classification hook on the PII engine.
|
|
56
|
+
*/
|
|
57
|
+
export function registerClassificationRules(rules: ClassificationRule[]): void {
|
|
58
|
+
_rules.push(...rules);
|
|
59
|
+
setClassificationHook(_classifyField);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Replace the current classification policy. */
|
|
63
|
+
export function setClassificationPolicy(policy: ClassificationPolicy): void {
|
|
64
|
+
_policy = { ...policy };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Return the current classification policy. */
|
|
68
|
+
export function getClassificationPolicy(): ClassificationPolicy {
|
|
69
|
+
return { ..._policy };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Return the DataClass label for a key if a rule matches, else null. */
|
|
73
|
+
export function _classifyField(key: string, _value: unknown): string | null {
|
|
74
|
+
for (const rule of _rules) {
|
|
75
|
+
if (matchGlob(rule.pattern, key)) {
|
|
76
|
+
return rule.classification;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Reset all classification state and remove the hook (test helper). */
|
|
83
|
+
export function resetClassificationForTests(): void {
|
|
84
|
+
_rules.length = 0;
|
|
85
|
+
_policy = { ..._DEFAULT_POLICY };
|
|
86
|
+
setClassificationHook(null);
|
|
87
|
+
}
|