UNPKG

@ogcio/o11y-sdk-node

Version:

Opentelemetry standard instrumentation SDK for NodeJS based project

153 lines (138 loc) 4.12 kB
import { ExportResult } from "@opentelemetry/core"; import { OTLPExporterBase } from "@opentelemetry/otlp-exporter-base"; import { ReadableLogRecord } from "@opentelemetry/sdk-logs"; import { PushMetricExporter, ResourceMetrics, } from "@opentelemetry/sdk-metrics"; import { ReadableSpan, SpanExporter } from "@opentelemetry/sdk-trace-base"; import { NodeSDKConfig } from "../index.js"; import { _cleanLogBodyPII, _cleanObjectPII, _cleanStringPII, } from "../internals/pii-detection.js"; export class PIIExporterDecorator extends OTLPExporterBase< (ReadableSpan | ReadableLogRecord)[] | ResourceMetrics > implements SpanExporter, PushMetricExporter { private readonly _exporter; private readonly _config; constructor( exporter: OTLPExporterBase< (ReadableSpan | ReadableLogRecord)[] | ResourceMetrics >, config: NodeSDKConfig, ) { super(exporter["_delegate"]); this._exporter = exporter; this._config = config; } forceFlush(): Promise<void> { return this._exporter.forceFlush(); } shutdown(): Promise<void> { return this._exporter.shutdown(); } export( items: (ReadableSpan | ReadableLogRecord)[] | ResourceMetrics, resultCallback: (result: ExportResult) => void, ): void { if (!this._config.detection?.email) { this._exporter.export(items, resultCallback); return; } if (Array.isArray(items)) { const redactedItem = items.map((item) => { if (this._isReadableSpan(item)) { this._redactSpan(item); } else if (this._isReadableLogRecord(item)) { item = this._redactLogRecord(item) as ReadableLogRecord; } return item; }); this._exporter.export(redactedItem, resultCallback); return; } if (this._isResourceMetrics(items)) { this._redactResourceMetrics(items); this._exporter.export(items, resultCallback); } } private _isReadableSpan(span: unknown): span is ReadableSpan { return ( typeof span === "object" && span !== null && "name" in span && "kind" in span && "spanContext" in span && "attributes" in span ); } private _isReadableLogRecord(span: unknown): span is ReadableLogRecord { return ( typeof span === "object" && span !== null && "body" in span && "attributes" in span && "severityText" in span && "severityNumber" in span ); } private _isResourceMetrics(obj: unknown): obj is ResourceMetrics { return ( typeof obj === "object" && obj !== null && !Array.isArray(obj) && "resource" in obj && "scopeMetrics" in obj ); } private _redactSpan(span: ReadableSpan) { Object.assign(span, { name: _cleanStringPII(span.name, "trace"), attributes: span.attributes && _cleanObjectPII(span.attributes, "trace"), resource: { attributes: span?.resource?.attributes && _cleanObjectPII(span.resource.attributes, "trace"), }, links: span?.links?.map((link) => { Object.assign(link, { attributes: link?.attributes && _cleanObjectPII(link.attributes, "trace"), }); }), events: span?.events?.map((event) => { Object.assign(event, { name: _cleanStringPII(event.name, "trace"), attributes: event?.attributes && _cleanObjectPII(event.attributes, "trace"), }); return event; }), }); } private _redactLogRecord(log: ReadableLogRecord) { return { ...log, body: _cleanLogBodyPII(log.body), attributes: log.attributes && _cleanObjectPII(log.attributes, "log"), resource: log.resource && { ...log.resource, attributes: _cleanObjectPII(log.resource.attributes, "log"), }, }; } private _redactResourceMetrics(metric: ResourceMetrics) { Object.assign(metric, { resource: { attributes: metric?.resource?.attributes && _cleanObjectPII(metric.resource.attributes, "metric"), }, }); } }