@ogcio/o11y-sdk-node 0.3.0 → 0.4.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/CHANGELOG.md +21 -0
- package/dist/lib/exporter/pii-exporter-decorator.d.ts +3 -1
- package/dist/lib/exporter/pii-exporter-decorator.js +33 -17
- package/dist/lib/index.d.ts +5 -0
- package/dist/lib/instrumentation.node.js +0 -8
- package/dist/lib/internals/redaction/pii-detection.d.ts +23 -0
- package/dist/lib/internals/redaction/pii-detection.js +87 -0
- package/dist/lib/internals/redaction/redactors/email.d.ts +8 -0
- package/dist/lib/internals/redaction/redactors/email.js +48 -0
- package/dist/lib/internals/redaction/redactors/index.d.ts +4 -0
- package/dist/lib/internals/redaction/redactors/index.js +6 -0
- package/dist/lib/internals/redaction/redactors/ip.d.ts +10 -0
- package/dist/lib/internals/redaction/redactors/ip.js +54 -0
- package/dist/lib/processor/enrich-logger-processor.d.ts +2 -2
- package/dist/package.json +14 -14
- package/dist/vitest.config.js +4 -4
- package/lib/exporter/pii-exporter-decorator.ts +56 -24
- package/lib/index.ts +5 -0
- package/lib/instrumentation.node.ts +0 -10
- package/lib/internals/redaction/pii-detection.ts +126 -0
- package/lib/internals/redaction/redactors/email.ts +58 -0
- package/lib/internals/redaction/redactors/index.ts +12 -0
- package/lib/internals/redaction/redactors/ip.ts +68 -0
- package/lib/internals/shared-metrics.ts +1 -1
- package/lib/processor/enrich-logger-processor.ts +2 -2
- package/package.json +14 -14
- package/test/exporter/pii-exporter-decorator.test.ts +75 -126
- package/test/internals/pii-detection.test.ts +27 -25
- package/test/internals/redactors/email.test.ts +81 -0
- package/test/internals/redactors/ip.test.ts +89 -0
- package/test/traces/active-span.test.ts +1 -1
- package/vitest.config.ts +4 -4
- package/dist/lib/internals/pii-detection.d.ts +0 -17
- package/dist/lib/internals/pii-detection.js +0 -116
- package/lib/internals/pii-detection.ts +0 -145
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.0](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.3.1...@ogcio/o11y-sdk-node@v0.4.0) (2025-09-02)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* o11y react-sdk IP pii redaction AB[#30758](https://github.com/ogcio/o11y/issues/30758) ([#196](https://github.com/ogcio/o11y/issues/196)) ([d6bb83f](https://github.com/ogcio/o11y/commit/d6bb83fa425ffdf3fb023ec62caeef070995d07a))
|
|
9
|
+
* pii redaction refactor and ip redaction support AB[#30042](https://github.com/ogcio/o11y/issues/30042) AB[#30043](https://github.com/ogcio/o11y/issues/30043) ([#195](https://github.com/ogcio/o11y/issues/195)) ([3074693](https://github.com/ogcio/o11y/commit/307469399a7b03f3b647d85a2249e3c86dce933f))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Miscellaneous Chores
|
|
13
|
+
|
|
14
|
+
* **deps:** bump the root-deps group across 1 directory with 16 updates ([#193](https://github.com/ogcio/o11y/issues/193)) ([c523565](https://github.com/ogcio/o11y/commit/c523565a6ba7f327473e8d93afc7d532ac220457))
|
|
15
|
+
* **deps:** bump the root-deps group across 3 directories with 34 updates ([#188](https://github.com/ogcio/o11y/issues/188)) ([c0059f3](https://github.com/ogcio/o11y/commit/c0059f33cbb5c39cf6df0f4640604796dbbd3f57))
|
|
16
|
+
|
|
17
|
+
## [0.3.1](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.3.0...@ogcio/o11y-sdk-node@v0.3.1) (2025-07-31)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* **sdk-node:** replace Object.assign with spread operator on log redaction ([#186](https://github.com/ogcio/o11y/issues/186)) ([432f8d6](https://github.com/ogcio/o11y/commit/432f8d6aa493fd01d093f7ecdd0a9faccd0726e9))
|
|
23
|
+
|
|
3
24
|
## [0.3.0](https://github.com/ogcio/o11y/compare/@ogcio/o11y-sdk-node@v0.2.0...@ogcio/o11y-sdk-node@v0.3.0) (2025-07-28)
|
|
4
25
|
|
|
5
26
|
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ExportResult } from "@opentelemetry/core";
|
|
2
2
|
import { OTLPExporterBase } from "@opentelemetry/otlp-exporter-base";
|
|
3
3
|
import { ReadableLogRecord } from "@opentelemetry/sdk-logs";
|
|
4
|
+
import { PushMetricExporter, ResourceMetrics } from "@opentelemetry/sdk-metrics";
|
|
4
5
|
import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base";
|
|
5
6
|
import { NodeSDKConfig } from "../index.js";
|
|
6
|
-
import { PushMetricExporter, ResourceMetrics } from "@opentelemetry/sdk-metrics";
|
|
7
7
|
export declare class PIIExporterDecorator extends OTLPExporterBase<(ReadableSpan | ReadableLogRecord)[] | ResourceMetrics> implements SpanExporter, PushMetricExporter {
|
|
8
8
|
private readonly _exporter;
|
|
9
9
|
private readonly _config;
|
|
10
|
+
private readonly _redactors;
|
|
10
11
|
constructor(exporter: OTLPExporterBase<(ReadableSpan | ReadableLogRecord)[] | ResourceMetrics>, config: NodeSDKConfig);
|
|
11
12
|
forceFlush(): Promise<void>;
|
|
12
13
|
shutdown(): Promise<void>;
|
|
@@ -17,4 +18,5 @@ export declare class PIIExporterDecorator extends OTLPExporterBase<(ReadableSpan
|
|
|
17
18
|
private _redactSpan;
|
|
18
19
|
private _redactLogRecord;
|
|
19
20
|
private _redactResourceMetrics;
|
|
21
|
+
private _buildRedactors;
|
|
20
22
|
}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { OTLPExporterBase } from "@opentelemetry/otlp-exporter-base";
|
|
2
|
-
import { _cleanLogBodyPII, _cleanObjectPII, _cleanStringPII, } from "../internals/pii-detection.js";
|
|
2
|
+
import { _cleanLogBodyPII, _cleanObjectPII, _cleanStringPII, } from "../internals/redaction/pii-detection.js";
|
|
3
|
+
import { redactors, } from "../internals/redaction/redactors/index.js";
|
|
3
4
|
export class PIIExporterDecorator extends OTLPExporterBase {
|
|
4
5
|
_exporter;
|
|
5
6
|
_config;
|
|
7
|
+
_redactors;
|
|
6
8
|
constructor(exporter, config) {
|
|
7
9
|
super(exporter["_delegate"]);
|
|
8
10
|
this._exporter = exporter;
|
|
9
11
|
this._config = config;
|
|
12
|
+
this._redactors = this._buildRedactors(config.detection);
|
|
10
13
|
}
|
|
11
14
|
forceFlush() {
|
|
12
15
|
return this._exporter.forceFlush();
|
|
@@ -15,7 +18,7 @@ export class PIIExporterDecorator extends OTLPExporterBase {
|
|
|
15
18
|
return this._exporter.shutdown();
|
|
16
19
|
}
|
|
17
20
|
export(items, resultCallback) {
|
|
18
|
-
if (
|
|
21
|
+
if (this._redactors.length === 0) {
|
|
19
22
|
this._exporter.export(items, resultCallback);
|
|
20
23
|
return;
|
|
21
24
|
}
|
|
@@ -25,7 +28,7 @@ export class PIIExporterDecorator extends OTLPExporterBase {
|
|
|
25
28
|
this._redactSpan(item);
|
|
26
29
|
}
|
|
27
30
|
else if (this._isReadableLogRecord(item)) {
|
|
28
|
-
this._redactLogRecord(item);
|
|
31
|
+
item = this._redactLogRecord(item);
|
|
29
32
|
}
|
|
30
33
|
return item;
|
|
31
34
|
});
|
|
@@ -62,42 +65,55 @@ export class PIIExporterDecorator extends OTLPExporterBase {
|
|
|
62
65
|
}
|
|
63
66
|
_redactSpan(span) {
|
|
64
67
|
Object.assign(span, {
|
|
65
|
-
name: _cleanStringPII(span.name, "trace"),
|
|
66
|
-
attributes: span.attributes &&
|
|
68
|
+
name: _cleanStringPII(span.name, "trace", this._redactors),
|
|
69
|
+
attributes: span.attributes &&
|
|
70
|
+
_cleanObjectPII(span.attributes, "trace", this._redactors),
|
|
67
71
|
resource: {
|
|
68
72
|
attributes: span?.resource?.attributes &&
|
|
69
|
-
_cleanObjectPII(span.resource.attributes, "trace"),
|
|
73
|
+
_cleanObjectPII(span.resource.attributes, "trace", this._redactors),
|
|
70
74
|
},
|
|
71
75
|
links: span?.links?.map((link) => {
|
|
72
76
|
Object.assign(link, {
|
|
73
|
-
attributes: link?.attributes &&
|
|
77
|
+
attributes: link?.attributes &&
|
|
78
|
+
_cleanObjectPII(link.attributes, "trace", this._redactors),
|
|
74
79
|
});
|
|
75
80
|
}),
|
|
76
81
|
events: span?.events?.map((event) => {
|
|
77
82
|
Object.assign(event, {
|
|
78
|
-
name: _cleanStringPII(event.name, "trace"),
|
|
79
|
-
attributes: event?.attributes &&
|
|
83
|
+
name: _cleanStringPII(event.name, "trace", this._redactors),
|
|
84
|
+
attributes: event?.attributes &&
|
|
85
|
+
_cleanObjectPII(event.attributes, "trace", this._redactors),
|
|
80
86
|
});
|
|
81
87
|
return event;
|
|
82
88
|
}),
|
|
83
89
|
});
|
|
84
90
|
}
|
|
85
91
|
_redactLogRecord(log) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
attributes
|
|
91
|
-
|
|
92
|
+
return {
|
|
93
|
+
...log,
|
|
94
|
+
body: _cleanLogBodyPII(log.body, this._redactors),
|
|
95
|
+
attributes: log.attributes &&
|
|
96
|
+
_cleanObjectPII(log.attributes, "log", this._redactors),
|
|
97
|
+
resource: log.resource && {
|
|
98
|
+
...log.resource,
|
|
99
|
+
attributes: _cleanObjectPII(log.resource.attributes, "log", this._redactors),
|
|
92
100
|
},
|
|
93
|
-
}
|
|
101
|
+
};
|
|
94
102
|
}
|
|
95
103
|
_redactResourceMetrics(metric) {
|
|
96
104
|
Object.assign(metric, {
|
|
97
105
|
resource: {
|
|
98
106
|
attributes: metric?.resource?.attributes &&
|
|
99
|
-
_cleanObjectPII(metric.resource.attributes, "metric"),
|
|
107
|
+
_cleanObjectPII(metric.resource.attributes, "metric", this._redactors),
|
|
100
108
|
},
|
|
101
109
|
});
|
|
102
110
|
}
|
|
111
|
+
// Default opt-in every redactor available, excluding only those explicitly configured to false
|
|
112
|
+
_buildRedactors(redactorsConfig = {}) {
|
|
113
|
+
return Object.entries(redactors)
|
|
114
|
+
.filter(([key]) => {
|
|
115
|
+
return redactorsConfig[key] !== false;
|
|
116
|
+
})
|
|
117
|
+
.map(([_, value]) => value);
|
|
118
|
+
}
|
|
103
119
|
}
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -23,14 +23,6 @@ export default async function buildNodeInstrumentation(config) {
|
|
|
23
23
|
console.error("collectorUrl does not use a valid format. Skipping NodeJS OpenTelemetry instrumentation.");
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
if (!config.detection) {
|
|
27
|
-
config.detection = {
|
|
28
|
-
email: true,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
if (config.detection.email === undefined) {
|
|
32
|
-
config.detection.email = true;
|
|
33
|
-
}
|
|
34
26
|
// Init configManager to make it available to all o11y utils.
|
|
35
27
|
setNodeSdkConfig(config);
|
|
36
28
|
const urlSampler = new UrlSampler(config.ignoreUrls, new TraceIdRatioBasedSampler(config.traceRatio ?? 1));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AnyValue } from "@opentelemetry/api-logs";
|
|
2
|
+
import { Redactor } from "./redactors/index.js";
|
|
3
|
+
import { AttributeValue } from "@opentelemetry/api";
|
|
4
|
+
export type PIISource = "trace" | "log" | "metric";
|
|
5
|
+
/**
|
|
6
|
+
* Cleans a string by redacting configured PIIs and emitting metrics for redacted values.
|
|
7
|
+
*
|
|
8
|
+
* If the string is URL-encoded, it will be decoded before redaction.
|
|
9
|
+
* Metrics are emitted for:
|
|
10
|
+
* - each domain found in redacted email addresses.
|
|
11
|
+
* - IPv4|IPv6 addresses redacted.
|
|
12
|
+
*
|
|
13
|
+
* @template T
|
|
14
|
+
*
|
|
15
|
+
* @param {T} value - The input value to sanitize.
|
|
16
|
+
* @param {"trace" | "log"} source - The source context of the input, used in metrics.
|
|
17
|
+
* @param {Redactor[]} redactors - The string processors containing the redaction logic.
|
|
18
|
+
*
|
|
19
|
+
* @returns {T} The cleaned string with any configured PII replaced by `[REDACTED PII_TYPE]`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function _cleanStringPII<T extends AnyValue>(value: T, source: PIISource, redactors: Redactor[]): T;
|
|
22
|
+
export declare function _cleanObjectPII(entry: object, source: PIISource, redactors: Redactor[]): Record<string, AttributeValue>;
|
|
23
|
+
export declare function _cleanLogBodyPII<T extends AnyValue>(value: T, redactors: Redactor[]): T;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const decoder = new TextDecoder();
|
|
2
|
+
const encoder = new TextEncoder();
|
|
3
|
+
/**
|
|
4
|
+
* Checks whether a string contains URI-encoded components.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} value - The string to inspect.
|
|
7
|
+
* @returns {boolean} `true` if the string is encoded, `false` otherwise.
|
|
8
|
+
*/
|
|
9
|
+
function _containsEncodedComponents(value) {
|
|
10
|
+
try {
|
|
11
|
+
return decodeURI(value) !== decodeURIComponent(value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Cleans a string by redacting configured PIIs and emitting metrics for redacted values.
|
|
19
|
+
*
|
|
20
|
+
* If the string is URL-encoded, it will be decoded before redaction.
|
|
21
|
+
* Metrics are emitted for:
|
|
22
|
+
* - each domain found in redacted email addresses.
|
|
23
|
+
* - IPv4|IPv6 addresses redacted.
|
|
24
|
+
*
|
|
25
|
+
* @template T
|
|
26
|
+
*
|
|
27
|
+
* @param {T} value - The input value to sanitize.
|
|
28
|
+
* @param {"trace" | "log"} source - The source context of the input, used in metrics.
|
|
29
|
+
* @param {Redactor[]} redactors - The string processors containing the redaction logic.
|
|
30
|
+
*
|
|
31
|
+
* @returns {T} The cleaned string with any configured PII replaced by `[REDACTED PII_TYPE]`.
|
|
32
|
+
*/
|
|
33
|
+
export function _cleanStringPII(value, source, redactors) {
|
|
34
|
+
if (Array.isArray(value)) {
|
|
35
|
+
return value.map((v) => _cleanStringPII(v, source, redactors));
|
|
36
|
+
}
|
|
37
|
+
if (typeof value !== "string") {
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
let kind = "string";
|
|
41
|
+
let decodedValue = value;
|
|
42
|
+
if (_containsEncodedComponents(value)) {
|
|
43
|
+
decodedValue = decodeURIComponent(value);
|
|
44
|
+
kind = "url";
|
|
45
|
+
}
|
|
46
|
+
return redactors.reduce((redactedValue, currentRedactor) => currentRedactor(redactedValue, source, kind), decodedValue);
|
|
47
|
+
}
|
|
48
|
+
export function _cleanObjectPII(entry, source, redactors) {
|
|
49
|
+
if (!entry) {
|
|
50
|
+
return entry;
|
|
51
|
+
}
|
|
52
|
+
return Object.fromEntries(Object.entries(entry).map(([k, v]) => [
|
|
53
|
+
k,
|
|
54
|
+
_cleanStringPII(v, source, redactors),
|
|
55
|
+
]));
|
|
56
|
+
}
|
|
57
|
+
export function _cleanLogBodyPII(value, redactors) {
|
|
58
|
+
if (typeof value === "string") {
|
|
59
|
+
return _cleanStringPII(value, "log", redactors);
|
|
60
|
+
}
|
|
61
|
+
if (typeof value === "number" ||
|
|
62
|
+
typeof value === "boolean" ||
|
|
63
|
+
value == null) {
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
if (value instanceof Uint8Array) {
|
|
67
|
+
try {
|
|
68
|
+
const decoded = decoder.decode(value);
|
|
69
|
+
const sanitized = _cleanStringPII(decoded, "log", redactors);
|
|
70
|
+
return encoder.encode(sanitized);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (Array.isArray(value)) {
|
|
77
|
+
return value.map((value) => _cleanLogBodyPII(value, redactors));
|
|
78
|
+
}
|
|
79
|
+
if (typeof value === "object") {
|
|
80
|
+
const sanitized = {};
|
|
81
|
+
for (const [key, val] of Object.entries(value)) {
|
|
82
|
+
sanitized[key] = _cleanLogBodyPII(val, redactors);
|
|
83
|
+
}
|
|
84
|
+
return sanitized;
|
|
85
|
+
}
|
|
86
|
+
return value;
|
|
87
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redacts provided input and collects metadata metrics about redacted email domains,
|
|
3
|
+
* data source and kind.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} value The input string potentially containing email addresses.
|
|
6
|
+
* @returns {string} the redacted value
|
|
7
|
+
*/
|
|
8
|
+
export declare const emailRedactor: (value: string, source: string, kind: string) => string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { _getPIICounterRedactionMetric } from "../../shared-metrics.js";
|
|
2
|
+
const EMAIL_REGEX = /[\p{L}\p{N}._%+-]+@((?:[\p{L}\p{N}-]+\.)+[\p{L}]{2,})/giu;
|
|
3
|
+
/**
|
|
4
|
+
* Redacts all email addresses in the input string and collects metadata.
|
|
5
|
+
*
|
|
6
|
+
* @param {string} value The input string potentially containing email addresses.
|
|
7
|
+
* @returns {{
|
|
8
|
+
* redacted: string,
|
|
9
|
+
* count: number,
|
|
10
|
+
* domains: Record<string, number>
|
|
11
|
+
* }}
|
|
12
|
+
*
|
|
13
|
+
* An object containing:
|
|
14
|
+
* - `redacted`: the string with email addresses replaced by `[REDACTED EMAIL]`
|
|
15
|
+
* - `count`: total number of email addresses redacted
|
|
16
|
+
* - `domains`: a map of domain names to the number of times they were redacted
|
|
17
|
+
*/
|
|
18
|
+
function _redactEmails(value) {
|
|
19
|
+
let count = 0;
|
|
20
|
+
const domains = {};
|
|
21
|
+
const redacted = value.replace(EMAIL_REGEX, (_, domain) => {
|
|
22
|
+
count++;
|
|
23
|
+
domains[domain] = (domains[domain] || 0) + 1;
|
|
24
|
+
return "[REDACTED EMAIL]";
|
|
25
|
+
});
|
|
26
|
+
return { redacted, count, domains };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Redacts provided input and collects metadata metrics about redacted email domains,
|
|
30
|
+
* data source and kind.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} value The input string potentially containing email addresses.
|
|
33
|
+
* @returns {string} the redacted value
|
|
34
|
+
*/
|
|
35
|
+
export const emailRedactor = (value, source, kind) => {
|
|
36
|
+
const { redacted, count, domains } = _redactEmails(value);
|
|
37
|
+
if (count > 0) {
|
|
38
|
+
for (const [domain, domainCount] of Object.entries(domains)) {
|
|
39
|
+
_getPIICounterRedactionMetric().add(domainCount, {
|
|
40
|
+
pii_type: "email",
|
|
41
|
+
redaction_source: source,
|
|
42
|
+
pii_email_domain: domain,
|
|
43
|
+
pii_format: kind,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return redacted;
|
|
48
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { NodeSDKConfig } from "../../../index.js";
|
|
2
|
+
export type Redactor = (value: string, source: string, kind: string) => string;
|
|
3
|
+
export type RedactorKeys = keyof NonNullable<NodeSDKConfig["detection"]>;
|
|
4
|
+
export declare const redactors: Record<RedactorKeys, Redactor>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redacts provided input and collects metadata metrics about redacted IPs,
|
|
3
|
+
* data source and kind.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} value The input string potentially containing IP addresses.
|
|
6
|
+
* @param {string} source The source of the attribute being redacted (log, span, metric).
|
|
7
|
+
* @param {string} kind The type of the data structure containing the PII
|
|
8
|
+
* @returns {string} the redacted value
|
|
9
|
+
*/
|
|
10
|
+
export declare const ipRedactor: (value: string, source: string, kind: string) => string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { _getPIICounterRedactionMetric } from "../../shared-metrics.js";
|
|
2
|
+
// Generous IP address matchers (might match some invalid addresses like 192.168.01.1)
|
|
3
|
+
const IPV4_REGEX = /(?<!\d)(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}(?!\d)/gi;
|
|
4
|
+
const IPV6_REGEX = /(?<![0-9a-f:])((?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,7}:|:(?::[0-9A-Fa-f]{1,4}){1,7}|(?:[0-9A-Fa-f]{1,4}:){1,6}:[0-9A-Fa-f]{1,4}|(?:[0-9A-Fa-f]{1,4}:){1,5}(?::[0-9A-Fa-f]{1,4}){1,2}|(?:[0-9A-Fa-f]{1,4}:){1,4}(?::[0-9A-Fa-f]{1,4}){1,3}|(?:[0-9A-Fa-f]{1,4}:){1,3}(?::[0-9A-Fa-f]{1,4}){1,4}|(?:[0-9A-Fa-f]{1,4}:){1,2}(?::[0-9A-Fa-f]{1,4}){1,5}|[0-9A-Fa-f]{1,4}:(?::[0-9A-Fa-f]{1,4}){1,6}|:(?::[0-9A-Fa-f]{1,4}){1,7}:?|(?:[0-9A-Fa-f]{1,4}:){1,4}:(?:25[0-5]|2[0-4]\d|1\d\d|\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|\d{1,2})){3})(?![0-9a-f:])/gi;
|
|
5
|
+
/**
|
|
6
|
+
* Redacts all ip addresses in the input string and collects metadata.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} value The input string potentially containing ip addresses.
|
|
9
|
+
* @returns {{
|
|
10
|
+
* redacted: string,
|
|
11
|
+
* count: number,
|
|
12
|
+
* domains: Record<string, number>
|
|
13
|
+
* }}
|
|
14
|
+
*
|
|
15
|
+
* An object containing:
|
|
16
|
+
* - `redacted`: the string with IP addresses replaced by `[REDACTED IPV*]`
|
|
17
|
+
* - `counters`: total number of addresses redacted by IPv* type
|
|
18
|
+
* - `domains`: a map of domain names to the number of times they were redacted
|
|
19
|
+
*/
|
|
20
|
+
function _redactIps(value) {
|
|
21
|
+
const counters = {};
|
|
22
|
+
const redacted = value
|
|
23
|
+
.replace(IPV4_REGEX, () => {
|
|
24
|
+
counters["IPv4"] = (counters["IPv4"] || 0) + 1;
|
|
25
|
+
return "[REDACTED IPV4]";
|
|
26
|
+
})
|
|
27
|
+
.replace(IPV6_REGEX, () => {
|
|
28
|
+
counters["IPv4"] = (counters["IPv4"] || 0) + 1;
|
|
29
|
+
return "[REDACTED IPV6]";
|
|
30
|
+
});
|
|
31
|
+
return { redacted, counters };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Redacts provided input and collects metadata metrics about redacted IPs,
|
|
35
|
+
* data source and kind.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} value The input string potentially containing IP addresses.
|
|
38
|
+
* @param {string} source The source of the attribute being redacted (log, span, metric).
|
|
39
|
+
* @param {string} kind The type of the data structure containing the PII
|
|
40
|
+
* @returns {string} the redacted value
|
|
41
|
+
*/
|
|
42
|
+
export const ipRedactor = (value, source, kind) => {
|
|
43
|
+
const { redacted, counters } = _redactIps(value);
|
|
44
|
+
Object.entries(counters).forEach(([type, counter]) => {
|
|
45
|
+
if (counter > 0) {
|
|
46
|
+
_getPIICounterRedactionMetric().add(counter, {
|
|
47
|
+
pii_type: type,
|
|
48
|
+
redaction_source: source,
|
|
49
|
+
pii_format: kind,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return redacted;
|
|
54
|
+
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SdkLogRecord, LogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
2
2
|
import { Context } from "@opentelemetry/api";
|
|
3
3
|
import { SignalAttributeValue } from "../index.js";
|
|
4
4
|
export declare class EnrichLogProcessor implements LogRecordProcessor {
|
|
5
5
|
private _spanAttributes?;
|
|
6
6
|
constructor(spanAttributes?: Record<string, SignalAttributeValue | (() => SignalAttributeValue)>);
|
|
7
7
|
forceFlush(): Promise<void>;
|
|
8
|
-
onEmit(logRecord:
|
|
8
|
+
onEmit(logRecord: SdkLogRecord, _context?: Context): void;
|
|
9
9
|
shutdown(): Promise<void>;
|
|
10
10
|
}
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ogcio/o11y-sdk-node",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Opentelemetry standard instrumentation SDK for NodeJS based project",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,26 +30,26 @@
|
|
|
30
30
|
"@grpc/grpc-js": "^1.13.4",
|
|
31
31
|
"@opentelemetry/api": "^1.9.0",
|
|
32
32
|
"@opentelemetry/api-logs": "^0.203.0",
|
|
33
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
33
|
+
"@opentelemetry/auto-instrumentations-node": "^0.62.1",
|
|
34
34
|
"@opentelemetry/core": "^2.0.1",
|
|
35
|
-
"@opentelemetry/exporter-logs-otlp-grpc": "^0.
|
|
36
|
-
"@opentelemetry/exporter-logs-otlp-http": "^0.
|
|
37
|
-
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.
|
|
38
|
-
"@opentelemetry/exporter-metrics-otlp-http": "^0.
|
|
39
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0.
|
|
40
|
-
"@opentelemetry/exporter-trace-otlp-http": "^0.
|
|
41
|
-
"@opentelemetry/instrumentation": "^0.
|
|
42
|
-
"@opentelemetry/otlp-exporter-base": "^0.
|
|
35
|
+
"@opentelemetry/exporter-logs-otlp-grpc": "^0.203.0",
|
|
36
|
+
"@opentelemetry/exporter-logs-otlp-http": "^0.203.0",
|
|
37
|
+
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.203.0",
|
|
38
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.203.0",
|
|
39
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.203.0",
|
|
40
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.203.0",
|
|
41
|
+
"@opentelemetry/instrumentation": "^0.203.0",
|
|
42
|
+
"@opentelemetry/otlp-exporter-base": "^0.203.0",
|
|
43
43
|
"@opentelemetry/resources": "^2.0.1",
|
|
44
|
-
"@opentelemetry/sdk-logs": "^0.
|
|
44
|
+
"@opentelemetry/sdk-logs": "^0.203.0",
|
|
45
45
|
"@opentelemetry/sdk-metrics": "^2.0.1",
|
|
46
|
-
"@opentelemetry/sdk-node": "^0.
|
|
46
|
+
"@opentelemetry/sdk-node": "^0.203.0",
|
|
47
47
|
"@opentelemetry/sdk-trace-base": "^2.0.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@types/node": "^24.0
|
|
50
|
+
"@types/node": "^24.3.0",
|
|
51
51
|
"@vitest/coverage-v8": "^3.2.4",
|
|
52
|
-
"tsx": "^4.20.
|
|
52
|
+
"tsx": "^4.20.5",
|
|
53
53
|
"typescript": "^5.8.3",
|
|
54
54
|
"vitest": "^3.2.4"
|
|
55
55
|
},
|
package/dist/vitest.config.js
CHANGED
|
@@ -26,10 +26,10 @@ export default defineConfig({
|
|
|
26
26
|
test: {
|
|
27
27
|
include: [
|
|
28
28
|
"**/test/*.test.ts",
|
|
29
|
-
"**/test/processor
|
|
30
|
-
"**/test/traces
|
|
31
|
-
"**/test/internals
|
|
32
|
-
"**/test/exporter
|
|
29
|
+
"**/test/processor/**/*.test.ts",
|
|
30
|
+
"**/test/traces/**/*.test.ts",
|
|
31
|
+
"**/test/internals/**/*.test.ts",
|
|
32
|
+
"**/test/exporter/**/*.test.ts",
|
|
33
33
|
],
|
|
34
34
|
name: "unit",
|
|
35
35
|
},
|