@ogcio/o11y-sdk-node 0.2.0 → 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.
Files changed (52) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +158 -13
  3. package/dist/lib/config-manager.d.ts +3 -0
  4. package/dist/lib/config-manager.js +11 -0
  5. package/dist/lib/exporter/console.js +3 -4
  6. package/dist/lib/exporter/grpc.js +14 -13
  7. package/dist/lib/exporter/http.d.ts +1 -1
  8. package/dist/lib/exporter/http.js +14 -13
  9. package/dist/lib/exporter/pii-exporter-decorator.d.ts +20 -0
  10. package/dist/lib/exporter/pii-exporter-decorator.js +103 -0
  11. package/dist/lib/exporter/processor-config.d.ts +5 -0
  12. package/dist/lib/exporter/processor-config.js +16 -0
  13. package/dist/lib/index.d.ts +18 -4
  14. package/dist/lib/instrumentation.node.js +13 -11
  15. package/dist/lib/internals/hooks.d.ts +3 -0
  16. package/dist/lib/internals/hooks.js +12 -0
  17. package/dist/lib/internals/pii-detection.d.ts +17 -0
  18. package/dist/lib/internals/pii-detection.js +116 -0
  19. package/dist/lib/internals/shared-metrics.d.ts +7 -0
  20. package/dist/lib/internals/shared-metrics.js +18 -0
  21. package/dist/lib/traces.d.ts +20 -1
  22. package/dist/lib/traces.js +47 -1
  23. package/dist/package.json +3 -2
  24. package/dist/vitest.config.js +7 -1
  25. package/lib/config-manager.ts +16 -0
  26. package/lib/exporter/console.ts +6 -4
  27. package/lib/exporter/grpc.ts +34 -21
  28. package/lib/exporter/http.ts +33 -20
  29. package/lib/exporter/pii-exporter-decorator.ts +152 -0
  30. package/lib/exporter/processor-config.ts +23 -0
  31. package/lib/index.ts +19 -4
  32. package/lib/instrumentation.node.ts +16 -16
  33. package/lib/internals/hooks.ts +14 -0
  34. package/lib/internals/pii-detection.ts +145 -0
  35. package/lib/internals/shared-metrics.ts +34 -0
  36. package/lib/traces.ts +74 -1
  37. package/package.json +3 -2
  38. package/test/config-manager.test.ts +34 -0
  39. package/test/exporter/pii-exporter-decorator.test.ts +139 -0
  40. package/test/integration/{integration.test.ts → http-tracing.integration.test.ts} +0 -2
  41. package/test/integration/pii.integration.test.ts +68 -0
  42. package/test/integration/run.sh +2 -2
  43. package/test/internals/hooks.test.ts +45 -0
  44. package/test/internals/pii-detection.test.ts +141 -0
  45. package/test/internals/shared-metrics.test.ts +34 -0
  46. package/test/node-config.test.ts +59 -14
  47. package/test/processor/enrich-span-processor.test.ts +2 -54
  48. package/test/traces/active-span.test.ts +28 -0
  49. package/test/traces/with-span.test.ts +340 -0
  50. package/test/utils/alloy-log-parser.ts +7 -0
  51. package/test/utils/mock-signals.ts +144 -0
  52. package/vitest.config.ts +7 -1
@@ -1,12 +1,13 @@
1
- import process from "process";
2
1
  import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
3
2
  import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
4
3
  import { W3CTraceContextPropagator } from "@opentelemetry/core";
5
4
  import { NodeSDK } from "@opentelemetry/sdk-node";
6
5
  import { AlwaysOffSampler, ParentBasedSampler, TraceIdRatioBasedSampler, } from "@opentelemetry/sdk-trace-base";
6
+ import { setNodeSdkConfig } from "./config-manager.js";
7
7
  import buildConsoleExporters from "./exporter/console.js";
8
8
  import buildGrpcExporters from "./exporter/grpc.js";
9
9
  import buildHttpExporters from "./exporter/http.js";
10
+ import { _shutdownHook } from "./internals/hooks.js";
10
11
  import { ObservabilityResourceDetector } from "./resource.js";
11
12
  import { UrlSampler } from "./url-sampler.js";
12
13
  export default async function buildNodeInstrumentation(config) {
@@ -22,6 +23,16 @@ export default async function buildNodeInstrumentation(config) {
22
23
  console.error("collectorUrl does not use a valid format. Skipping NodeJS OpenTelemetry instrumentation.");
23
24
  return;
24
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
+ // Init configManager to make it available to all o11y utils.
35
+ setNodeSdkConfig(config);
25
36
  const urlSampler = new UrlSampler(config.ignoreUrls, new TraceIdRatioBasedSampler(config.traceRatio ?? 1));
26
37
  const mainSampler = new ParentBasedSampler({
27
38
  root: urlSampler,
@@ -61,16 +72,7 @@ export default async function buildNodeInstrumentation(config) {
61
72
  });
62
73
  sdk.start();
63
74
  console.log("NodeJS OpenTelemetry instrumentation started successfully.");
64
- process.on("SIGTERM", async () => {
65
- try {
66
- // Flushing before shutdown is implemented on a per-exporter basis.
67
- await sdk.shutdown();
68
- console.log("NodeJS OpenTelemetry instrumentation shutdown successfully");
69
- }
70
- catch (error) {
71
- console.error("Error shutting down NodeJS OpenTelemetry instrumentation:", error);
72
- }
73
- });
75
+ _shutdownHook(sdk);
74
76
  return sdk;
75
77
  }
76
78
  catch (error) {
@@ -0,0 +1,3 @@
1
+ export declare function _shutdownHook(sdk: {
2
+ shutdown: () => Promise<void>;
3
+ }): void;
@@ -0,0 +1,12 @@
1
+ export function _shutdownHook(sdk) {
2
+ process.on("SIGTERM", async () => {
3
+ try {
4
+ // Flushing before shutdown is implemented on a per-exporter basis.
5
+ await sdk.shutdown();
6
+ console.log("NodeJS OpenTelemetry instrumentation shutdown successfully");
7
+ }
8
+ catch (error) {
9
+ console.error("Error shutting down NodeJS OpenTelemetry instrumentation:", error);
10
+ }
11
+ });
12
+ }
@@ -0,0 +1,17 @@
1
+ import type { AnyValue } from "@opentelemetry/api-logs";
2
+ export type PIISource = "trace" | "log" | "metric";
3
+ /**
4
+ * Cleans a string by redacting email addresses and emitting metrics for PII.
5
+ *
6
+ * If the string is URL-encoded, it will be decoded before redaction.
7
+ * Metrics are emitted for each domain found in redacted email addresses.
8
+ *
9
+ * @param {string} value - The input string to sanitize.
10
+ * @param {"trace" | "log"} source - The source context of the input, used in metrics.
11
+ * @returns {string} The cleaned string with any email addresses replaced by `[REDACTED EMAIL]`.
12
+ */
13
+ export declare function _cleanStringPII(value: AnyValue, source: PIISource): AnyValue;
14
+ export declare function _cleanObjectPII(entry: object, source: PIISource): {
15
+ [k: string]: AnyValue;
16
+ };
17
+ export declare function _cleanLogBodyPII(value: AnyValue): AnyValue;
@@ -0,0 +1,116 @@
1
+ import { _getPIICounterRedactionMetric } from "./shared-metrics.js";
2
+ const EMAIL_REGEX = /[a-zA-Z0-9._%+-]+@([a-zA-Z0-9.-]+\.[a-z]{2,})/gi;
3
+ const decoder = new TextDecoder();
4
+ const encoder = new TextEncoder();
5
+ /**
6
+ * Redacts all email addresses in the input string and collects metadata.
7
+ *
8
+ * @param {string} value The input string potentially containing email 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 email addresses replaced by `[REDACTED EMAIL]`
17
+ * - `count`: total number of email addresses redacted
18
+ * - `domains`: a map of domain names to the number of times they were redacted
19
+ */
20
+ function _redactEmails(value) {
21
+ let count = 0;
22
+ const domains = {};
23
+ const redacted = value.replace(EMAIL_REGEX, (_, domain) => {
24
+ count++;
25
+ domains[domain] = (domains[domain] || 0) + 1;
26
+ return "[REDACTED EMAIL]";
27
+ });
28
+ return { redacted, count, domains };
29
+ }
30
+ /**
31
+ * Checks whether a string contains URI-encoded components.
32
+ *
33
+ * @param {string} value - The string to inspect.
34
+ * @returns {boolean} `true` if the string is encoded, `false` otherwise.
35
+ */
36
+ function _containsEncodedComponents(value) {
37
+ try {
38
+ return decodeURI(value) !== decodeURIComponent(value);
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ }
44
+ /**
45
+ * Cleans a string by redacting email addresses and emitting metrics for PII.
46
+ *
47
+ * If the string is URL-encoded, it will be decoded before redaction.
48
+ * Metrics are emitted for each domain found in redacted email addresses.
49
+ *
50
+ * @param {string} value - The input string to sanitize.
51
+ * @param {"trace" | "log"} source - The source context of the input, used in metrics.
52
+ * @returns {string} The cleaned string with any email addresses replaced by `[REDACTED EMAIL]`.
53
+ */
54
+ export function _cleanStringPII(value, source) {
55
+ if (Array.isArray(value)) {
56
+ return value.map((v) => _cleanStringPII(v, source));
57
+ }
58
+ if (typeof value !== "string") {
59
+ return value;
60
+ }
61
+ let kind = "string";
62
+ let decodedValue = value;
63
+ if (_containsEncodedComponents(value)) {
64
+ decodedValue = decodeURIComponent(value);
65
+ kind = "url";
66
+ }
67
+ const { redacted, count, domains } = _redactEmails(decodedValue);
68
+ if (count > 0) {
69
+ for (const [domain, domainCount] of Object.entries(domains)) {
70
+ _getPIICounterRedactionMetric().add(domainCount, {
71
+ pii_type: "email",
72
+ redaction_source: source,
73
+ pii_email_domain: domain,
74
+ pii_format: kind,
75
+ });
76
+ }
77
+ }
78
+ return redacted;
79
+ }
80
+ export function _cleanObjectPII(entry, source) {
81
+ if (!entry) {
82
+ return entry;
83
+ }
84
+ return Object.fromEntries(Object.entries(entry).map(([k, v]) => [k, _cleanStringPII(v, source)]));
85
+ }
86
+ export function _cleanLogBodyPII(value) {
87
+ if (typeof value === "string") {
88
+ return _cleanStringPII(value, "log");
89
+ }
90
+ if (typeof value === "number" ||
91
+ typeof value === "boolean" ||
92
+ value == null) {
93
+ return value;
94
+ }
95
+ if (value instanceof Uint8Array) {
96
+ try {
97
+ const decoded = decoder.decode(value);
98
+ const sanitized = _cleanStringPII(decoded, "log");
99
+ return encoder.encode(sanitized);
100
+ }
101
+ catch {
102
+ return value;
103
+ }
104
+ }
105
+ if (Array.isArray(value)) {
106
+ return value.map(_cleanLogBodyPII);
107
+ }
108
+ if (typeof value === "object") {
109
+ const sanitized = {};
110
+ for (const [key, val] of Object.entries(value)) {
111
+ sanitized[key] = _cleanLogBodyPII(val);
112
+ }
113
+ return sanitized;
114
+ }
115
+ return value;
116
+ }
@@ -0,0 +1,7 @@
1
+ import { Attributes, Counter } from "@opentelemetry/api";
2
+ /**
3
+ * Returns a singleton OpenTelemetry counter metric used to record occurrences of PII redactions.
4
+ *
5
+ * @returns {Counter} The singleton OpenTelemetry counter metric for PII redactions.
6
+ */
7
+ export declare function _getPIICounterRedactionMetric(): Counter<Attributes>;
@@ -0,0 +1,18 @@
1
+ import { getMetric } from "../metrics.js";
2
+ // Cached singleton instance of the redaction counter metric
3
+ let _redactedCounter;
4
+ /**
5
+ * Returns a singleton OpenTelemetry counter metric used to record occurrences of PII redactions.
6
+ *
7
+ * @returns {Counter} The singleton OpenTelemetry counter metric for PII redactions.
8
+ */
9
+ export function _getPIICounterRedactionMetric() {
10
+ if (_redactedCounter) {
11
+ return _redactedCounter;
12
+ }
13
+ _redactedCounter = getMetric("counter", {
14
+ meterName: "o11y",
15
+ metricName: "o11y_pii_redaction",
16
+ });
17
+ return _redactedCounter;
18
+ }
@@ -1 +1,20 @@
1
- export declare function getActiveSpan(): import("@opentelemetry/api").Span | undefined;
1
+ import { Span, SpanOptions } from "@opentelemetry/api";
2
+ export type WithSpanParams<T> = {
3
+ /**
4
+ * The name of the trace the span should belong to.
5
+ * NOTE: If you want the new span to belong to an already existing trace, you should provide the same tracer name
6
+ */
7
+ traceName?: string;
8
+ spanName: string;
9
+ spanOptions?: SpanOptions;
10
+ /** A function defining the task you want to be wrapped by this span */
11
+ fn: (span: Span) => T | Promise<T>;
12
+ };
13
+ /**
14
+ * Gets the currently active OpenTelemetry span.
15
+ *
16
+ * @returns {Span | undefined} The active span with redaction logic applied,
17
+ * or `undefined` if there is no active span in context.
18
+ */
19
+ export declare function getActiveSpan(): Span | undefined;
20
+ export declare function withSpan<T>({ traceName, spanName, spanOptions, fn, }: WithSpanParams<T>): Promise<T>;
@@ -1,4 +1,50 @@
1
- import { trace } from "@opentelemetry/api";
1
+ import { SpanStatusCode, trace } from "@opentelemetry/api";
2
+ import { getNodeSdkConfig } from "./config-manager.js";
3
+ /**
4
+ * Generates a function wrapping a given Callable `fn` into an error handling block.
5
+ * Setting Span status and recording any caught exception before bubbling it up.
6
+ *
7
+ * Marks the span as ended once the provided callable has ended or an error has been caught.
8
+ *
9
+ * @returns {Promise<T>} where T is the type returned by the Callable.
10
+ * @throws any error thrown by the original Callable `fn` provided.
11
+ */
12
+ function selfContainedSpanHandlerGenerator(fn) {
13
+ return async (span) => {
14
+ try {
15
+ const fnResult = await fn(span);
16
+ span.setStatus({ code: SpanStatusCode.OK });
17
+ return fnResult;
18
+ }
19
+ catch (err) {
20
+ if (err instanceof Error) {
21
+ span.recordException(err);
22
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
23
+ throw err;
24
+ }
25
+ span.recordException({ message: JSON.stringify(err) });
26
+ span.setStatus({
27
+ code: SpanStatusCode.ERROR,
28
+ message: JSON.stringify(err),
29
+ });
30
+ throw err;
31
+ }
32
+ finally {
33
+ span.end();
34
+ }
35
+ };
36
+ }
37
+ /**
38
+ * Gets the currently active OpenTelemetry span.
39
+ *
40
+ * @returns {Span | undefined} The active span with redaction logic applied,
41
+ * or `undefined` if there is no active span in context.
42
+ */
2
43
  export function getActiveSpan() {
3
44
  return trace.getActiveSpan();
4
45
  }
46
+ export function withSpan({ traceName, spanName, spanOptions = {}, fn, }) {
47
+ const sdkConfig = getNodeSdkConfig();
48
+ const tracer = trace.getTracer(traceName ?? sdkConfig.serviceName ?? "o11y-sdk", sdkConfig.serviceVersion);
49
+ return tracer.startActiveSpan(spanName, spanOptions, selfContainedSpanHandlerGenerator(fn));
50
+ }
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ogcio/o11y-sdk-node",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Opentelemetry standard instrumentation SDK for NodeJS based project",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -29,6 +29,7 @@
29
29
  "dependencies": {
30
30
  "@grpc/grpc-js": "^1.13.4",
31
31
  "@opentelemetry/api": "^1.9.0",
32
+ "@opentelemetry/api-logs": "^0.203.0",
32
33
  "@opentelemetry/auto-instrumentations-node": "^0.60.1",
33
34
  "@opentelemetry/core": "^2.0.1",
34
35
  "@opentelemetry/exporter-logs-otlp-grpc": "^0.202.0",
@@ -46,7 +47,7 @@
46
47
  "@opentelemetry/sdk-trace-base": "^2.0.1"
47
48
  },
48
49
  "devDependencies": {
49
- "@types/node": "^24.0.3",
50
+ "@types/node": "^24.0.10",
50
51
  "@vitest/coverage-v8": "^3.2.4",
51
52
  "tsx": "^4.20.3",
52
53
  "typescript": "^5.8.3",
@@ -24,7 +24,13 @@ export default defineConfig({
24
24
  projects: [
25
25
  {
26
26
  test: {
27
- include: ["**/test/*.test.ts", "**/test/processor/*.test.ts"],
27
+ include: [
28
+ "**/test/*.test.ts",
29
+ "**/test/processor/*.test.ts",
30
+ "**/test/traces/*.test.ts",
31
+ "**/test/internals/*.test.ts",
32
+ "**/test/exporter/*.test.ts",
33
+ ],
28
34
  name: "unit",
29
35
  },
30
36
  },
@@ -0,0 +1,16 @@
1
+ import { NodeSDKConfig } from "./index.js";
2
+
3
+ let nodeSDKConfig: NodeSDKConfig;
4
+
5
+ export const setNodeSdkConfig = (config: NodeSDKConfig) => {
6
+ nodeSDKConfig = config;
7
+ };
8
+
9
+ export const getNodeSdkConfig = (): NodeSDKConfig => {
10
+ if (!nodeSDKConfig) {
11
+ throw new Error("Node SDK Config was not initialized.");
12
+ }
13
+
14
+ // Ensure getters do not edit config.
15
+ return JSON.parse(JSON.stringify(nodeSDKConfig));
16
+ };
@@ -8,9 +8,11 @@ import {
8
8
  SimpleSpanProcessor,
9
9
  } from "@opentelemetry/sdk-trace-base";
10
10
  import { NodeSDKConfig } from "../index.js";
11
+ import {
12
+ _logsProcessorConfig,
13
+ _spansProcessorConfig,
14
+ } from "./processor-config.js";
11
15
  import { Exporters } from "./index.js";
12
- import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
13
- import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
14
16
 
15
17
  export default function buildConsoleExporters(
16
18
  config: NodeSDKConfig,
@@ -18,13 +20,13 @@ export default function buildConsoleExporters(
18
20
  return {
19
21
  spans: [
20
22
  new SimpleSpanProcessor(new ConsoleSpanExporter()),
21
- new EnrichSpanProcessor(config.spanAttributes),
23
+ ..._spansProcessorConfig(config),
22
24
  ],
23
25
  metrics: new metrics.PeriodicExportingMetricReader({
24
26
  exporter: new metrics.ConsoleMetricExporter(),
25
27
  }),
26
28
  logs: [
27
- new EnrichLogProcessor(config.spanAttributes),
29
+ ..._logsProcessorConfig(config),
28
30
  new SimpleLogRecordProcessor(new ConsoleLogRecordExporter()),
29
31
  ],
30
32
  };
@@ -1,13 +1,17 @@
1
- import { metrics } from "@opentelemetry/sdk-node";
2
- import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
3
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
4
1
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-grpc";
5
2
  import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-grpc";
3
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-grpc";
4
+ import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
5
+ import { metrics } from "@opentelemetry/sdk-node";
6
6
  import { NodeSDKConfig } from "../index.js";
7
- import { Exporters } from "./index.js";
8
7
  import { LogRecordProcessorMap, SpanProcessorMap } from "../utils.js";
9
- import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
10
- import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
8
+ import {
9
+ _logsProcessorConfig,
10
+ _spansProcessorConfig,
11
+ } from "./processor-config.js";
12
+ import { Exporters } from "./index.js";
13
+ import { getNodeSdkConfig } from "../config-manager.js";
14
+ import { PIIExporterDecorator } from "./pii-exporter-decorator.js";
11
15
 
12
16
  async function defaultMetadata() {
13
17
  const { Metadata } = await import("@grpc/grpc-js");
@@ -23,29 +27,38 @@ export default async function buildGrpcExporters(
23
27
  return {
24
28
  spans: [
25
29
  new SpanProcessorMap[config.collectorMode ?? "batch"](
26
- new OTLPTraceExporter({
30
+ new PIIExporterDecorator(
31
+ new OTLPTraceExporter({
32
+ url: `${config.collectorUrl}`,
33
+ compression: CompressionAlgorithm.GZIP,
34
+ metadata: config.grpcMetadata ?? (await defaultMetadata()),
35
+ }),
36
+ getNodeSdkConfig(),
37
+ ),
38
+ ),
39
+ ..._spansProcessorConfig(config),
40
+ ],
41
+ metrics: new metrics.PeriodicExportingMetricReader({
42
+ exporter: new PIIExporterDecorator(
43
+ new OTLPMetricExporter({
27
44
  url: `${config.collectorUrl}`,
28
45
  compression: CompressionAlgorithm.GZIP,
29
46
  metadata: config.grpcMetadata ?? (await defaultMetadata()),
30
47
  }),
48
+ getNodeSdkConfig(),
31
49
  ),
32
- new EnrichSpanProcessor(config.spanAttributes),
33
- ],
34
- metrics: new metrics.PeriodicExportingMetricReader({
35
- exporter: new OTLPMetricExporter({
36
- url: `${config.collectorUrl}`,
37
- compression: CompressionAlgorithm.GZIP,
38
- metadata: config.grpcMetadata ?? (await defaultMetadata()),
39
- }),
40
50
  }),
41
51
  logs: [
42
- new EnrichLogProcessor(config.spanAttributes),
52
+ ..._logsProcessorConfig(config),
43
53
  new LogRecordProcessorMap[config.collectorMode ?? "batch"](
44
- new OTLPLogExporter({
45
- url: `${config.collectorUrl}`,
46
- compression: CompressionAlgorithm.GZIP,
47
- metadata: config.grpcMetadata ?? (await defaultMetadata()),
48
- }),
54
+ new PIIExporterDecorator(
55
+ new OTLPLogExporter({
56
+ url: `${config.collectorUrl}`,
57
+ compression: CompressionAlgorithm.GZIP,
58
+ metadata: config.grpcMetadata ?? (await defaultMetadata()),
59
+ }),
60
+ getNodeSdkConfig(),
61
+ ),
49
62
  ),
50
63
  ],
51
64
  };
@@ -1,13 +1,17 @@
1
- import { metrics } from "@opentelemetry/sdk-node";
2
- import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
3
- import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
4
1
  import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
5
2
  import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
3
+ import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
4
+ import { CompressionAlgorithm } from "@opentelemetry/otlp-exporter-base";
5
+ import { metrics } from "@opentelemetry/sdk-node";
6
+ import { NodeSDKConfig } from "../index.js";
6
7
  import { LogRecordProcessorMap, SpanProcessorMap } from "../utils.js";
7
- import { EnrichSpanProcessor } from "../processor/enrich-span-processor.js";
8
+ import {
9
+ _logsProcessorConfig,
10
+ _spansProcessorConfig,
11
+ } from "./processor-config.js";
8
12
  import { Exporters } from "./index.js";
9
- import { NodeSDKConfig } from "../index.js";
10
- import { EnrichLogProcessor } from "../processor/enrich-logger-processor.js";
13
+ import { getNodeSdkConfig } from "../config-manager.js";
14
+ import { PIIExporterDecorator } from "./pii-exporter-decorator.js";
11
15
 
12
16
  export default function buildHttpExporters(config: NodeSDKConfig): Exporters {
13
17
  if (config.collectorUrl.endsWith("/")) {
@@ -17,26 +21,35 @@ export default function buildHttpExporters(config: NodeSDKConfig): Exporters {
17
21
  return {
18
22
  spans: [
19
23
  new SpanProcessorMap[config.collectorMode ?? "batch"](
20
- new OTLPTraceExporter({
21
- url: `${config.collectorUrl}/v1/traces`,
22
- compression: CompressionAlgorithm.GZIP,
23
- }),
24
+ new PIIExporterDecorator(
25
+ new OTLPTraceExporter({
26
+ url: `${config.collectorUrl}/v1/traces`,
27
+ compression: CompressionAlgorithm.GZIP,
28
+ }),
29
+ getNodeSdkConfig(),
30
+ ),
24
31
  ),
25
- new EnrichSpanProcessor(config.spanAttributes),
32
+ ..._spansProcessorConfig(config),
26
33
  ],
27
34
  metrics: new metrics.PeriodicExportingMetricReader({
28
- exporter: new OTLPMetricExporter({
29
- url: `${config.collectorUrl}/v1/metrics`,
30
- compression: CompressionAlgorithm.GZIP,
31
- }),
35
+ exporter: new PIIExporterDecorator(
36
+ new OTLPMetricExporter({
37
+ url: `${config.collectorUrl}/v1/metrics`,
38
+ compression: CompressionAlgorithm.GZIP,
39
+ }),
40
+ getNodeSdkConfig(),
41
+ ),
32
42
  }),
33
43
  logs: [
34
- new EnrichLogProcessor(config.spanAttributes),
44
+ ..._logsProcessorConfig(config),
35
45
  new LogRecordProcessorMap[config.collectorMode ?? "batch"](
36
- new OTLPLogExporter({
37
- url: `${config.collectorUrl}/v1/logs`,
38
- compression: CompressionAlgorithm.GZIP,
39
- }),
46
+ new PIIExporterDecorator(
47
+ new OTLPLogExporter({
48
+ url: `${config.collectorUrl}/v1/logs`,
49
+ compression: CompressionAlgorithm.GZIP,
50
+ }),
51
+ getNodeSdkConfig(),
52
+ ),
40
53
  ),
41
54
  ],
42
55
  };