autotel-tanstack 1.13.24 → 1.13.26
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/dist/auto.d.ts +13 -17
- package/dist/auto.js +9 -46
- package/dist/auto.js.map +1 -1
- package/dist/chunk-7OXOAS64.js +41 -0
- package/dist/chunk-7OXOAS64.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/instrument-DRR7VL63.d.ts +46 -0
- package/package.json +3 -3
- package/src/auto.test.ts +13 -6
- package/src/auto.ts +21 -80
- package/src/index.ts +4 -0
- package/src/instrument.test.ts +131 -0
- package/src/instrument.ts +97 -0
package/dist/auto.d.ts
CHANGED
|
@@ -1,46 +1,42 @@
|
|
|
1
|
+
export { i as instrument } from './instrument-DRR7VL63.js';
|
|
1
2
|
export { functionTracingMiddleware, tracingMiddleware } from './middleware.js';
|
|
2
3
|
export { traceServerFn } from './server-functions.js';
|
|
3
4
|
export { traceBeforeLoad, traceLoader } from './loaders.js';
|
|
5
|
+
import 'autotel';
|
|
4
6
|
import './types-m5OjZJ-4.js';
|
|
5
7
|
import '@opentelemetry/api';
|
|
6
8
|
import '@tanstack/react-router';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
|
-
* Zero-config auto-instrumentation for TanStack Start
|
|
11
|
+
* Zero-config auto-instrumentation for TanStack Start.
|
|
10
12
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
+
* Importing this module configures OpenTelemetry tracing from environment
|
|
14
|
+
* variables — it is simply `instrument()` with no options. For subscribers,
|
|
15
|
+
* structured logs, canonical log lines, or an explicit endpoint, call
|
|
16
|
+
* `instrument(options)` from `autotel-tanstack` directly (see ./instrument).
|
|
13
17
|
*
|
|
14
|
-
* Environment Variables:
|
|
18
|
+
* Environment Variables (resolved by autotel core):
|
|
15
19
|
* - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')
|
|
16
20
|
* - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL
|
|
17
|
-
* - OTEL_EXPORTER_OTLP_HEADERS:
|
|
18
|
-
* - AUTOTEL_DEBUG:
|
|
21
|
+
* - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)
|
|
22
|
+
* - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console
|
|
19
23
|
*
|
|
20
24
|
* @example
|
|
21
25
|
* ```typescript
|
|
22
26
|
* // app/start.ts
|
|
23
27
|
* import 'autotel-tanstack/auto';
|
|
24
28
|
* import { createStart } from '@tanstack/react-start';
|
|
25
|
-
*
|
|
26
|
-
* // Tracing is automatically configured!
|
|
27
29
|
* export const startInstance = createStart(() => ({}));
|
|
28
30
|
* ```
|
|
29
31
|
*
|
|
30
32
|
* @module
|
|
31
33
|
*/
|
|
32
34
|
|
|
33
|
-
/**
|
|
34
|
-
* Check if auto-instrumentation is active
|
|
35
|
-
*/
|
|
35
|
+
/** Check if auto-instrumentation is active. */
|
|
36
36
|
declare function isAutoInstrumentationActive(): boolean;
|
|
37
|
-
/**
|
|
38
|
-
* Get the configured service name
|
|
39
|
-
*/
|
|
37
|
+
/** The configured service name. */
|
|
40
38
|
declare function getServiceName(): string;
|
|
41
|
-
/**
|
|
42
|
-
* Get the configured endpoint
|
|
43
|
-
*/
|
|
39
|
+
/** The configured OTLP endpoint, if any. */
|
|
44
40
|
declare function getEndpoint(): string | undefined;
|
|
45
41
|
|
|
46
42
|
export { getEndpoint, getServiceName, isAutoInstrumentationActive };
|
package/dist/auto.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { instrument } from './chunk-7OXOAS64.js';
|
|
2
|
+
export { instrument } from './chunk-7OXOAS64.js';
|
|
1
3
|
export { functionTracingMiddleware, tracingMiddleware } from './chunk-LRA2UVVS.js';
|
|
2
4
|
export { traceServerFn } from './chunk-ESU66L3L.js';
|
|
3
5
|
export { traceBeforeLoad, traceLoader } from './chunk-KPXGFKPU.js';
|
|
@@ -6,62 +8,23 @@ import './chunk-CCME55EK.js';
|
|
|
6
8
|
import './chunk-I4LX3LOG.js';
|
|
7
9
|
import './chunk-NTY64BKS.js';
|
|
8
10
|
import './chunk-EGRHWZRV.js';
|
|
9
|
-
import { init } from 'autotel';
|
|
10
|
-
import { InMemorySpanExporter } from 'autotel/exporters';
|
|
11
|
-
import { SimpleSpanProcessor } from 'autotel/processors';
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
var headers;
|
|
16
|
-
if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {
|
|
17
|
-
headers = {};
|
|
18
|
-
const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(",");
|
|
19
|
-
for (const pair of pairs) {
|
|
20
|
-
const [key, value] = pair.split("=");
|
|
21
|
-
if (key && value) {
|
|
22
|
-
headers[key.trim()] = value.trim();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function resolveDebug() {
|
|
27
|
-
const env = process.env.AUTOTEL_DEBUG;
|
|
28
|
-
if (env === "pretty") return "pretty";
|
|
29
|
-
if (env === "true" || env === "1") return true;
|
|
30
|
-
if (env === "false" || env === "0") return false;
|
|
31
|
-
if (!endpoint && process.env.NODE_ENV === "development") return "pretty";
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
if (process.env.E2E === "1") {
|
|
35
|
-
const e2eExporter = new InMemorySpanExporter();
|
|
36
|
-
const e2eProcessor = new SimpleSpanProcessor(e2eExporter);
|
|
37
|
-
globalThis.__testSpanExporter = e2eExporter;
|
|
38
|
-
init({
|
|
39
|
-
service,
|
|
40
|
-
spanProcessors: [e2eProcessor]
|
|
41
|
-
});
|
|
42
|
-
} else {
|
|
43
|
-
init({
|
|
44
|
-
service,
|
|
45
|
-
endpoint,
|
|
46
|
-
headers,
|
|
47
|
-
debug: resolveDebug()
|
|
48
|
-
});
|
|
49
|
-
}
|
|
12
|
+
// src/auto.ts
|
|
13
|
+
instrument();
|
|
50
14
|
if (process.env.NODE_ENV === "development" || process.env.AUTOTEL_DEBUG) {
|
|
51
|
-
console.log("[autotel-tanstack] Auto-initialized
|
|
52
|
-
service,
|
|
53
|
-
endpoint: process.env.E2E === "1" ? "(E2E: in-memory)" :
|
|
54
|
-
hasHeaders: !!headers
|
|
15
|
+
console.log("[autotel-tanstack] Auto-initialized", {
|
|
16
|
+
service: process.env.OTEL_SERVICE_NAME || "tanstack-start",
|
|
17
|
+
endpoint: process.env.E2E === "1" ? "(E2E: in-memory)" : process.env.OTEL_EXPORTER_OTLP_ENDPOINT || "(not configured)"
|
|
55
18
|
});
|
|
56
19
|
}
|
|
57
20
|
function isAutoInstrumentationActive() {
|
|
58
21
|
return true;
|
|
59
22
|
}
|
|
60
23
|
function getServiceName() {
|
|
61
|
-
return
|
|
24
|
+
return process.env.OTEL_SERVICE_NAME || "tanstack-start";
|
|
62
25
|
}
|
|
63
26
|
function getEndpoint() {
|
|
64
|
-
return
|
|
27
|
+
return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
65
28
|
}
|
|
66
29
|
|
|
67
30
|
export { getEndpoint, getServiceName, isAutoInstrumentationActive };
|
package/dist/auto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auto.ts"],"names":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"sources":["../src/auto.ts"],"names":[],"mappings":";;;;;;;;;;;;AA2BA,UAAA,EAAW;AAGX,IAAI,QAAQ,GAAA,CAAI,QAAA,KAAa,aAAA,IAAiB,OAAA,CAAQ,IAAI,aAAA,EAAe;AACvE,EAAA,OAAA,CAAQ,IAAI,qCAAA,EAAuC;AAAA,IACjD,OAAA,EAAS,OAAA,CAAQ,GAAA,CAAI,iBAAA,IAAqB,gBAAA;AAAA,IAC1C,QAAA,EACE,QAAQ,GAAA,CAAI,GAAA,KAAQ,MAChB,kBAAA,GACA,OAAA,CAAQ,IAAI,2BAAA,IAA+B;AAAA,GAClD,CAAA;AACH;AASO,SAAS,2BAAA,GAAuC;AACrD,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,cAAA,GAAyB;AACvC,EAAA,OAAO,OAAA,CAAQ,IAAI,iBAAA,IAAqB,gBAAA;AAC1C;AAGO,SAAS,WAAA,GAAkC;AAChD,EAAA,OAAO,QAAQ,GAAA,CAAI,2BAAA;AACrB","file":"auto.js","sourcesContent":["/**\n * Zero-config auto-instrumentation for TanStack Start.\n *\n * Importing this module configures OpenTelemetry tracing from environment\n * variables — it is simply `instrument()` with no options. For subscribers,\n * structured logs, canonical log lines, or an explicit endpoint, call\n * `instrument(options)` from `autotel-tanstack` directly (see ./instrument).\n *\n * Environment Variables (resolved by autotel core):\n * - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')\n * - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL\n * - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)\n * - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console\n *\n * @example\n * ```typescript\n * // app/start.ts\n * import 'autotel-tanstack/auto';\n * import { createStart } from '@tanstack/react-start';\n * export const startInstance = createStart(() => ({}));\n * ```\n *\n * @module\n */\n\nimport { instrument } from './instrument';\n\ninstrument();\n\n// Surface what happened, in development only.\nif (process.env.NODE_ENV === 'development' || process.env.AUTOTEL_DEBUG) {\n console.log('[autotel-tanstack] Auto-initialized', {\n service: process.env.OTEL_SERVICE_NAME || 'tanstack-start',\n endpoint:\n process.env.E2E === '1'\n ? '(E2E: in-memory)'\n : process.env.OTEL_EXPORTER_OTLP_ENDPOINT || '(not configured)',\n });\n}\n\n// Re-export the configurable form + middleware/helpers for convenience.\nexport { instrument } from './instrument';\nexport { tracingMiddleware, functionTracingMiddleware } from './middleware';\nexport { traceServerFn } from './server-functions';\nexport { traceLoader, traceBeforeLoad } from './loaders';\n\n/** Check if auto-instrumentation is active. */\nexport function isAutoInstrumentationActive(): boolean {\n return true;\n}\n\n/** The configured service name. */\nexport function getServiceName(): string {\n return process.env.OTEL_SERVICE_NAME || 'tanstack-start';\n}\n\n/** The configured OTLP endpoint, if any. */\nexport function getEndpoint(): string | undefined {\n return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { isInitialized, init } from 'autotel';
|
|
2
|
+
import { InMemorySpanExporter } from 'autotel/exporters';
|
|
3
|
+
import { SimpleSpanProcessor } from 'autotel/processors';
|
|
4
|
+
|
|
5
|
+
// src/instrument.ts
|
|
6
|
+
var DEFAULT_SERVICE = "tanstack-start";
|
|
7
|
+
function resolveDebug(explicit, endpoint) {
|
|
8
|
+
if (explicit !== void 0) return explicit;
|
|
9
|
+
const env = process.env.AUTOTEL_DEBUG;
|
|
10
|
+
if (env === "pretty") return "pretty";
|
|
11
|
+
if (env === "true" || env === "1") return true;
|
|
12
|
+
if (env === "false" || env === "0") return false;
|
|
13
|
+
if (!endpoint && process.env.NODE_ENV === "development") return "pretty";
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
function instrument(options = {}) {
|
|
17
|
+
if (isInitialized()) return;
|
|
18
|
+
const service = options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;
|
|
19
|
+
if (process.env.E2E === "1") {
|
|
20
|
+
const exporter = new InMemorySpanExporter();
|
|
21
|
+
globalThis.__testSpanExporter = exporter;
|
|
22
|
+
init({
|
|
23
|
+
service,
|
|
24
|
+
subscribers: options.subscribers,
|
|
25
|
+
spanProcessors: [
|
|
26
|
+
new SimpleSpanProcessor(exporter),
|
|
27
|
+
...options.spanProcessors ?? []
|
|
28
|
+
]
|
|
29
|
+
});
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
init({
|
|
33
|
+
...options,
|
|
34
|
+
service,
|
|
35
|
+
debug: resolveDebug(options.debug, options.endpoint)
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export { instrument };
|
|
40
|
+
//# sourceMappingURL=chunk-7OXOAS64.js.map
|
|
41
|
+
//# sourceMappingURL=chunk-7OXOAS64.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/instrument.ts"],"names":[],"mappings":";;;;;AAgDA,IAAM,eAAA,GAAkB,gBAAA;AAOxB,SAAS,YAAA,CACP,UACA,QAAA,EACoB;AACpB,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,QAAA;AACnC,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,CAAI,aAAA;AACxB,EAAA,IAAI,GAAA,KAAQ,UAAU,OAAO,QAAA;AAC7B,EAAA,IAAI,GAAA,KAAQ,MAAA,IAAU,GAAA,KAAQ,GAAA,EAAK,OAAO,IAAA;AAC1C,EAAA,IAAI,GAAA,KAAQ,OAAA,IAAW,GAAA,KAAQ,GAAA,EAAK,OAAO,KAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,IAAY,OAAA,CAAQ,GAAA,CAAI,QAAA,KAAa,eAAe,OAAO,QAAA;AAChE,EAAA,OAAO,KAAA;AACT;AAEO,SAAS,UAAA,CAAW,OAAA,GAA6B,EAAC,EAAS;AAGhE,EAAA,IAAI,eAAc,EAAG;AAErB,EAAA,MAAM,OAAA,GACJ,OAAA,CAAQ,OAAA,IAAW,OAAA,CAAQ,IAAI,iBAAA,IAAqB,eAAA;AAEtD,EAAA,IAAI,OAAA,CAAQ,GAAA,CAAI,GAAA,KAAQ,GAAA,EAAK;AAE3B,IAAA,MAAM,QAAA,GAAW,IAAI,oBAAA,EAAqB;AAC1C,IAAC,WAAuC,kBAAA,GAAqB,QAAA;AAC7D,IAAA,IAAA,CAAK;AAAA,MACH,OAAA;AAAA,MACA,aAAa,OAAA,CAAQ,WAAA;AAAA,MACrB,cAAA,EAAgB;AAAA,QACd,IAAI,oBAAoB,QAAQ,CAAA;AAAA,QAChC,GAAI,OAAA,CAAQ,cAAA,IAAkB;AAAC;AACjC,KACD,CAAA;AACD,IAAA;AAAA,EACF;AAEA,EAAA,IAAA,CAAK;AAAA,IACH,GAAG,OAAA;AAAA,IACH,OAAA;AAAA,IACA,KAAA,EAAO,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO,QAAQ,QAAQ;AAAA,GACpD,CAAA;AACH","file":"chunk-7OXOAS64.js","sourcesContent":["/**\n * Configurable tracing setup for TanStack Start.\n *\n * `instrument(options)` is a thin wrapper over autotel's `init` that adds the\n * TanStack defaults so apps don't hand-roll them:\n *\n * - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;\n * - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);\n * - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as\n * `globalThis.__testSpanExporter` (for span assertions) instead of shipping\n * over OTLP;\n * - it's idempotent — a second call is a no-op.\n *\n * Everything else — `endpoint`, `headers`, `subscribers`, `logs`,\n * `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to\n * `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so\n * apps never re-parse them.\n *\n * The zero-config `autotel-tanstack/auto` side-effect module is just\n * `instrument()` with no options.\n *\n * @example\n * ```ts\n * import { instrument } from 'autotel-tanstack';\n * import { PostHogSubscriber } from 'autotel-subscribers';\n *\n * instrument({\n * subscribers: process.env.POSTHOG_KEY\n * ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]\n * : [],\n * logs: true,\n * canonicalLogLines: { enabled: true, rootSpansOnly: true },\n * });\n * ```\n *\n * @module\n */\n\nimport { init, isInitialized, type AutotelConfig } from 'autotel';\nimport { InMemorySpanExporter } from 'autotel/exporters';\nimport { SimpleSpanProcessor } from 'autotel/processors';\n\n// `service` is optional here — instrument() defaults it to OTEL_SERVICE_NAME or\n// 'tanstack-start'. Everything else matches autotel's init config.\nexport type InstrumentOptions = Omit<AutotelConfig, 'service'> & {\n service?: string;\n};\n\nconst DEFAULT_SERVICE = 'tanstack-start';\n\n/**\n * Resolve span-debug output: an explicit option wins; otherwise `AUTOTEL_DEBUG`\n * (`pretty` | `true`/`1` | `false`/`0`); otherwise pretty-print in development\n * when there's no OTLP endpoint, so spans are visible immediately.\n */\nfunction resolveDebug(\n explicit: AutotelConfig['debug'],\n endpoint: string | undefined,\n): boolean | 'pretty' {\n if (explicit !== undefined) return explicit;\n const env = process.env.AUTOTEL_DEBUG;\n if (env === 'pretty') return 'pretty';\n if (env === 'true' || env === '1') return true;\n if (env === 'false' || env === '0') return false;\n if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';\n return false;\n}\n\nexport function instrument(options: InstrumentOptions = {}): void {\n // Idempotent: tolerate the instrumentation module being evaluated more than\n // once (HMR, multiple entry points) without re-initializing.\n if (isInitialized()) return;\n\n const service =\n options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;\n\n if (process.env.E2E === '1') {\n // Capture spans in memory for test assertions; skip OTLP/logs entirely.\n const exporter = new InMemorySpanExporter();\n (globalThis as Record<string, unknown>).__testSpanExporter = exporter;\n init({\n service,\n subscribers: options.subscribers,\n spanProcessors: [\n new SimpleSpanProcessor(exporter),\n ...(options.spanProcessors ?? []),\n ],\n });\n return;\n }\n\n init({\n ...options,\n service,\n debug: resolveDebug(options.debug, options.endpoint),\n });\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { createTracedHeaders, extractContextFromRequest, getActiveContext, injec
|
|
|
7
7
|
export { DebugHeadersConfig, debugHeadersMiddleware } from './debug-headers.js';
|
|
8
8
|
export { TimingStats, createMetricsHandler, metricsCollector, recordTiming } from './metrics.js';
|
|
9
9
|
export { ErrorReport, createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './error-reporting.js';
|
|
10
|
+
export { I as InstrumentOptions, i as instrument } from './instrument-DRR7VL63.js';
|
|
10
11
|
export { flush, init, shutdown, span, trace } from 'autotel';
|
|
11
12
|
import '@opentelemetry/api';
|
|
12
13
|
import '@tanstack/react-router';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { debugHeadersMiddleware } from './chunk-UTPW3QRT.js';
|
|
2
2
|
export { createMetricsHandler, metricsCollector, recordTiming } from './chunk-G526TOMY.js';
|
|
3
3
|
export { createErrorReportingHandler, errorStore, reportError, withErrorReporting } from './chunk-XXBHZR3M.js';
|
|
4
|
+
export { instrument } from './chunk-7OXOAS64.js';
|
|
4
5
|
export { createTracingMiddleware, createTracingServerHandler, functionTracingMiddleware, tracingMiddleware } from './chunk-LRA2UVVS.js';
|
|
5
6
|
export { createTracedServerFnFactory, traceServerFn } from './chunk-ESU66L3L.js';
|
|
6
7
|
export { createTracedRoute, traceBeforeLoad, traceLoader } from './chunk-KPXGFKPU.js';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { AutotelConfig } from 'autotel';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Configurable tracing setup for TanStack Start.
|
|
5
|
+
*
|
|
6
|
+
* `instrument(options)` is a thin wrapper over autotel's `init` that adds the
|
|
7
|
+
* TanStack defaults so apps don't hand-roll them:
|
|
8
|
+
*
|
|
9
|
+
* - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;
|
|
10
|
+
* - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);
|
|
11
|
+
* - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as
|
|
12
|
+
* `globalThis.__testSpanExporter` (for span assertions) instead of shipping
|
|
13
|
+
* over OTLP;
|
|
14
|
+
* - it's idempotent — a second call is a no-op.
|
|
15
|
+
*
|
|
16
|
+
* Everything else — `endpoint`, `headers`, `subscribers`, `logs`,
|
|
17
|
+
* `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to
|
|
18
|
+
* `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so
|
|
19
|
+
* apps never re-parse them.
|
|
20
|
+
*
|
|
21
|
+
* The zero-config `autotel-tanstack/auto` side-effect module is just
|
|
22
|
+
* `instrument()` with no options.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { instrument } from 'autotel-tanstack';
|
|
27
|
+
* import { PostHogSubscriber } from 'autotel-subscribers';
|
|
28
|
+
*
|
|
29
|
+
* instrument({
|
|
30
|
+
* subscribers: process.env.POSTHOG_KEY
|
|
31
|
+
* ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]
|
|
32
|
+
* : [],
|
|
33
|
+
* logs: true,
|
|
34
|
+
* canonicalLogLines: { enabled: true, rootSpansOnly: true },
|
|
35
|
+
* });
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @module
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
type InstrumentOptions = Omit<AutotelConfig, 'service'> & {
|
|
42
|
+
service?: string;
|
|
43
|
+
};
|
|
44
|
+
declare function instrument(options?: InstrumentOptions): void;
|
|
45
|
+
|
|
46
|
+
export { type InstrumentOptions as I, instrument as i };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "autotel-tanstack",
|
|
3
|
-
"version": "1.13.
|
|
3
|
+
"version": "1.13.26",
|
|
4
4
|
"description": "OpenTelemetry instrumentation for TanStack Start - automatic tracing for server functions, middleware, and route loaders",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -120,8 +120,8 @@
|
|
|
120
120
|
"license": "MIT",
|
|
121
121
|
"dependencies": {
|
|
122
122
|
"@opentelemetry/api": "^1.9.1",
|
|
123
|
-
"autotel": "3.4.
|
|
124
|
-
"autotel-adapters": "0.3.
|
|
123
|
+
"autotel": "3.4.2",
|
|
124
|
+
"autotel-adapters": "0.3.4",
|
|
125
125
|
"autotel-edge": "3.16.12"
|
|
126
126
|
},
|
|
127
127
|
"peerDependencies": {
|
package/src/auto.test.ts
CHANGED
|
@@ -7,6 +7,8 @@ const mockGetFinishedSpans = vi.fn(() => []);
|
|
|
7
7
|
|
|
8
8
|
vi.mock('autotel', () => ({
|
|
9
9
|
init: mockInit,
|
|
10
|
+
// instrument() guards on this; false so every test proceeds to init().
|
|
11
|
+
isInitialized: vi.fn(() => false),
|
|
10
12
|
}));
|
|
11
13
|
|
|
12
14
|
const mockExporterInstance = {
|
|
@@ -85,15 +87,20 @@ describe('auto.ts E2E mode', () => {
|
|
|
85
87
|
expect(call.spanProcessors).toHaveLength(2);
|
|
86
88
|
});
|
|
87
89
|
|
|
88
|
-
it('
|
|
90
|
+
it('initializes in production mode without injecting an in-memory processor', async () => {
|
|
91
|
+
// The OTLP endpoint/headers are resolved by autotel core from env, so the
|
|
92
|
+
// zero-config path no longer passes them explicitly — it just inits.
|
|
89
93
|
delete process.env.E2E;
|
|
90
94
|
process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4318';
|
|
91
95
|
await import('./auto');
|
|
92
|
-
expect(mockInit).
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
expect(mockInit).toHaveBeenCalledOnce();
|
|
97
|
+
const call = mockInit.mock.calls[0][0] as {
|
|
98
|
+
spanProcessors?: unknown[];
|
|
99
|
+
service?: string;
|
|
100
|
+
};
|
|
101
|
+
expect(call.spanProcessors).toBeUndefined();
|
|
102
|
+
expect(call.service).toBe('tanstack-start');
|
|
103
|
+
expect(MockInMemorySpanExporter).not.toHaveBeenCalled();
|
|
97
104
|
});
|
|
98
105
|
|
|
99
106
|
it('uses OTEL_SERVICE_NAME env var', async () => {
|
package/src/auto.ts
CHANGED
|
@@ -1,119 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Zero-config auto-instrumentation for TanStack Start
|
|
2
|
+
* Zero-config auto-instrumentation for TanStack Start.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Importing this module configures OpenTelemetry tracing from environment
|
|
5
|
+
* variables — it is simply `instrument()` with no options. For subscribers,
|
|
6
|
+
* structured logs, canonical log lines, or an explicit endpoint, call
|
|
7
|
+
* `instrument(options)` from `autotel-tanstack` directly (see ./instrument).
|
|
6
8
|
*
|
|
7
|
-
* Environment Variables:
|
|
9
|
+
* Environment Variables (resolved by autotel core):
|
|
8
10
|
* - OTEL_SERVICE_NAME: Service name (default: 'tanstack-start')
|
|
9
11
|
* - OTEL_EXPORTER_OTLP_ENDPOINT: OTLP collector URL
|
|
10
|
-
* - OTEL_EXPORTER_OTLP_HEADERS:
|
|
11
|
-
* - AUTOTEL_DEBUG:
|
|
12
|
+
* - OTEL_EXPORTER_OTLP_HEADERS: Auth headers (key=value,key=value)
|
|
13
|
+
* - AUTOTEL_DEBUG: 'true' | 'pretty' to log spans to the server console
|
|
12
14
|
*
|
|
13
15
|
* @example
|
|
14
16
|
* ```typescript
|
|
15
17
|
* // app/start.ts
|
|
16
18
|
* import 'autotel-tanstack/auto';
|
|
17
19
|
* import { createStart } from '@tanstack/react-start';
|
|
18
|
-
*
|
|
19
|
-
* // Tracing is automatically configured!
|
|
20
20
|
* export const startInstance = createStart(() => ({}));
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import {
|
|
27
|
-
import { InMemorySpanExporter } from 'autotel/exporters';
|
|
28
|
-
import { SimpleSpanProcessor } from 'autotel/processors';
|
|
29
|
-
|
|
30
|
-
// Parse service name
|
|
31
|
-
const service = process.env.OTEL_SERVICE_NAME || 'tanstack-start';
|
|
26
|
+
import { instrument } from './instrument';
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
28
|
+
instrument();
|
|
35
29
|
|
|
36
|
-
//
|
|
37
|
-
let headers: Record<string, string> | undefined;
|
|
38
|
-
if (process.env.OTEL_EXPORTER_OTLP_HEADERS) {
|
|
39
|
-
headers = {};
|
|
40
|
-
const pairs = process.env.OTEL_EXPORTER_OTLP_HEADERS.split(',');
|
|
41
|
-
for (const pair of pairs) {
|
|
42
|
-
const [key, value] = pair.split('=');
|
|
43
|
-
if (key && value) {
|
|
44
|
-
headers[key.trim()] = value.trim();
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Debug: span output to server console. AUTOTEL_DEBUG=pretty | true, or default
|
|
50
|
-
// to pretty in dev when no OTLP endpoint is set so you see spans immediately.
|
|
51
|
-
function resolveDebug(): boolean | 'pretty' {
|
|
52
|
-
const env = process.env.AUTOTEL_DEBUG;
|
|
53
|
-
if (env === 'pretty') return 'pretty';
|
|
54
|
-
if (env === 'true' || env === '1') return true;
|
|
55
|
-
if (env === 'false' || env === '0') return false;
|
|
56
|
-
if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// E2E mode: use InMemorySpanExporter so tests can capture and assert on spans.
|
|
61
|
-
// When E2E=1, skip the normal OTLP path and use in-memory storage instead.
|
|
62
|
-
// Note: combined E2E + OTLP (two processors) is handled at integration level
|
|
63
|
-
// because constructing an OTLP processor requires deps not available here.
|
|
64
|
-
if (process.env.E2E === '1') {
|
|
65
|
-
const e2eExporter = new InMemorySpanExporter();
|
|
66
|
-
const e2eProcessor = new SimpleSpanProcessor(e2eExporter);
|
|
67
|
-
(globalThis as Record<string, unknown>).__testSpanExporter = e2eExporter;
|
|
68
|
-
|
|
69
|
-
init({
|
|
70
|
-
service,
|
|
71
|
-
spanProcessors: [e2eProcessor],
|
|
72
|
-
});
|
|
73
|
-
} else {
|
|
74
|
-
// Initialize autotel (production path — unchanged)
|
|
75
|
-
init({
|
|
76
|
-
service,
|
|
77
|
-
endpoint,
|
|
78
|
-
headers,
|
|
79
|
-
debug: resolveDebug(),
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Log initialization (only in development)
|
|
30
|
+
// Surface what happened, in development only.
|
|
84
31
|
if (process.env.NODE_ENV === 'development' || process.env.AUTOTEL_DEBUG) {
|
|
85
|
-
console.log('[autotel-tanstack] Auto-initialized
|
|
86
|
-
service,
|
|
32
|
+
console.log('[autotel-tanstack] Auto-initialized', {
|
|
33
|
+
service: process.env.OTEL_SERVICE_NAME || 'tanstack-start',
|
|
87
34
|
endpoint:
|
|
88
35
|
process.env.E2E === '1'
|
|
89
36
|
? '(E2E: in-memory)'
|
|
90
|
-
:
|
|
91
|
-
hasHeaders: !!headers,
|
|
37
|
+
: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || '(not configured)',
|
|
92
38
|
});
|
|
93
39
|
}
|
|
94
40
|
|
|
95
|
-
// Re-export middleware for convenience
|
|
41
|
+
// Re-export the configurable form + middleware/helpers for convenience.
|
|
42
|
+
export { instrument } from './instrument';
|
|
96
43
|
export { tracingMiddleware, functionTracingMiddleware } from './middleware';
|
|
97
44
|
export { traceServerFn } from './server-functions';
|
|
98
45
|
export { traceLoader, traceBeforeLoad } from './loaders';
|
|
99
46
|
|
|
100
|
-
/**
|
|
101
|
-
* Check if auto-instrumentation is active
|
|
102
|
-
*/
|
|
47
|
+
/** Check if auto-instrumentation is active. */
|
|
103
48
|
export function isAutoInstrumentationActive(): boolean {
|
|
104
49
|
return true;
|
|
105
50
|
}
|
|
106
51
|
|
|
107
|
-
/**
|
|
108
|
-
* Get the configured service name
|
|
109
|
-
*/
|
|
52
|
+
/** The configured service name. */
|
|
110
53
|
export function getServiceName(): string {
|
|
111
|
-
return
|
|
54
|
+
return process.env.OTEL_SERVICE_NAME || 'tanstack-start';
|
|
112
55
|
}
|
|
113
56
|
|
|
114
|
-
/**
|
|
115
|
-
* Get the configured endpoint
|
|
116
|
-
*/
|
|
57
|
+
/** The configured OTLP endpoint, if any. */
|
|
117
58
|
export function getEndpoint(): string | undefined {
|
|
118
|
-
return
|
|
59
|
+
return process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
|
|
119
60
|
}
|
package/src/index.ts
CHANGED
|
@@ -84,6 +84,10 @@ export {
|
|
|
84
84
|
type ErrorReport,
|
|
85
85
|
} from './error-reporting';
|
|
86
86
|
|
|
87
|
+
// Configurable TanStack Start tracing setup (the configurable form of the
|
|
88
|
+
// zero-config `autotel-tanstack/auto` import).
|
|
89
|
+
export { instrument, type InstrumentOptions } from './instrument';
|
|
90
|
+
|
|
87
91
|
// Re-export autotel core utilities for convenience
|
|
88
92
|
// Note: These should only be used on the server side
|
|
89
93
|
// They use Node.js APIs (AsyncLocalStorage) that don't exist in the browser
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Hoisted so the values exist when the (also-hoisted) vi.mock factories run,
|
|
4
|
+
// since instrument is imported statically below.
|
|
5
|
+
const {
|
|
6
|
+
mockInit,
|
|
7
|
+
mockIsInitialized,
|
|
8
|
+
mockExporter,
|
|
9
|
+
MockInMemorySpanExporter,
|
|
10
|
+
MockSimpleSpanProcessor,
|
|
11
|
+
} = vi.hoisted(() => {
|
|
12
|
+
const exporter = { reset: vi.fn(), getFinishedSpans: vi.fn(() => []) };
|
|
13
|
+
return {
|
|
14
|
+
mockInit: vi.fn(),
|
|
15
|
+
mockIsInitialized: vi.fn(() => false),
|
|
16
|
+
mockExporter: exporter,
|
|
17
|
+
MockInMemorySpanExporter: vi.fn(function () {
|
|
18
|
+
return exporter;
|
|
19
|
+
}),
|
|
20
|
+
MockSimpleSpanProcessor: vi.fn(function (exp: unknown) {
|
|
21
|
+
return { exporter: exp };
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
vi.mock('autotel', () => ({
|
|
27
|
+
init: mockInit,
|
|
28
|
+
isInitialized: mockIsInitialized,
|
|
29
|
+
}));
|
|
30
|
+
vi.mock('autotel/exporters', () => ({
|
|
31
|
+
InMemorySpanExporter: MockInMemorySpanExporter,
|
|
32
|
+
}));
|
|
33
|
+
vi.mock('autotel/processors', () => ({
|
|
34
|
+
SimpleSpanProcessor: MockSimpleSpanProcessor,
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
import { instrument } from './instrument';
|
|
38
|
+
|
|
39
|
+
type InitCall = {
|
|
40
|
+
service?: string;
|
|
41
|
+
endpoint?: string;
|
|
42
|
+
debug?: boolean | 'pretty';
|
|
43
|
+
logs?: unknown;
|
|
44
|
+
subscribers?: unknown;
|
|
45
|
+
spanProcessors?: unknown[];
|
|
46
|
+
};
|
|
47
|
+
const lastInit = () => mockInit.mock.calls[0][0] as InitCall;
|
|
48
|
+
|
|
49
|
+
describe('instrument()', () => {
|
|
50
|
+
const originalEnv = { ...process.env };
|
|
51
|
+
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
mockInit.mockReset();
|
|
54
|
+
mockIsInitialized.mockReturnValue(false);
|
|
55
|
+
MockInMemorySpanExporter.mockClear();
|
|
56
|
+
MockSimpleSpanProcessor.mockClear();
|
|
57
|
+
delete (globalThis as Record<string, unknown>).__testSpanExporter;
|
|
58
|
+
delete process.env.E2E;
|
|
59
|
+
delete process.env.AUTOTEL_DEBUG;
|
|
60
|
+
delete process.env.OTEL_SERVICE_NAME;
|
|
61
|
+
delete process.env.NODE_ENV;
|
|
62
|
+
});
|
|
63
|
+
afterEach(() => {
|
|
64
|
+
process.env = { ...originalEnv };
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('is idempotent — does nothing when already initialized', () => {
|
|
68
|
+
mockIsInitialized.mockReturnValue(true);
|
|
69
|
+
instrument({ service: 'x' });
|
|
70
|
+
expect(mockInit).not.toHaveBeenCalled();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('defaults the service name to tanstack-start', () => {
|
|
74
|
+
instrument();
|
|
75
|
+
expect(lastInit().service).toBe('tanstack-start');
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('prefers an explicit service over OTEL_SERVICE_NAME', () => {
|
|
79
|
+
process.env.OTEL_SERVICE_NAME = 'from-env';
|
|
80
|
+
instrument({ service: 'explicit' });
|
|
81
|
+
expect(lastInit().service).toBe('explicit');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('falls back to OTEL_SERVICE_NAME', () => {
|
|
85
|
+
process.env.OTEL_SERVICE_NAME = 'from-env';
|
|
86
|
+
instrument();
|
|
87
|
+
expect(lastInit().service).toBe('from-env');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('passes options straight through to init in normal mode', () => {
|
|
91
|
+
const subscribers = [{ name: 'sub' } as never];
|
|
92
|
+
instrument({
|
|
93
|
+
endpoint: 'http://collector:4318',
|
|
94
|
+
subscribers,
|
|
95
|
+
logs: true,
|
|
96
|
+
});
|
|
97
|
+
const call = lastInit();
|
|
98
|
+
expect(call.endpoint).toBe('http://collector:4318');
|
|
99
|
+
expect(call.subscribers).toBe(subscribers);
|
|
100
|
+
expect(call.logs).toBe(true);
|
|
101
|
+
expect(call.spanProcessors).toBeUndefined();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('resolves debug from AUTOTEL_DEBUG', () => {
|
|
105
|
+
process.env.AUTOTEL_DEBUG = 'pretty';
|
|
106
|
+
instrument({ endpoint: 'http://c:4318' });
|
|
107
|
+
expect(lastInit().debug).toBe('pretty');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('pretty-prints in dev when no endpoint is set', () => {
|
|
111
|
+
process.env.NODE_ENV = 'development';
|
|
112
|
+
instrument();
|
|
113
|
+
expect(lastInit().debug).toBe('pretty');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('captures spans in memory under E2E=1 and skips OTLP + logs', () => {
|
|
117
|
+
process.env.E2E = '1';
|
|
118
|
+
const subscribers = [{ name: 'sub' } as never];
|
|
119
|
+
instrument({ endpoint: 'http://c:4318', subscribers, logs: true });
|
|
120
|
+
|
|
121
|
+
expect(MockInMemorySpanExporter).toHaveBeenCalledOnce();
|
|
122
|
+
const call = lastInit();
|
|
123
|
+
expect(call.spanProcessors).toHaveLength(1);
|
|
124
|
+
expect(call.endpoint).toBeUndefined(); // no OTLP shipping in tests
|
|
125
|
+
expect(call.logs).toBeUndefined(); // logs off in E2E
|
|
126
|
+
expect(call.subscribers).toBe(subscribers); // subscribers still flow
|
|
127
|
+
expect((globalThis as Record<string, unknown>).__testSpanExporter).toBe(
|
|
128
|
+
mockExporter,
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configurable tracing setup for TanStack Start.
|
|
3
|
+
*
|
|
4
|
+
* `instrument(options)` is a thin wrapper over autotel's `init` that adds the
|
|
5
|
+
* TanStack defaults so apps don't hand-roll them:
|
|
6
|
+
*
|
|
7
|
+
* - service name defaults to `OTEL_SERVICE_NAME` or `'tanstack-start'`;
|
|
8
|
+
* - `debug` resolves from `AUTOTEL_DEBUG` (`pretty` in dev when no endpoint set);
|
|
9
|
+
* - when `E2E=1`, spans are captured by an `InMemorySpanExporter` exposed as
|
|
10
|
+
* `globalThis.__testSpanExporter` (for span assertions) instead of shipping
|
|
11
|
+
* over OTLP;
|
|
12
|
+
* - it's idempotent — a second call is a no-op.
|
|
13
|
+
*
|
|
14
|
+
* Everything else — `endpoint`, `headers`, `subscribers`, `logs`,
|
|
15
|
+
* `canonicalLogLines`, extra `spanProcessors`, … — passes straight through to
|
|
16
|
+
* `init`, and the standard `OTEL_*` env vars are resolved by autotel core, so
|
|
17
|
+
* apps never re-parse them.
|
|
18
|
+
*
|
|
19
|
+
* The zero-config `autotel-tanstack/auto` side-effect module is just
|
|
20
|
+
* `instrument()` with no options.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { instrument } from 'autotel-tanstack';
|
|
25
|
+
* import { PostHogSubscriber } from 'autotel-subscribers';
|
|
26
|
+
*
|
|
27
|
+
* instrument({
|
|
28
|
+
* subscribers: process.env.POSTHOG_KEY
|
|
29
|
+
* ? [new PostHogSubscriber({ apiKey: process.env.POSTHOG_KEY })]
|
|
30
|
+
* : [],
|
|
31
|
+
* logs: true,
|
|
32
|
+
* canonicalLogLines: { enabled: true, rootSpansOnly: true },
|
|
33
|
+
* });
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @module
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { init, isInitialized, type AutotelConfig } from 'autotel';
|
|
40
|
+
import { InMemorySpanExporter } from 'autotel/exporters';
|
|
41
|
+
import { SimpleSpanProcessor } from 'autotel/processors';
|
|
42
|
+
|
|
43
|
+
// `service` is optional here — instrument() defaults it to OTEL_SERVICE_NAME or
|
|
44
|
+
// 'tanstack-start'. Everything else matches autotel's init config.
|
|
45
|
+
export type InstrumentOptions = Omit<AutotelConfig, 'service'> & {
|
|
46
|
+
service?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const DEFAULT_SERVICE = 'tanstack-start';
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Resolve span-debug output: an explicit option wins; otherwise `AUTOTEL_DEBUG`
|
|
53
|
+
* (`pretty` | `true`/`1` | `false`/`0`); otherwise pretty-print in development
|
|
54
|
+
* when there's no OTLP endpoint, so spans are visible immediately.
|
|
55
|
+
*/
|
|
56
|
+
function resolveDebug(
|
|
57
|
+
explicit: AutotelConfig['debug'],
|
|
58
|
+
endpoint: string | undefined,
|
|
59
|
+
): boolean | 'pretty' {
|
|
60
|
+
if (explicit !== undefined) return explicit;
|
|
61
|
+
const env = process.env.AUTOTEL_DEBUG;
|
|
62
|
+
if (env === 'pretty') return 'pretty';
|
|
63
|
+
if (env === 'true' || env === '1') return true;
|
|
64
|
+
if (env === 'false' || env === '0') return false;
|
|
65
|
+
if (!endpoint && process.env.NODE_ENV === 'development') return 'pretty';
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function instrument(options: InstrumentOptions = {}): void {
|
|
70
|
+
// Idempotent: tolerate the instrumentation module being evaluated more than
|
|
71
|
+
// once (HMR, multiple entry points) without re-initializing.
|
|
72
|
+
if (isInitialized()) return;
|
|
73
|
+
|
|
74
|
+
const service =
|
|
75
|
+
options.service ?? process.env.OTEL_SERVICE_NAME ?? DEFAULT_SERVICE;
|
|
76
|
+
|
|
77
|
+
if (process.env.E2E === '1') {
|
|
78
|
+
// Capture spans in memory for test assertions; skip OTLP/logs entirely.
|
|
79
|
+
const exporter = new InMemorySpanExporter();
|
|
80
|
+
(globalThis as Record<string, unknown>).__testSpanExporter = exporter;
|
|
81
|
+
init({
|
|
82
|
+
service,
|
|
83
|
+
subscribers: options.subscribers,
|
|
84
|
+
spanProcessors: [
|
|
85
|
+
new SimpleSpanProcessor(exporter),
|
|
86
|
+
...(options.spanProcessors ?? []),
|
|
87
|
+
],
|
|
88
|
+
});
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
init({
|
|
93
|
+
...options,
|
|
94
|
+
service,
|
|
95
|
+
debug: resolveDebug(options.debug, options.endpoint),
|
|
96
|
+
});
|
|
97
|
+
}
|