@open-mercato/telemetry 0.6.7-develop.6834.1.e76f4b8cbc
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/.turbo/turbo-build.log +2 -0
- package/AGENTS.md +71 -0
- package/README.md +164 -0
- package/build.mjs +10 -0
- package/dist/env.js +44 -0
- package/dist/env.js.map +7 -0
- package/dist/facade/context.js +14 -0
- package/dist/facade/context.js.map +7 -0
- package/dist/facade/http.js +18 -0
- package/dist/facade/http.js.map +7 -0
- package/dist/facade/logger-bridge.js +40 -0
- package/dist/facade/logger-bridge.js.map +7 -0
- package/dist/facade/meter.js +16 -0
- package/dist/facade/meter.js.map +7 -0
- package/dist/facade/propagation.js +20 -0
- package/dist/facade/propagation.js.map +7 -0
- package/dist/facade/redact.js +21 -0
- package/dist/facade/redact.js.map +7 -0
- package/dist/facade/report-error.js +26 -0
- package/dist/facade/report-error.js.map +7 -0
- package/dist/facade/serialize.js +35 -0
- package/dist/facade/serialize.js.map +7 -0
- package/dist/facade/tracer.js +21 -0
- package/dist/facade/tracer.js.map +7 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +7 -0
- package/dist/init.js +98 -0
- package/dist/init.js.map +7 -0
- package/dist/nextjs-config.js +21 -0
- package/dist/nextjs-config.js.map +7 -0
- package/dist/nextjs.js +30 -0
- package/dist/nextjs.js.map +7 -0
- package/dist/provider/console-provider.js +70 -0
- package/dist/provider/console-provider.js.map +7 -0
- package/dist/provider/noop-provider.js +45 -0
- package/dist/provider/noop-provider.js.map +7 -0
- package/dist/provider/otlp-provider.js +212 -0
- package/dist/provider/otlp-provider.js.map +7 -0
- package/dist/provider/registry.js +40 -0
- package/dist/provider/registry.js.map +7 -0
- package/dist/provider/run-span.js +34 -0
- package/dist/provider/run-span.js.map +7 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +7 -0
- package/jest.config.cjs +27 -0
- package/package.json +68 -0
- package/src/__tests__/default-unloaded.test.ts +58 -0
- package/src/__tests__/env-load-order.test.ts +80 -0
- package/src/__tests__/env.test.ts +72 -0
- package/src/__tests__/logger-level.test.ts +64 -0
- package/src/__tests__/nextjs-shutdown.test.ts +71 -0
- package/src/__tests__/nextjs.test.ts +122 -0
- package/src/__tests__/otlp-integration.test.ts +264 -0
- package/src/__tests__/pg-instrumentation.test.ts +88 -0
- package/src/__tests__/pg-pii-config.test.ts +14 -0
- package/src/__tests__/redact.test.ts +92 -0
- package/src/__tests__/registry.test.ts +77 -0
- package/src/__tests__/run-span.test.ts +56 -0
- package/src/__tests__/serialize.test.ts +47 -0
- package/src/__tests__/telemetry.test.ts +172 -0
- package/src/env.ts +71 -0
- package/src/facade/context.ts +17 -0
- package/src/facade/http.ts +25 -0
- package/src/facade/logger-bridge.ts +50 -0
- package/src/facade/meter.ts +20 -0
- package/src/facade/propagation.ts +31 -0
- package/src/facade/redact.ts +54 -0
- package/src/facade/report-error.ts +41 -0
- package/src/facade/serialize.ts +46 -0
- package/src/facade/tracer.ts +25 -0
- package/src/index.ts +30 -0
- package/src/init.ts +134 -0
- package/src/nextjs-config.ts +22 -0
- package/src/nextjs.ts +47 -0
- package/src/provider/console-provider.ts +87 -0
- package/src/provider/noop-provider.ts +53 -0
- package/src/provider/otlp-provider.ts +316 -0
- package/src/provider/registry.ts +60 -0
- package/src/provider/run-span.ts +45 -0
- package/src/types.ts +108 -0
- package/tsconfig.json +9 -0
- package/watch.mjs +6 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { withSpan, currentSpan, setAttributes } from "./facade/tracer.js";
|
|
2
|
+
import { counter, histogram, gauge } from "./facade/meter.js";
|
|
3
|
+
import { reportError } from "./facade/report-error.js";
|
|
4
|
+
import { captureTraceContext, continueTrace } from "./facade/propagation.js";
|
|
5
|
+
import { initTelemetry, shutdownTelemetry } from "./init.js";
|
|
6
|
+
import { registerProvider } from "./provider/registry.js";
|
|
7
|
+
export {
|
|
8
|
+
captureTraceContext,
|
|
9
|
+
continueTrace,
|
|
10
|
+
counter,
|
|
11
|
+
currentSpan,
|
|
12
|
+
gauge,
|
|
13
|
+
histogram,
|
|
14
|
+
initTelemetry,
|
|
15
|
+
registerProvider,
|
|
16
|
+
reportError,
|
|
17
|
+
setAttributes,
|
|
18
|
+
shutdownTelemetry,
|
|
19
|
+
withSpan
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Public facade for the telemetry package. Import from `@open-mercato/telemetry`.\n *\n * Vendor-neutral by construction \u2014 nothing here imports `@opentelemetry/*`;\n * only `provider/otlp-provider.ts` does, and it is loaded dynamically.\n */\nexport { withSpan, currentSpan, setAttributes } from './facade/tracer'\nexport { counter, histogram, gauge } from './facade/meter'\nexport { reportError } from './facade/report-error'\nexport type { ReportErrorContext } from './facade/report-error'\nexport { captureTraceContext, continueTrace } from './facade/propagation'\nexport { initTelemetry, shutdownTelemetry } from './init'\nexport { registerProvider } from './provider/registry'\n\nexport type {\n Span,\n SpanKind,\n SpanOptions,\n TelemetryProvider,\n TelemetrySignal,\n TelemetryBackendName,\n LogRecord,\n LogLevel,\n MetricKind,\n MetricPoint,\n Attributes,\n AttributeValue,\n TraceCarrier,\n TraceContext,\n} from './types'\n"],
|
|
5
|
+
"mappings": "AAMA,SAAS,UAAU,aAAa,qBAAqB;AACrD,SAAS,SAAS,WAAW,aAAa;AAC1C,SAAS,mBAAmB;AAE5B,SAAS,qBAAqB,qBAAqB;AACnD,SAAS,eAAe,yBAAyB;AACjD,SAAS,wBAAwB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { isOtlpBackend, readTelemetryEnv, resetTelemetryEnvCache } from "./env.js";
|
|
2
|
+
import { ConsoleProvider } from "./provider/console-provider.js";
|
|
3
|
+
import {
|
|
4
|
+
getRegisteredProvider,
|
|
5
|
+
clearActiveProvider,
|
|
6
|
+
setActiveProvider
|
|
7
|
+
} from "./provider/registry.js";
|
|
8
|
+
import {
|
|
9
|
+
registerTelemetryRuntime
|
|
10
|
+
} from "@open-mercato/shared/lib/telemetry/runtime";
|
|
11
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
12
|
+
import { registerTelemetryLogger } from "./facade/logger-bridge.js";
|
|
13
|
+
import { captureTraceContext, continueTrace } from "./facade/propagation.js";
|
|
14
|
+
import { recordHttpDuration } from "./facade/http.js";
|
|
15
|
+
import { reportError } from "./facade/report-error.js";
|
|
16
|
+
let initialized = false;
|
|
17
|
+
let activeProvider;
|
|
18
|
+
let disposeLoggerExtension;
|
|
19
|
+
let disposeRuntime;
|
|
20
|
+
const logger = createLogger("telemetry");
|
|
21
|
+
async function initTelemetry() {
|
|
22
|
+
if (initialized) return;
|
|
23
|
+
resetTelemetryEnvCache();
|
|
24
|
+
const env = readTelemetryEnv();
|
|
25
|
+
const configuredBackend = process.env.TELEMETRY_BACKEND?.trim().toLowerCase() ?? "";
|
|
26
|
+
const registeredProvider = configuredBackend && configuredBackend !== "noop" ? getRegisteredProvider(configuredBackend) : void 0;
|
|
27
|
+
if (!env.enabled && !registeredProvider) return;
|
|
28
|
+
const provider = registeredProvider ?? await resolveProvider(env.backend);
|
|
29
|
+
if (!provider) {
|
|
30
|
+
logger.warn("Telemetry backend is unsupported; telemetry remains disabled", {
|
|
31
|
+
backend: configuredBackend || env.backend
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
await provider.start();
|
|
36
|
+
setActiveProvider(provider);
|
|
37
|
+
activeProvider = provider;
|
|
38
|
+
disposeLoggerExtension = registerTelemetryLogger(provider);
|
|
39
|
+
disposeRuntime = registerTelemetryRuntime(createRuntime(provider));
|
|
40
|
+
initialized = true;
|
|
41
|
+
logger.info("Telemetry initialized", {
|
|
42
|
+
backend: provider.name,
|
|
43
|
+
samplingRatio: env.samplingRatio
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async function resolveProvider(backend) {
|
|
47
|
+
const registered = getRegisteredProvider(backend);
|
|
48
|
+
if (registered) return registered;
|
|
49
|
+
if (backend === "console") return new ConsoleProvider();
|
|
50
|
+
if (isOtlpBackend(backend)) return await loadOtlpProvider(backend);
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
async function loadOtlpProvider(backend) {
|
|
54
|
+
try {
|
|
55
|
+
const mod = await import("./provider/otlp-provider.js");
|
|
56
|
+
return new mod.OtlpProvider({}, backend);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
logger.warn("OTLP provider unavailable; falling back to console", {
|
|
59
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
60
|
+
});
|
|
61
|
+
return new ConsoleProvider();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function shutdownTelemetry() {
|
|
65
|
+
const provider = activeProvider;
|
|
66
|
+
activeProvider = void 0;
|
|
67
|
+
initialized = false;
|
|
68
|
+
disposeLoggerExtension?.();
|
|
69
|
+
disposeLoggerExtension = void 0;
|
|
70
|
+
disposeRuntime?.();
|
|
71
|
+
disposeRuntime = void 0;
|
|
72
|
+
clearActiveProvider();
|
|
73
|
+
if (provider) await provider.shutdown();
|
|
74
|
+
}
|
|
75
|
+
function createRuntime(provider) {
|
|
76
|
+
return {
|
|
77
|
+
canUseGlobalTracePropagation: () => isOtlpBackend(provider.name) && readTelemetryEnv().trustInboundTrace,
|
|
78
|
+
captureTraceContext,
|
|
79
|
+
continueTrace: (carrier, name, fn, options) => continueTrace(carrier, name, () => fn(), options),
|
|
80
|
+
recordHttpDuration,
|
|
81
|
+
reportError,
|
|
82
|
+
shutdown: shutdownTelemetry
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function resetTelemetryInit() {
|
|
86
|
+
initialized = false;
|
|
87
|
+
activeProvider = void 0;
|
|
88
|
+
disposeLoggerExtension?.();
|
|
89
|
+
disposeLoggerExtension = void 0;
|
|
90
|
+
disposeRuntime?.();
|
|
91
|
+
disposeRuntime = void 0;
|
|
92
|
+
}
|
|
93
|
+
export {
|
|
94
|
+
initTelemetry,
|
|
95
|
+
resetTelemetryInit,
|
|
96
|
+
shutdownTelemetry
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/init.ts"],
|
|
4
|
+
"sourcesContent": ["import type { TelemetryBackendName, TelemetryProvider } from './types'\nimport { isOtlpBackend, readTelemetryEnv, resetTelemetryEnvCache } from './env'\nimport { ConsoleProvider } from './provider/console-provider'\nimport {\n getRegisteredProvider,\n clearActiveProvider,\n setActiveProvider,\n} from './provider/registry'\nimport {\n registerTelemetryRuntime,\n type TelemetryRuntime,\n} from '@open-mercato/shared/lib/telemetry/runtime'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { registerTelemetryLogger } from './facade/logger-bridge'\nimport { captureTraceContext, continueTrace } from './facade/propagation'\nimport { recordHttpDuration } from './facade/http'\nimport { reportError } from './facade/report-error'\n\nlet initialized = false\nlet activeProvider: TelemetryProvider | undefined\nlet disposeLoggerExtension: (() => void) | undefined\nlet disposeRuntime: (() => void) | undefined\n\nconst logger = createLogger('telemetry')\n\n/**\n * One-shot bootstrap, invoked from `apps/mercato/instrumentation.ts` (web) and,\n * for cross-boundary propagation, from the queue/worker bootstrap. Resolves the\n * backend from `TELEMETRY_BACKEND`, starts it, and installs it as the active\n * provider. Idempotent and safe to call when telemetry is off (defaults to\n * no-op).\n */\nexport async function initTelemetry(): Promise<void> {\n if (initialized) return\n\n // Drop any env snapshot memoized BEFORE the host loaded its `.env` (the CLI\n // binary imports this package before dotenv runs) so init resolves the backend\n // from the actual, fully-loaded environment.\n resetTelemetryEnvCache()\n const env = readTelemetryEnv()\n const configuredBackend = process.env.TELEMETRY_BACKEND?.trim().toLowerCase() ?? ''\n const registeredProvider = configuredBackend && configuredBackend !== 'noop'\n ? getRegisteredProvider(configuredBackend)\n : undefined\n // Explicit off is absolute: do not resolve providers, register hooks, or\n // install process-wide bridges when the backend is unset/noop/unregistered.\n if (!env.enabled && !registeredProvider) return\n\n const provider = registeredProvider ?? await resolveProvider(env.backend)\n if (!provider) {\n logger.warn('Telemetry backend is unsupported; telemetry remains disabled', {\n backend: configuredBackend || env.backend,\n })\n return\n }\n\n // Only flag initialized AFTER start() succeeds \u2014 a throw here must leave\n // telemetry re-initializable, not stuck flagged-on with an unstarted provider.\n await provider.start()\n setActiveProvider(provider)\n activeProvider = provider\n disposeLoggerExtension = registerTelemetryLogger(provider)\n disposeRuntime = registerTelemetryRuntime(createRuntime(provider))\n initialized = true\n\n logger.info('Telemetry initialized', {\n backend: provider.name,\n samplingRatio: env.samplingRatio,\n })\n}\n\nasync function resolveProvider(backend: TelemetryBackendName): Promise<TelemetryProvider | undefined> {\n const registered = getRegisteredProvider(backend)\n if (registered) return registered\n\n if (backend === 'console') return new ConsoleProvider()\n // signoz | newrelic | otlp \u2014 same OTLP provider, vendor differs only by endpoint.\n if (isOtlpBackend(backend)) return await loadOtlpProvider(backend)\n return undefined\n}\n\n/**\n * Dynamically load the OTLP provider so `@opentelemetry/*` (optionalDependencies)\n * is imported only when an OTLP backend is selected. Falls back to console if\n * the OTEL packages are absent rather than crashing the app.\n */\nasync function loadOtlpProvider(backend: TelemetryBackendName): Promise<TelemetryProvider> {\n try {\n const mod = await import('./provider/otlp-provider')\n return new mod.OtlpProvider({}, backend)\n } catch (err) {\n logger.warn('OTLP provider unavailable; falling back to console', {\n reason: err instanceof Error ? err.message : String(err),\n })\n return new ConsoleProvider()\n }\n}\n\n/** Flush + tear down the active backend (shutdown hook / `after()`). */\nexport async function shutdownTelemetry(): Promise<void> {\n const provider = activeProvider\n activeProvider = undefined\n initialized = false\n disposeLoggerExtension?.()\n disposeLoggerExtension = undefined\n disposeRuntime?.()\n disposeRuntime = undefined\n clearActiveProvider()\n if (provider) await provider.shutdown()\n}\n\nfunction createRuntime(provider: TelemetryProvider): TelemetryRuntime {\n return {\n canUseGlobalTracePropagation: () =>\n isOtlpBackend(provider.name as TelemetryBackendName)\n && readTelemetryEnv().trustInboundTrace,\n captureTraceContext,\n continueTrace: (carrier, name, fn, options) =>\n continueTrace(carrier, name, () => fn(), options),\n recordHttpDuration,\n reportError,\n shutdown: shutdownTelemetry,\n }\n}\n\n/** Test-only: allow re-init in jest. */\nexport function resetTelemetryInit(): void {\n initialized = false\n activeProvider = undefined\n disposeLoggerExtension?.()\n disposeLoggerExtension = undefined\n disposeRuntime?.()\n disposeRuntime = undefined\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,eAAe,kBAAkB,8BAA8B;AACxE,SAAS,uBAAuB;AAChC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,OAEK;AACP,SAAS,oBAAoB;AAC7B,SAAS,+BAA+B;AACxC,SAAS,qBAAqB,qBAAqB;AACnD,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAE5B,IAAI,cAAc;AAClB,IAAI;AACJ,IAAI;AACJ,IAAI;AAEJ,MAAM,SAAS,aAAa,WAAW;AASvC,eAAsB,gBAA+B;AACnD,MAAI,YAAa;AAKjB,yBAAuB;AACvB,QAAM,MAAM,iBAAiB;AAC7B,QAAM,oBAAoB,QAAQ,IAAI,mBAAmB,KAAK,EAAE,YAAY,KAAK;AACjF,QAAM,qBAAqB,qBAAqB,sBAAsB,SAClE,sBAAsB,iBAAiB,IACvC;AAGJ,MAAI,CAAC,IAAI,WAAW,CAAC,mBAAoB;AAEzC,QAAM,WAAW,sBAAsB,MAAM,gBAAgB,IAAI,OAAO;AACxE,MAAI,CAAC,UAAU;AACb,WAAO,KAAK,gEAAgE;AAAA,MAC1E,SAAS,qBAAqB,IAAI;AAAA,IACpC,CAAC;AACD;AAAA,EACF;AAIA,QAAM,SAAS,MAAM;AACrB,oBAAkB,QAAQ;AAC1B,mBAAiB;AACjB,2BAAyB,wBAAwB,QAAQ;AACzD,mBAAiB,yBAAyB,cAAc,QAAQ,CAAC;AACjE,gBAAc;AAEd,SAAO,KAAK,yBAAyB;AAAA,IACnC,SAAS,SAAS;AAAA,IAClB,eAAe,IAAI;AAAA,EACrB,CAAC;AACH;AAEA,eAAe,gBAAgB,SAAuE;AACpG,QAAM,aAAa,sBAAsB,OAAO;AAChD,MAAI,WAAY,QAAO;AAEvB,MAAI,YAAY,UAAW,QAAO,IAAI,gBAAgB;AAEtD,MAAI,cAAc,OAAO,EAAG,QAAO,MAAM,iBAAiB,OAAO;AACjE,SAAO;AACT;AAOA,eAAe,iBAAiB,SAA2D;AACzF,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,0BAA0B;AACnD,WAAO,IAAI,IAAI,aAAa,CAAC,GAAG,OAAO;AAAA,EACzC,SAAS,KAAK;AACZ,WAAO,KAAK,sDAAsD;AAAA,MAChE,QAAQ,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACzD,CAAC;AACD,WAAO,IAAI,gBAAgB;AAAA,EAC7B;AACF;AAGA,eAAsB,oBAAmC;AACvD,QAAM,WAAW;AACjB,mBAAiB;AACjB,gBAAc;AACd,2BAAyB;AACzB,2BAAyB;AACzB,mBAAiB;AACjB,mBAAiB;AACjB,sBAAoB;AACpB,MAAI,SAAU,OAAM,SAAS,SAAS;AACxC;AAEA,SAAS,cAAc,UAA+C;AACpE,SAAO;AAAA,IACL,8BAA8B,MAC5B,cAAc,SAAS,IAA4B,KAChD,iBAAiB,EAAE;AAAA,IACxB;AAAA,IACA,eAAe,CAAC,SAAS,MAAM,IAAI,YACjC,cAAc,SAAS,MAAM,MAAM,GAAG,GAAG,OAAO;AAAA,IAClD;AAAA,IACA;AAAA,IACA,UAAU;AAAA,EACZ;AACF;AAGO,SAAS,qBAA2B;AACzC,gBAAc;AACd,mBAAiB;AACjB,2BAAyB;AACzB,2BAAyB;AACzB,mBAAiB;AACjB,mBAAiB;AACnB;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const telemetryServerExternalPackages = [
|
|
2
|
+
"@opentelemetry/api",
|
|
3
|
+
"@opentelemetry/api-logs",
|
|
4
|
+
"@opentelemetry/core",
|
|
5
|
+
"@opentelemetry/sdk-node",
|
|
6
|
+
"@opentelemetry/sdk-trace-node",
|
|
7
|
+
"@opentelemetry/sdk-logs",
|
|
8
|
+
"@opentelemetry/sdk-metrics",
|
|
9
|
+
"@opentelemetry/resources",
|
|
10
|
+
"@opentelemetry/semantic-conventions",
|
|
11
|
+
"@opentelemetry/instrumentation",
|
|
12
|
+
"@opentelemetry/instrumentation-pg",
|
|
13
|
+
"@opentelemetry/instrumentation-undici",
|
|
14
|
+
"@opentelemetry/exporter-trace-otlp-http",
|
|
15
|
+
"@opentelemetry/exporter-logs-otlp-http",
|
|
16
|
+
"@opentelemetry/exporter-metrics-otlp-http"
|
|
17
|
+
];
|
|
18
|
+
export {
|
|
19
|
+
telemetryServerExternalPackages
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=nextjs-config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/nextjs-config.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * OpenTelemetry packages that must remain real Node modules so runtime\n * instrumentations can patch their targets. This config-only entrypoint has no\n * telemetry runtime imports and is safe to evaluate from `next.config.ts`.\n */\nexport const telemetryServerExternalPackages = [\n '@opentelemetry/api',\n '@opentelemetry/api-logs',\n '@opentelemetry/core',\n '@opentelemetry/sdk-node',\n '@opentelemetry/sdk-trace-node',\n '@opentelemetry/sdk-logs',\n '@opentelemetry/sdk-metrics',\n '@opentelemetry/resources',\n '@opentelemetry/semantic-conventions',\n '@opentelemetry/instrumentation',\n '@opentelemetry/instrumentation-pg',\n '@opentelemetry/instrumentation-undici',\n '@opentelemetry/exporter-trace-otlp-http',\n '@opentelemetry/exporter-logs-otlp-http',\n '@opentelemetry/exporter-metrics-otlp-http',\n] as const\n"],
|
|
5
|
+
"mappings": "AAKO,MAAM,kCAAkC;AAAA,EAC7C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/nextjs.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isTelemetryBackendEnabled } from "@open-mercato/shared/lib/telemetry/runtime";
|
|
2
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
3
|
+
import { telemetryServerExternalPackages } from "./nextjs-config.js";
|
|
4
|
+
import { recordHttpDuration } from "./facade/http.js";
|
|
5
|
+
const logger = createLogger("telemetry");
|
|
6
|
+
async function registerTelemetryForNextjs() {
|
|
7
|
+
if (process.env.NEXT_RUNTIME && process.env.NEXT_RUNTIME !== "nodejs") return;
|
|
8
|
+
if (!isTelemetryBackendEnabled()) return;
|
|
9
|
+
const { initTelemetry, shutdownTelemetry } = await import("./init.js");
|
|
10
|
+
try {
|
|
11
|
+
await initTelemetry();
|
|
12
|
+
} catch (error) {
|
|
13
|
+
logger.warn("Init from Next.js instrumentation failed", { err: error });
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const flush = (signal) => {
|
|
17
|
+
void shutdownTelemetry().catch(() => {
|
|
18
|
+
}).finally(() => {
|
|
19
|
+
process.kill(process.pid, signal);
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
process.once("SIGTERM", flush);
|
|
23
|
+
process.once("SIGINT", flush);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
recordHttpDuration,
|
|
27
|
+
registerTelemetryForNextjs,
|
|
28
|
+
telemetryServerExternalPackages
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=nextjs.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/nextjs.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Next.js wiring helpers for `@open-mercato/telemetry`.\n *\n * Runtime helpers for an enabled Next.js telemetry integration. Build-time\n * config belongs in `@open-mercato/telemetry/nextjs-config`, which has no\n * runtime imports.\n */\nimport { isTelemetryBackendEnabled } from '@open-mercato/shared/lib/telemetry/runtime'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nexport { telemetryServerExternalPackages } from './nextjs-config'\nexport { recordHttpDuration } from './facade/http'\n\nconst logger = createLogger('telemetry')\n\n/**\n * One-line telemetry bootstrap for a Next.js `instrumentation.ts`. Initializes\n * the active backend (no-op unless `TELEMETRY_BACKEND` is set), degrades to no\n * telemetry on init failure (never bubbles a rejection out of Next's\n * `register()`), and registers a best-effort flush on `SIGTERM`/`SIGINT`. Skips\n * the edge runtime \u2014 the OTEL NodeSDK is Node-only \u2014 so callers may import it\n * unconditionally, though gating the dynamic import on\n * `NEXT_RUNTIME === 'nodejs'` also keeps the SDK off the edge bundle.\n */\nexport async function registerTelemetryForNextjs(): Promise<void> {\n if (process.env.NEXT_RUNTIME && process.env.NEXT_RUNTIME !== 'nodejs') return\n if (!isTelemetryBackendEnabled()) return\n const { initTelemetry, shutdownTelemetry } = await import('./init')\n try {\n await initTelemetry()\n } catch (error) {\n logger.warn('Init from Next.js instrumentation failed', { err: error })\n return\n }\n // A signal listener suppresses Node's default termination, so after the\n // best-effort flush the handler re-raises the signal. `once` has already\n // removed this listener by then, so the re-raise falls through to the default\n // terminate (or to another component's own handler, e.g. Next's).\n const flush = (signal: NodeJS.Signals) => {\n void shutdownTelemetry()\n .catch(() => {})\n .finally(() => {\n process.kill(process.pid, signal)\n })\n }\n process.once('SIGTERM', flush)\n process.once('SIGINT', flush)\n}\n"],
|
|
5
|
+
"mappings": "AAOA,SAAS,iCAAiC;AAC1C,SAAS,oBAAoB;AAC7B,SAAS,uCAAuC;AAChD,SAAS,0BAA0B;AAEnC,MAAM,SAAS,aAAa,WAAW;AAWvC,eAAsB,6BAA4C;AAChE,MAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,iBAAiB,SAAU;AACvE,MAAI,CAAC,0BAA0B,EAAG;AAClC,QAAM,EAAE,eAAe,kBAAkB,IAAI,MAAM,OAAO,QAAQ;AAClE,MAAI;AACF,UAAM,cAAc;AAAA,EACtB,SAAS,OAAO;AACd,WAAO,KAAK,4CAA4C,EAAE,KAAK,MAAM,CAAC;AACtE;AAAA,EACF;AAKA,QAAM,QAAQ,CAAC,WAA2B;AACxC,SAAK,kBAAkB,EACpB,MAAM,MAAM;AAAA,IAAC,CAAC,EACd,QAAQ,MAAM;AACb,cAAQ,KAAK,QAAQ,KAAK,MAAM;AAAA,IAClC,CAAC;AAAA,EACL;AACA,UAAQ,KAAK,WAAW,KAAK;AAC7B,UAAQ,KAAK,UAAU,KAAK;AAC9B;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
2
|
+
import { serializeError } from "../facade/serialize.js";
|
|
3
|
+
import { runSpan } from "./run-span.js";
|
|
4
|
+
const logger = createLogger("telemetry");
|
|
5
|
+
class ConsoleSpan {
|
|
6
|
+
constructor(name) {
|
|
7
|
+
this.name = name;
|
|
8
|
+
this.attributes = {};
|
|
9
|
+
this.status = "ok";
|
|
10
|
+
this.startedAt = Date.now();
|
|
11
|
+
}
|
|
12
|
+
setAttribute(key, value) {
|
|
13
|
+
this.attributes[key] = value;
|
|
14
|
+
}
|
|
15
|
+
setAttributes(attributes) {
|
|
16
|
+
Object.assign(this.attributes, attributes);
|
|
17
|
+
}
|
|
18
|
+
recordException(error) {
|
|
19
|
+
this.status = "error";
|
|
20
|
+
this.attributes.exception = serializeError(error).message;
|
|
21
|
+
}
|
|
22
|
+
setStatus(status) {
|
|
23
|
+
this.status = status;
|
|
24
|
+
}
|
|
25
|
+
end() {
|
|
26
|
+
logger[this.status === "error" ? "error" : "debug"](`Span ${this.name}`, {
|
|
27
|
+
span: this.name,
|
|
28
|
+
durationMs: Date.now() - this.startedAt,
|
|
29
|
+
status: this.status
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
class ConsoleProvider {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.name = "console";
|
|
36
|
+
this.supports = ["traces", "metrics"];
|
|
37
|
+
}
|
|
38
|
+
async start() {
|
|
39
|
+
}
|
|
40
|
+
async shutdown() {
|
|
41
|
+
}
|
|
42
|
+
runInSpan(name, _options, fn) {
|
|
43
|
+
return runSpan(new ConsoleSpan(name), fn);
|
|
44
|
+
}
|
|
45
|
+
activeSpan() {
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
activeTraceContext() {
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
inject(_carrier) {
|
|
52
|
+
}
|
|
53
|
+
runInRemoteSpan(_carrier, name, _options, fn) {
|
|
54
|
+
return runSpan(new ConsoleSpan(name), fn);
|
|
55
|
+
}
|
|
56
|
+
emitLog(_record) {
|
|
57
|
+
}
|
|
58
|
+
recordMetric(point) {
|
|
59
|
+
logger.debug(`Metric ${point.name}`, {
|
|
60
|
+
metric: point.name,
|
|
61
|
+
kind: point.kind,
|
|
62
|
+
value: point.value,
|
|
63
|
+
...point.labels
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
ConsoleProvider
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=console-provider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/provider/console-provider.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n LogRecord,\n MetricPoint,\n Span,\n SpanOptions,\n TelemetryProvider,\n TelemetrySignal,\n TraceCarrier,\n TraceContext,\n} from '../types'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { serializeError } from '../facade/serialize'\nimport { runSpan } from './run-span'\n\nconst logger = createLogger('telemetry')\n\n/**\n * Dev backend: prints span timings and metric points to stdout (via the shared\n * logger). It does NOT handle logs \u2014 the facade's logger already writes those to\n * stdout, so `emitLog` is a no-op here to avoid duplication.\n */\nclass ConsoleSpan implements Span {\n private readonly attributes: Record<string, unknown> = {}\n private status: 'ok' | 'error' = 'ok'\n private readonly startedAt = Date.now()\n\n constructor(private readonly name: string) {}\n\n setAttribute(key: string, value: string | number | boolean): void {\n this.attributes[key] = value\n }\n setAttributes(attributes: Record<string, string | number | boolean | undefined>): void {\n Object.assign(this.attributes, attributes)\n }\n recordException(error: unknown): void {\n this.status = 'error'\n this.attributes.exception = serializeError(error).message\n }\n setStatus(status: 'ok' | 'error'): void {\n this.status = status\n }\n end(): void {\n logger[this.status === 'error' ? 'error' : 'debug'](`Span ${this.name}`, {\n span: this.name,\n durationMs: Date.now() - this.startedAt,\n status: this.status,\n })\n }\n}\n\nexport class ConsoleProvider implements TelemetryProvider {\n readonly name = 'console'\n readonly supports: readonly TelemetrySignal[] = ['traces', 'metrics']\n\n async start(): Promise<void> {}\n async shutdown(): Promise<void> {}\n\n runInSpan<T>(name: string, _options: SpanOptions, fn: (span: Span) => T): T {\n return runSpan(new ConsoleSpan(name), fn)\n }\n\n activeSpan(): Span | undefined {\n return undefined\n }\n\n activeTraceContext(): TraceContext | undefined {\n // ConsoleSpan carries no real trace ids (dev-only timing print).\n return undefined\n }\n\n inject(_carrier: TraceCarrier): void {}\n\n runInRemoteSpan<T>(_carrier: TraceCarrier, name: string, _options: SpanOptions, fn: (span: Span) => T): T {\n return runSpan(new ConsoleSpan(name), fn)\n }\n\n emitLog(_record: LogRecord): void {}\n\n recordMetric(point: MetricPoint): void {\n logger.debug(`Metric ${point.name}`, {\n metric: point.name,\n kind: point.kind,\n value: point.value,\n ...point.labels,\n })\n }\n}\n"],
|
|
5
|
+
"mappings": "AAUA,SAAS,oBAAoB;AAC7B,SAAS,sBAAsB;AAC/B,SAAS,eAAe;AAExB,MAAM,SAAS,aAAa,WAAW;AAOvC,MAAM,YAA4B;AAAA,EAKhC,YAA6B,MAAc;AAAd;AAJ7B,SAAiB,aAAsC,CAAC;AACxD,SAAQ,SAAyB;AACjC,SAAiB,YAAY,KAAK,IAAI;AAAA,EAEM;AAAA,EAE5C,aAAa,KAAa,OAAwC;AAChE,SAAK,WAAW,GAAG,IAAI;AAAA,EACzB;AAAA,EACA,cAAc,YAAyE;AACrF,WAAO,OAAO,KAAK,YAAY,UAAU;AAAA,EAC3C;AAAA,EACA,gBAAgB,OAAsB;AACpC,SAAK,SAAS;AACd,SAAK,WAAW,YAAY,eAAe,KAAK,EAAE;AAAA,EACpD;AAAA,EACA,UAAU,QAA8B;AACtC,SAAK,SAAS;AAAA,EAChB;AAAA,EACA,MAAY;AACV,WAAO,KAAK,WAAW,UAAU,UAAU,OAAO,EAAE,QAAQ,KAAK,IAAI,IAAI;AAAA,MACvE,MAAM,KAAK;AAAA,MACX,YAAY,KAAK,IAAI,IAAI,KAAK;AAAA,MAC9B,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AACF;AAEO,MAAM,gBAA6C;AAAA,EAAnD;AACL,SAAS,OAAO;AAChB,SAAS,WAAuC,CAAC,UAAU,SAAS;AAAA;AAAA,EAEpE,MAAM,QAAuB;AAAA,EAAC;AAAA,EAC9B,MAAM,WAA0B;AAAA,EAAC;AAAA,EAEjC,UAAa,MAAc,UAAuB,IAA0B;AAC1E,WAAO,QAAQ,IAAI,YAAY,IAAI,GAAG,EAAE;AAAA,EAC1C;AAAA,EAEA,aAA+B;AAC7B,WAAO;AAAA,EACT;AAAA,EAEA,qBAA+C;AAE7C,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,UAA8B;AAAA,EAAC;AAAA,EAEtC,gBAAmB,UAAwB,MAAc,UAAuB,IAA0B;AACxG,WAAO,QAAQ,IAAI,YAAY,IAAI,GAAG,EAAE;AAAA,EAC1C;AAAA,EAEA,QAAQ,SAA0B;AAAA,EAAC;AAAA,EAEnC,aAAa,OAA0B;AACrC,WAAO,MAAM,UAAU,MAAM,IAAI,IAAI;AAAA,MACnC,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,OAAO,MAAM;AAAA,MACb,GAAG,MAAM;AAAA,IACX,CAAC;AAAA,EACH;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const NOOP_SPAN = {
|
|
2
|
+
setAttribute() {
|
|
3
|
+
},
|
|
4
|
+
setAttributes() {
|
|
5
|
+
},
|
|
6
|
+
recordException() {
|
|
7
|
+
},
|
|
8
|
+
setStatus() {
|
|
9
|
+
},
|
|
10
|
+
end() {
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
class NoopProvider {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.name = "noop";
|
|
16
|
+
this.supports = [];
|
|
17
|
+
}
|
|
18
|
+
async start() {
|
|
19
|
+
}
|
|
20
|
+
async shutdown() {
|
|
21
|
+
}
|
|
22
|
+
runInSpan(_name, _options, fn) {
|
|
23
|
+
return fn(NOOP_SPAN);
|
|
24
|
+
}
|
|
25
|
+
activeSpan() {
|
|
26
|
+
return void 0;
|
|
27
|
+
}
|
|
28
|
+
activeTraceContext() {
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
inject(_carrier) {
|
|
32
|
+
}
|
|
33
|
+
runInRemoteSpan(_carrier, _name, _options, fn) {
|
|
34
|
+
return fn(NOOP_SPAN);
|
|
35
|
+
}
|
|
36
|
+
emitLog(_record) {
|
|
37
|
+
}
|
|
38
|
+
recordMetric(_point) {
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
NOOP_SPAN,
|
|
43
|
+
NoopProvider
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=noop-provider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/provider/noop-provider.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n LogRecord,\n MetricPoint,\n Span,\n SpanOptions,\n TelemetryProvider,\n TelemetrySignal,\n TraceCarrier,\n TraceContext,\n} from '../types'\n\n/** A span that does nothing \u2014 used when telemetry is off. */\nexport const NOOP_SPAN: Span = {\n setAttribute() {},\n setAttributes() {},\n recordException() {},\n setStatus() {},\n end() {},\n}\n\n/**\n * The default backend: a hard no-op. `runInSpan` still runs `fn` (so app logic\n * is unaffected); everything else is a cheap return. The heavy OTEL SDK is\n * never imported on this path.\n */\nexport class NoopProvider implements TelemetryProvider {\n readonly name = 'noop'\n readonly supports: readonly TelemetrySignal[] = []\n\n async start(): Promise<void> {}\n async shutdown(): Promise<void> {}\n\n runInSpan<T>(_name: string, _options: SpanOptions, fn: (span: Span) => T): T {\n return fn(NOOP_SPAN)\n }\n\n activeSpan(): Span | undefined {\n return undefined\n }\n\n activeTraceContext(): TraceContext | undefined {\n return undefined\n }\n\n inject(_carrier: TraceCarrier): void {}\n\n runInRemoteSpan<T>(_carrier: TraceCarrier, _name: string, _options: SpanOptions, fn: (span: Span) => T): T {\n return fn(NOOP_SPAN)\n }\n\n emitLog(_record: LogRecord): void {}\n recordMetric(_point: MetricPoint): void {}\n}\n"],
|
|
5
|
+
"mappings": "AAYO,MAAM,YAAkB;AAAA,EAC7B,eAAe;AAAA,EAAC;AAAA,EAChB,gBAAgB;AAAA,EAAC;AAAA,EACjB,kBAAkB;AAAA,EAAC;AAAA,EACnB,YAAY;AAAA,EAAC;AAAA,EACb,MAAM;AAAA,EAAC;AACT;AAOO,MAAM,aAA0C;AAAA,EAAhD;AACL,SAAS,OAAO;AAChB,SAAS,WAAuC,CAAC;AAAA;AAAA,EAEjD,MAAM,QAAuB;AAAA,EAAC;AAAA,EAC9B,MAAM,WAA0B;AAAA,EAAC;AAAA,EAEjC,UAAa,OAAe,UAAuB,IAA0B;AAC3E,WAAO,GAAG,SAAS;AAAA,EACrB;AAAA,EAEA,aAA+B;AAC7B,WAAO;AAAA,EACT;AAAA,EAEA,qBAA+C;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,UAA8B;AAAA,EAAC;AAAA,EAEtC,gBAAmB,UAAwB,OAAe,UAAuB,IAA0B;AACzG,WAAO,GAAG,SAAS;AAAA,EACrB;AAAA,EAEA,QAAQ,SAA0B;AAAA,EAAC;AAAA,EACnC,aAAa,QAA2B;AAAA,EAAC;AAC3C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
trace,
|
|
3
|
+
metrics,
|
|
4
|
+
context,
|
|
5
|
+
isSpanContextValid,
|
|
6
|
+
defaultTextMapGetter,
|
|
7
|
+
defaultTextMapSetter,
|
|
8
|
+
SpanStatusCode,
|
|
9
|
+
SpanKind as OtelSpanKind
|
|
10
|
+
} from "@opentelemetry/api";
|
|
11
|
+
import { W3CTraceContextPropagator } from "@opentelemetry/core";
|
|
12
|
+
import { logs, SeverityNumber } from "@opentelemetry/api-logs";
|
|
13
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
14
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
15
|
+
import { ATTR_SERVICE_NAME } from "@opentelemetry/semantic-conventions";
|
|
16
|
+
import {
|
|
17
|
+
BatchSpanProcessor,
|
|
18
|
+
ParentBasedSampler,
|
|
19
|
+
TraceIdRatioBasedSampler
|
|
20
|
+
} from "@opentelemetry/sdk-trace-node";
|
|
21
|
+
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
|
|
22
|
+
import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
|
|
23
|
+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
|
|
24
|
+
import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
|
|
25
|
+
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
26
|
+
import { PgInstrumentation } from "@opentelemetry/instrumentation-pg";
|
|
27
|
+
import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
|
|
28
|
+
import { readTelemetryEnv } from "../env.js";
|
|
29
|
+
import { redactAttributes, redactPii } from "../facade/redact.js";
|
|
30
|
+
import { serializeError } from "../facade/serialize.js";
|
|
31
|
+
import { runSpan } from "./run-span.js";
|
|
32
|
+
const TRACER_NAME = "open-mercato";
|
|
33
|
+
const queuePropagator = new W3CTraceContextPropagator();
|
|
34
|
+
const W3C_TRACEPARENT = "traceparent";
|
|
35
|
+
const W3C_TRACESTATE = "tracestate";
|
|
36
|
+
const BACKUP_TRACEPARENT = "x-original-traceparent";
|
|
37
|
+
const BACKUP_TRACESTATE = "x-original-tracestate";
|
|
38
|
+
const backupHeaderPropagator = {
|
|
39
|
+
inject(ctx, carrier, setter) {
|
|
40
|
+
const tmp = {};
|
|
41
|
+
queuePropagator.inject(ctx, tmp, defaultTextMapSetter);
|
|
42
|
+
for (const [key, value] of Object.entries(tmp)) setter.set(carrier, key, value);
|
|
43
|
+
if (tmp[W3C_TRACEPARENT]) setter.set(carrier, BACKUP_TRACEPARENT, tmp[W3C_TRACEPARENT]);
|
|
44
|
+
if (tmp[W3C_TRACESTATE]) setter.set(carrier, BACKUP_TRACESTATE, tmp[W3C_TRACESTATE]);
|
|
45
|
+
},
|
|
46
|
+
extract(ctx, carrier, getter) {
|
|
47
|
+
if (!readTelemetryEnv().trustInboundTrace) return ctx;
|
|
48
|
+
const first = (value) => Array.isArray(value) ? value[0] : value;
|
|
49
|
+
const backupTraceparent = first(getter.get(carrier, BACKUP_TRACEPARENT));
|
|
50
|
+
if (backupTraceparent) {
|
|
51
|
+
const backupCarrier = { [W3C_TRACEPARENT]: backupTraceparent };
|
|
52
|
+
const backupTracestate = first(getter.get(carrier, BACKUP_TRACESTATE));
|
|
53
|
+
if (backupTracestate) backupCarrier[W3C_TRACESTATE] = backupTracestate;
|
|
54
|
+
return queuePropagator.extract(ctx, backupCarrier, defaultTextMapGetter);
|
|
55
|
+
}
|
|
56
|
+
return queuePropagator.extract(ctx, carrier, getter);
|
|
57
|
+
},
|
|
58
|
+
fields: () => [...queuePropagator.fields(), BACKUP_TRACEPARENT, BACKUP_TRACESTATE]
|
|
59
|
+
};
|
|
60
|
+
function cleanAttributes(attributes) {
|
|
61
|
+
const out = {};
|
|
62
|
+
if (!attributes) return out;
|
|
63
|
+
for (const [key, value] of Object.entries(redactAttributes(attributes))) {
|
|
64
|
+
if (value !== void 0) out[key] = value;
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
const SPAN_KIND = {
|
|
69
|
+
internal: OtelSpanKind.INTERNAL,
|
|
70
|
+
server: OtelSpanKind.SERVER,
|
|
71
|
+
client: OtelSpanKind.CLIENT,
|
|
72
|
+
producer: OtelSpanKind.PRODUCER,
|
|
73
|
+
consumer: OtelSpanKind.CONSUMER
|
|
74
|
+
};
|
|
75
|
+
const SEVERITY = {
|
|
76
|
+
debug: SeverityNumber.DEBUG,
|
|
77
|
+
info: SeverityNumber.INFO,
|
|
78
|
+
warn: SeverityNumber.WARN,
|
|
79
|
+
error: SeverityNumber.ERROR
|
|
80
|
+
};
|
|
81
|
+
class OtelSpan {
|
|
82
|
+
constructor(span) {
|
|
83
|
+
this.span = span;
|
|
84
|
+
}
|
|
85
|
+
setAttribute(key, value) {
|
|
86
|
+
const redacted = cleanAttributes({ [key]: value })[key];
|
|
87
|
+
if (redacted !== void 0) this.span.setAttribute(key, redacted);
|
|
88
|
+
}
|
|
89
|
+
setAttributes(attributes) {
|
|
90
|
+
this.span.setAttributes(cleanAttributes(attributes));
|
|
91
|
+
}
|
|
92
|
+
recordException(error) {
|
|
93
|
+
this.span.recordException(serializeError(error));
|
|
94
|
+
}
|
|
95
|
+
setStatus(status, message) {
|
|
96
|
+
this.span.setStatus({
|
|
97
|
+
code: status === "error" ? SpanStatusCode.ERROR : SpanStatusCode.OK,
|
|
98
|
+
message: message ? redactPii(message) : void 0
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
end() {
|
|
102
|
+
this.span.end();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const PG_INSTRUMENTATION_OPTIONS = { enhancedDatabaseReporting: false };
|
|
106
|
+
class OtlpProvider {
|
|
107
|
+
constructor(options = {}, name = "otlp") {
|
|
108
|
+
this.options = options;
|
|
109
|
+
this.supports = ["traces", "metrics", "logs", "errors"];
|
|
110
|
+
this.instruments = /* @__PURE__ */ new Map();
|
|
111
|
+
this.name = name;
|
|
112
|
+
}
|
|
113
|
+
async start() {
|
|
114
|
+
if (this.sdk) return;
|
|
115
|
+
const env = readTelemetryEnv();
|
|
116
|
+
this.sdk = new NodeSDK({
|
|
117
|
+
resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: env.serviceName }),
|
|
118
|
+
// Global propagation roots requests by default. Both standard and backup
|
|
119
|
+
// inbound headers are honored only when TELEMETRY_TRUST_INBOUND_TRACE is
|
|
120
|
+
// explicitly enabled behind trusted infrastructure.
|
|
121
|
+
textMapPropagator: backupHeaderPropagator,
|
|
122
|
+
// Parent-based so child spans follow the trace's sampling decision; root
|
|
123
|
+
// spans sample at the configured ratio.
|
|
124
|
+
sampler: new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(env.samplingRatio) }),
|
|
125
|
+
spanProcessors: this.options.spanProcessors ?? [new BatchSpanProcessor(new OTLPTraceExporter())],
|
|
126
|
+
logRecordProcessors: this.options.logRecordProcessors ?? [
|
|
127
|
+
new BatchLogRecordProcessor({ exporter: new OTLPLogExporter() })
|
|
128
|
+
],
|
|
129
|
+
metricReaders: this.options.metricReaders ?? [
|
|
130
|
+
new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter() })
|
|
131
|
+
],
|
|
132
|
+
instrumentations: this.options.instrumentations ?? [
|
|
133
|
+
new PgInstrumentation(PG_INSTRUMENTATION_OPTIONS),
|
|
134
|
+
new UndiciInstrumentation()
|
|
135
|
+
]
|
|
136
|
+
});
|
|
137
|
+
this.sdk.start();
|
|
138
|
+
}
|
|
139
|
+
async shutdown() {
|
|
140
|
+
if (!this.sdk) return;
|
|
141
|
+
await this.sdk.shutdown();
|
|
142
|
+
this.sdk = void 0;
|
|
143
|
+
}
|
|
144
|
+
runInSpan(name, options, fn) {
|
|
145
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
146
|
+
return tracer.startActiveSpan(
|
|
147
|
+
name,
|
|
148
|
+
{ kind: options.kind ? SPAN_KIND[options.kind] : void 0, attributes: cleanAttributes(options.attributes) },
|
|
149
|
+
(otelSpan) => runSpan(new OtelSpan(otelSpan), fn)
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
activeSpan() {
|
|
153
|
+
const active = trace.getActiveSpan();
|
|
154
|
+
return active ? new OtelSpan(active) : void 0;
|
|
155
|
+
}
|
|
156
|
+
activeTraceContext() {
|
|
157
|
+
const ctx = trace.getActiveSpan()?.spanContext();
|
|
158
|
+
if (!ctx || !isSpanContextValid(ctx)) return void 0;
|
|
159
|
+
return { traceId: ctx.traceId, spanId: ctx.spanId };
|
|
160
|
+
}
|
|
161
|
+
inject(carrier) {
|
|
162
|
+
queuePropagator.inject(context.active(), carrier, defaultTextMapSetter);
|
|
163
|
+
}
|
|
164
|
+
runInRemoteSpan(carrier, name, options, fn) {
|
|
165
|
+
const parent = queuePropagator.extract(context.active(), carrier, defaultTextMapGetter);
|
|
166
|
+
const tracer = trace.getTracer(TRACER_NAME);
|
|
167
|
+
return context.with(
|
|
168
|
+
parent,
|
|
169
|
+
() => tracer.startActiveSpan(
|
|
170
|
+
name,
|
|
171
|
+
{ kind: options.kind ? SPAN_KIND[options.kind] : void 0, attributes: cleanAttributes(options.attributes) },
|
|
172
|
+
(otelSpan) => runSpan(new OtelSpan(otelSpan), fn)
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
emitLog(record) {
|
|
177
|
+
const attributes = cleanAttributes(record.attributes);
|
|
178
|
+
if (record.error) {
|
|
179
|
+
attributes["exception.type"] = redactPii(record.error.name);
|
|
180
|
+
attributes["exception.message"] = redactPii(record.error.message);
|
|
181
|
+
if (record.error.stack) attributes["exception.stacktrace"] = redactPii(record.error.stack);
|
|
182
|
+
}
|
|
183
|
+
logs.getLogger(TRACER_NAME).emit({
|
|
184
|
+
severityNumber: SEVERITY[record.level],
|
|
185
|
+
severityText: record.level,
|
|
186
|
+
body: redactPii(record.message),
|
|
187
|
+
attributes
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
recordMetric(point) {
|
|
191
|
+
const labels = cleanAttributes(point.labels);
|
|
192
|
+
const instrument = this.getInstrument(point);
|
|
193
|
+
if (point.kind === "counter") instrument.add(point.value, labels);
|
|
194
|
+
else instrument.record(point.value, labels);
|
|
195
|
+
}
|
|
196
|
+
getInstrument(point) {
|
|
197
|
+
const key = `${point.kind}:${point.name}`;
|
|
198
|
+
let instrument = this.instruments.get(key);
|
|
199
|
+
if (!instrument) {
|
|
200
|
+
const meter = metrics.getMeter(TRACER_NAME);
|
|
201
|
+
const opts = point.unit ? { unit: point.unit } : void 0;
|
|
202
|
+
instrument = point.kind === "counter" ? meter.createCounter(point.name, opts) : point.kind === "histogram" ? meter.createHistogram(point.name, opts) : meter.createGauge(point.name, opts);
|
|
203
|
+
this.instruments.set(key, instrument);
|
|
204
|
+
}
|
|
205
|
+
return instrument;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
export {
|
|
209
|
+
OtlpProvider,
|
|
210
|
+
PG_INSTRUMENTATION_OPTIONS
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=otlp-provider.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/provider/otlp-provider.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * The ONLY file in this package that imports `@opentelemetry/*`. Loaded via\n * dynamic `import()` from `init.ts` (so the heavy SDK never loads when telemetry\n * is off), and the OTEL packages live in `optionalDependencies`.\n *\n * Serves any OTLP backend \u2014 the endpoint + headers come from the standard\n * `OTEL_EXPORTER_OTLP_*` env vars, read by the exporters directly.\n */\nimport {\n trace,\n metrics,\n context,\n isSpanContextValid,\n defaultTextMapGetter,\n defaultTextMapSetter,\n SpanStatusCode,\n SpanKind as OtelSpanKind,\n type Span as OtelApiSpan,\n type TextMapPropagator,\n type Counter,\n type Histogram,\n type Gauge,\n} from '@opentelemetry/api'\nimport { W3CTraceContextPropagator } from '@opentelemetry/core'\nimport { logs, SeverityNumber } from '@opentelemetry/api-logs'\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport type { Instrumentation } from '@opentelemetry/instrumentation'\nimport { resourceFromAttributes } from '@opentelemetry/resources'\nimport { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'\nimport {\n BatchSpanProcessor,\n ParentBasedSampler,\n TraceIdRatioBasedSampler,\n type SpanProcessor,\n} from '@opentelemetry/sdk-trace-node'\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http'\nimport { BatchLogRecordProcessor, type LogRecordProcessor } from '@opentelemetry/sdk-logs'\nimport { PeriodicExportingMetricReader, type IMetricReader } from '@opentelemetry/sdk-metrics'\nimport { PgInstrumentation } from '@opentelemetry/instrumentation-pg'\nimport { UndiciInstrumentation } from '@opentelemetry/instrumentation-undici'\n\nimport type {\n Attributes,\n AttributeValue,\n LogLevel,\n LogRecord,\n MetricPoint,\n Span,\n SpanKind,\n SpanOptions,\n TelemetryProvider,\n TelemetrySignal,\n TraceCarrier,\n TraceContext,\n} from '../types'\nimport { readTelemetryEnv } from '../env'\nimport { redactAttributes, redactPii } from '../facade/redact'\nimport { serializeError } from '../facade/serialize'\nimport { runSpan } from './run-span'\n\nconst TRACER_NAME = 'open-mercato'\n\n/**\n * Queue/event trace propagation rides a dedicated W3C propagator on the payload\n * `_trace` carrier \u2014 deliberately NOT the global propagator below.\n */\nconst queuePropagator = new W3CTraceContextPropagator()\n\nconst W3C_TRACEPARENT = 'traceparent'\nconst W3C_TRACESTATE = 'tracestate'\n// Backup headers that mirror the W3C context but a proxy/LB won't rewrite.\nconst BACKUP_TRACEPARENT = 'x-original-traceparent'\nconst BACKUP_TRACESTATE = 'x-original-tracestate'\n\n/**\n * Global propagator: standard W3C plus a backup copy\n * (`x-original-traceparent`), with explicit inbound trust.\n *\n * The problem: a load balancer (e.g. GCP's) reads the inbound `traceparent`,\n * creates its own span, and **rewrites** `traceparent` to point at that span \u2014\n * which our backend never sees. With plain W3C extraction every request becomes a\n * child of that unexported span: no request is a root, and root-span / trace-group\n * views come up empty.\n *\n * The fix (the industry \"backup header\" pattern): on inject we also write\n * `x-original-traceparent`, which the LB leaves untouched. A backup header is\n * still caller-controlled at an HTTP boundary, so its mere\n * presence is not proof that one of our services created it. Extraction ignores\n * both standard and backup headers by default.\n *\n * `TELEMETRY_TRUST_INBOUND_TRACE=true` enables both extraction paths for a\n * deployment behind a trusted upstream. Our dedicated queue/event carrier is\n * unaffected \u2014 it uses `queuePropagator` directly, not this global one.\n */\nconst backupHeaderPropagator: TextMapPropagator = {\n inject(ctx, carrier, setter) {\n // Inject into a plain temp carrier so we can mirror the values regardless of\n // the real carrier's setter shape, then copy both standard + backup headers.\n const tmp: Record<string, string> = {}\n queuePropagator.inject(ctx, tmp, defaultTextMapSetter)\n for (const [key, value] of Object.entries(tmp)) setter.set(carrier, key, value)\n if (tmp[W3C_TRACEPARENT]) setter.set(carrier, BACKUP_TRACEPARENT, tmp[W3C_TRACEPARENT])\n if (tmp[W3C_TRACESTATE]) setter.set(carrier, BACKUP_TRACESTATE, tmp[W3C_TRACESTATE])\n },\n extract(ctx, carrier, getter) {\n // Both the standard and backup headers are caller-controlled at an HTTP\n // boundary. Trust neither unless the deployment explicitly opts in.\n if (!readTelemetryEnv().trustInboundTrace) return ctx\n const first = (value: string | string[] | undefined): string | undefined =>\n Array.isArray(value) ? value[0] : value\n const backupTraceparent = first(getter.get(carrier, BACKUP_TRACEPARENT))\n if (backupTraceparent) {\n const backupCarrier: Record<string, string> = { [W3C_TRACEPARENT]: backupTraceparent }\n const backupTracestate = first(getter.get(carrier, BACKUP_TRACESTATE))\n if (backupTracestate) backupCarrier[W3C_TRACESTATE] = backupTracestate\n return queuePropagator.extract(ctx, backupCarrier, defaultTextMapGetter)\n }\n return queuePropagator.extract(ctx, carrier, getter)\n },\n fields: () => [...queuePropagator.fields(), BACKUP_TRACEPARENT, BACKUP_TRACESTATE],\n}\n\nfunction cleanAttributes(attributes?: Attributes): Record<string, AttributeValue> {\n const out: Record<string, AttributeValue> = {}\n if (!attributes) return out\n for (const [key, value] of Object.entries(redactAttributes(attributes))) {\n if (value !== undefined) out[key] = value\n }\n return out\n}\n\nconst SPAN_KIND: Record<SpanKind, OtelSpanKind> = {\n internal: OtelSpanKind.INTERNAL,\n server: OtelSpanKind.SERVER,\n client: OtelSpanKind.CLIENT,\n producer: OtelSpanKind.PRODUCER,\n consumer: OtelSpanKind.CONSUMER,\n}\n\nconst SEVERITY: Record<LogLevel, SeverityNumber> = {\n debug: SeverityNumber.DEBUG,\n info: SeverityNumber.INFO,\n warn: SeverityNumber.WARN,\n error: SeverityNumber.ERROR,\n}\n\n/** Adapts an OTEL span to the vendor-neutral `Span` interface. */\nclass OtelSpan implements Span {\n constructor(private readonly span: OtelApiSpan) {}\n setAttribute(key: string, value: AttributeValue): void {\n const redacted = cleanAttributes({ [key]: value })[key]\n if (redacted !== undefined) this.span.setAttribute(key, redacted)\n }\n setAttributes(attributes: Attributes): void {\n this.span.setAttributes(cleanAttributes(attributes))\n }\n recordException(error: unknown): void {\n // Redact message + stack before they leave the process (Privacy): the auto\n // record-on-throw path (run-span) and reportError both pass raw errors here.\n this.span.recordException(serializeError(error))\n }\n setStatus(status: 'ok' | 'error', message?: string): void {\n this.span.setStatus({\n code: status === 'error' ? SpanStatusCode.ERROR : SpanStatusCode.OK,\n message: message ? redactPii(message) : undefined,\n })\n }\n end(): void {\n this.span.end()\n }\n}\n\n/**\n * Test seam: override the SDK's exporters/instrumentations so tests can use\n * in-memory exporters (deterministic, no network) instead of the OTLP defaults.\n * Production passes nothing \u2014 the OTLP defaults apply.\n */\nexport type OtlpProviderOptions = {\n spanProcessors?: SpanProcessor[]\n logRecordProcessors?: LogRecordProcessor[]\n metricReaders?: IMetricReader[]\n instrumentations?: Instrumentation[]\n}\n\n/**\n * PII guard (telemetry spec Privacy / R12). The single source of truth for pg\n * instrumentation config: `enhancedDatabaseReporting: false` means bound SQL\n * parameter VALUES are NOT captured \u2014 only the statement shape ($1, $2). User\n * data lives in those params, so this must never be flipped on. Asserted by a\n * regression test.\n */\nexport const PG_INSTRUMENTATION_OPTIONS = { enhancedDatabaseReporting: false } as const\n\nexport class OtlpProvider implements TelemetryProvider {\n /** The configured backend name (signoz | newrelic | otlp) \u2014 all OTLP, vendor differs only by endpoint. */\n readonly name: string\n readonly supports: readonly TelemetrySignal[] = ['traces', 'metrics', 'logs', 'errors']\n\n private sdk: NodeSDK | undefined\n private readonly instruments = new Map<string, Counter | Histogram | Gauge>()\n\n constructor(private readonly options: OtlpProviderOptions = {}, name = 'otlp') {\n this.name = name\n }\n\n async start(): Promise<void> {\n if (this.sdk) return\n const env = readTelemetryEnv()\n\n this.sdk = new NodeSDK({\n resource: resourceFromAttributes({ [ATTR_SERVICE_NAME]: env.serviceName }),\n // Global propagation roots requests by default. Both standard and backup\n // inbound headers are honored only when TELEMETRY_TRUST_INBOUND_TRACE is\n // explicitly enabled behind trusted infrastructure.\n textMapPropagator: backupHeaderPropagator,\n // Parent-based so child spans follow the trace's sampling decision; root\n // spans sample at the configured ratio.\n sampler: new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(env.samplingRatio) }),\n spanProcessors: this.options.spanProcessors ?? [new BatchSpanProcessor(new OTLPTraceExporter())],\n logRecordProcessors: this.options.logRecordProcessors ?? [\n new BatchLogRecordProcessor({ exporter: new OTLPLogExporter() }),\n ],\n metricReaders: this.options.metricReaders ?? [\n new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter() }),\n ],\n instrumentations: this.options.instrumentations ?? [\n new PgInstrumentation(PG_INSTRUMENTATION_OPTIONS),\n new UndiciInstrumentation(),\n ],\n })\n this.sdk.start()\n }\n\n async shutdown(): Promise<void> {\n if (!this.sdk) return\n await this.sdk.shutdown()\n this.sdk = undefined\n }\n\n runInSpan<T>(name: string, options: SpanOptions, fn: (span: Span) => T): T {\n const tracer = trace.getTracer(TRACER_NAME)\n return tracer.startActiveSpan(\n name,\n { kind: options.kind ? SPAN_KIND[options.kind] : undefined, attributes: cleanAttributes(options.attributes) },\n (otelSpan) => runSpan(new OtelSpan(otelSpan), fn),\n )\n }\n\n activeSpan(): Span | undefined {\n const active = trace.getActiveSpan()\n return active ? new OtelSpan(active) : undefined\n }\n\n activeTraceContext(): TraceContext | undefined {\n const ctx = trace.getActiveSpan()?.spanContext()\n if (!ctx || !isSpanContextValid(ctx)) return undefined\n return { traceId: ctx.traceId, spanId: ctx.spanId }\n }\n\n inject(carrier: TraceCarrier): void {\n queuePropagator.inject(context.active(), carrier, defaultTextMapSetter)\n }\n\n runInRemoteSpan<T>(carrier: TraceCarrier, name: string, options: SpanOptions, fn: (span: Span) => T): T {\n const parent = queuePropagator.extract(context.active(), carrier, defaultTextMapGetter)\n const tracer = trace.getTracer(TRACER_NAME)\n return context.with(parent, () =>\n tracer.startActiveSpan(\n name,\n { kind: options.kind ? SPAN_KIND[options.kind] : undefined, attributes: cleanAttributes(options.attributes) },\n (otelSpan) => runSpan(new OtelSpan(otelSpan), fn),\n ),\n )\n }\n\n emitLog(record: LogRecord): void {\n const attributes: Record<string, AttributeValue> = cleanAttributes(record.attributes)\n if (record.error) {\n attributes['exception.type'] = redactPii(record.error.name)\n attributes['exception.message'] = redactPii(record.error.message)\n if (record.error.stack) attributes['exception.stacktrace'] = redactPii(record.error.stack)\n }\n logs.getLogger(TRACER_NAME).emit({\n severityNumber: SEVERITY[record.level],\n severityText: record.level,\n body: redactPii(record.message),\n attributes,\n })\n }\n\n recordMetric(point: MetricPoint): void {\n const labels = cleanAttributes(point.labels)\n const instrument = this.getInstrument(point)\n if (point.kind === 'counter') (instrument as Counter).add(point.value, labels)\n else (instrument as Histogram | Gauge).record(point.value, labels)\n }\n\n private getInstrument(point: MetricPoint): Counter | Histogram | Gauge {\n const key = `${point.kind}:${point.name}`\n let instrument = this.instruments.get(key)\n if (!instrument) {\n const meter = metrics.getMeter(TRACER_NAME)\n const opts = point.unit ? { unit: point.unit } : undefined\n instrument =\n point.kind === 'counter'\n ? meter.createCounter(point.name, opts)\n : point.kind === 'histogram'\n ? meter.createHistogram(point.name, opts)\n : meter.createGauge(point.name, opts)\n this.instruments.set(key, instrument)\n }\n return instrument\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|