apitally 1.0.0-beta.5 → 1.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +11 -7
  2. package/dist/_virtual/_rolldown/runtime.cjs +23 -0
  3. package/dist/activation.cjs +30 -0
  4. package/dist/activation.cjs.map +1 -1
  5. package/dist/activation.d.cts +1 -0
  6. package/dist/activation.d.ts +1 -0
  7. package/dist/activation.js +28 -1
  8. package/dist/activation.js.map +1 -1
  9. package/dist/adonisjs/middleware.cjs +1 -1
  10. package/dist/adonisjs/middleware.cjs.map +1 -1
  11. package/dist/adonisjs/middleware.js +1 -1
  12. package/dist/adonisjs/middleware.js.map +1 -1
  13. package/dist/elysia/index.cjs.map +1 -1
  14. package/dist/elysia/index.js.map +1 -1
  15. package/dist/elysia/middleware.cjs +8 -10
  16. package/dist/elysia/middleware.cjs.map +1 -1
  17. package/dist/elysia/middleware.js +8 -10
  18. package/dist/elysia/middleware.js.map +1 -1
  19. package/dist/elysia/routes.cjs +2 -1
  20. package/dist/elysia/routes.cjs.map +1 -1
  21. package/dist/elysia/routes.js +2 -1
  22. package/dist/elysia/routes.js.map +1 -1
  23. package/dist/express/index.cjs.map +1 -1
  24. package/dist/express/index.js.map +1 -1
  25. package/dist/express/install.cjs +1 -0
  26. package/dist/express/install.cjs.map +1 -1
  27. package/dist/express/install.js +2 -1
  28. package/dist/express/install.js.map +1 -1
  29. package/dist/express/middleware.cjs +1 -1
  30. package/dist/express/middleware.cjs.map +1 -1
  31. package/dist/express/middleware.js +1 -1
  32. package/dist/express/middleware.js.map +1 -1
  33. package/dist/fastify/middleware.cjs +1 -1
  34. package/dist/fastify/middleware.cjs.map +1 -1
  35. package/dist/fastify/middleware.js +1 -1
  36. package/dist/fastify/middleware.js.map +1 -1
  37. package/dist/h3/index.cjs +1 -0
  38. package/dist/h3/index.cjs.map +1 -1
  39. package/dist/h3/index.js +2 -1
  40. package/dist/h3/index.js.map +1 -1
  41. package/dist/h3/middleware.cjs +1 -1
  42. package/dist/h3/middleware.cjs.map +1 -1
  43. package/dist/h3/middleware.js +1 -1
  44. package/dist/h3/middleware.js.map +1 -1
  45. package/dist/hapi/middleware.cjs +1 -1
  46. package/dist/hapi/middleware.cjs.map +1 -1
  47. package/dist/hapi/middleware.js +1 -1
  48. package/dist/hapi/middleware.js.map +1 -1
  49. package/dist/hono/index.cjs.map +1 -1
  50. package/dist/hono/index.js.map +1 -1
  51. package/dist/hono/middleware.cjs +2 -1
  52. package/dist/hono/middleware.cjs.map +1 -1
  53. package/dist/hono/middleware.js +3 -2
  54. package/dist/hono/middleware.js.map +1 -1
  55. package/dist/koa/index.cjs +1 -0
  56. package/dist/koa/index.cjs.map +1 -1
  57. package/dist/koa/index.js +2 -1
  58. package/dist/koa/index.js.map +1 -1
  59. package/dist/koa/middleware.cjs +1 -1
  60. package/dist/koa/middleware.cjs.map +1 -1
  61. package/dist/koa/middleware.js +1 -1
  62. package/dist/koa/middleware.js.map +1 -1
  63. package/dist/requestObservation.cjs +2 -1
  64. package/dist/requestObservation.cjs.map +1 -1
  65. package/dist/requestObservation.js +2 -1
  66. package/dist/requestObservation.js.map +1 -1
  67. package/dist/tracing.cjs +2 -1
  68. package/dist/tracing.cjs.map +1 -1
  69. package/dist/tracing.js +2 -1
  70. package/dist/tracing.js.map +1 -1
  71. package/package.json +12 -12
package/README.md CHANGED
@@ -46,7 +46,7 @@ Learn more about Apitally on our 🌎 [website](https://apitally.io) or check ou
46
46
 
47
47
  ## Supported frameworks
48
48
 
49
- The SDK supports **Node.js** `>= 20.6` and **Bun** `>= 1.2.0`.
49
+ The SDK supports **Node.js** `^20.16` or `>= 22.3` and **Bun** `>= 1.2.0`.
50
50
 
51
51
  | Framework | Supported versions | Setup guide |
52
52
  | --- | --- | --- |
@@ -74,8 +74,6 @@ Install the SDK in your project:
74
74
  npm install apitally
75
75
  ```
76
76
 
77
- See the [SDK reference](https://docs.apitally.io/sdk-reference/javascript/v1/configuration) for all available configuration options, including how to mask sensitive data, capture request and response payloads, and more.
78
-
79
77
  ### AdonisJS
80
78
 
81
79
  Run the Ace `add` command from your application directory:
@@ -306,6 +304,8 @@ See our [documentation on masking](https://docs.apitally.io/sdk-reference/javasc
306
304
 
307
305
  The following functions add context to the current request. Call them while handling a request, for example in a route handler, middleware, or authentication code.
308
306
 
307
+ ### Consumers
308
+
309
309
  To associate the request with the API consumer making it, call `setConsumer`. Only `identifier` is required. You can also pass it as a string, for example `setConsumer(user.identifier)`.
310
310
 
311
311
  ```javascript
@@ -319,7 +319,9 @@ setConsumer({
319
319
  });
320
320
  ```
321
321
 
322
- To attach custom data to the request's trace, call `setRequestAttribute`. Sampling and masking callbacks can also read these attributes.
322
+ ### Custom attributes
323
+
324
+ To attach custom data to the request's trace, call `setRequestAttribute`. The `sampleOnResponse`, `maskRequestBody`, and `maskResponseBody` callbacks can also read these attributes.
323
325
 
324
326
  ```javascript
325
327
  import { setRequestAttribute } from "apitally";
@@ -327,6 +329,10 @@ import { setRequestAttribute } from "apitally";
327
329
  setRequestAttribute("tenant.id", tenantId);
328
330
  ```
329
331
 
332
+ See our [documentation on attributes](https://docs.apitally.io/sdk-reference/javascript/v1/attributes#set-custom-attributes) for details.
333
+
334
+ ### Handled exceptions
335
+
330
336
  To capture an exception that your code handles itself, call `captureException`. Unhandled exceptions are captured automatically.
331
337
 
332
338
  ```javascript
@@ -339,8 +345,6 @@ try {
339
345
  }
340
346
  ```
341
347
 
342
- See our documentation on [custom attributes](https://docs.apitally.io/sdk-reference/javascript/v1/attributes#set-custom-attributes) and [handled exceptions](https://docs.apitally.io/sdk-reference/javascript/v1/tracing#capture-handled-exceptions) for details.
343
-
344
348
  ## Existing OpenTelemetry setup
345
349
 
346
350
  If your app already registers its own tracer provider, for example with `NodeSDK`, add `ApitallySpanProcessor` to its span processors. Apitally then uses your tracer provider instead of registering its own, and keeps your existing exporters.
@@ -355,7 +359,7 @@ const sdk = new NodeSDK({
355
359
  });
356
360
  ```
357
361
 
358
- If you use versions 8 to 10 of the Sentry SDK, which register their own tracer provider, add `ApitallySpanProcessor` to the `openTelemetrySpanProcessors` option in `Sentry.init()` and enable Sentry tracing.
362
+ If you use version 10.x of the Sentry SDK, which registers its own tracer provider, add `ApitallySpanProcessor` to the `openTelemetrySpanProcessors` option in `Sentry.init()` and enable Sentry tracing.
359
363
 
360
364
  Your tracer provider's sampler also applies to Apitally. Requests it drops have no request logs or traces in Apitally, but still count in metrics.
361
365
 
@@ -0,0 +1,23 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ exports.__toESM = __toESM;
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
2
3
  const require_logger = require("./logger.cjs");
3
4
  const require_config = require("./config.cjs");
4
5
  const require_packageVersion = require("./packageVersion.cjs");
@@ -16,6 +17,8 @@ const require_spanExporter = require("./spanExporter.cjs");
16
17
  const require_spool = require("./spool.cjs");
17
18
  const require_startup = require("./startup.cjs");
18
19
  const require_validationErrors = require("./validationErrors.cjs");
20
+ let node_diagnostics_channel = require("node:diagnostics_channel");
21
+ node_diagnostics_channel = require_runtime.__toESM(node_diagnostics_channel, 1);
19
22
  let node_worker_threads = require("node:worker_threads");
20
23
  let _opentelemetry_api = require("@opentelemetry/api");
21
24
  let _opentelemetry_instrumentation_undici = require("@opentelemetry/instrumentation-undici");
@@ -28,6 +31,7 @@ const BATCH_MAX_QUEUE_SIZE = 2048;
28
31
  const BATCH_MAX_EXPORT_BATCH_SIZE = 512;
29
32
  const BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;
30
33
  const SIGNAL_FLUSH_TIMEOUT_MILLIS = 5e3;
34
+ const NET_SERVER_LISTEN_CHANNEL = "tracing:net.server.listen:asyncEnd";
31
35
  const ACTIVATION_STATE_KEY = Symbol.for("apitally.activation");
32
36
  function configure(options = {}) {
33
37
  const config = require_config.setConfig(options);
@@ -54,6 +58,25 @@ function activate() {
54
58
  require_logger.logError(`Apitally activation failed: ${String(error)}`);
55
59
  }
56
60
  }
61
+ function activateWhenHttpServerListens() {
62
+ const activationState = getActivationState();
63
+ if (activationState.httpServerListenHooks) return;
64
+ const onNetServerListen = (message) => {
65
+ if (message.server.listenerCount("request") > 0) activate();
66
+ };
67
+ node_diagnostics_channel.default.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);
68
+ const bun = globalThis.Bun;
69
+ const originalBunServe = bun?.serve;
70
+ if (bun && originalBunServe) bun.serve = function(...args) {
71
+ const server = originalBunServe.apply(this, args);
72
+ activate();
73
+ return server;
74
+ };
75
+ activationState.httpServerListenHooks = {
76
+ onNetServerListen,
77
+ originalBunServe
78
+ };
79
+ }
57
80
  function isActivated() {
58
81
  return getActivationState().handles !== void 0;
59
82
  }
@@ -94,6 +117,12 @@ async function resetActivation() {
94
117
  require_serverErrors.resetServerErrors();
95
118
  if (!activationState) return;
96
119
  removeLifecycleHooks(activationState);
120
+ const listenHooks = activationState.httpServerListenHooks;
121
+ if (listenHooks) {
122
+ node_diagnostics_channel.default.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);
123
+ const bun = globalThis.Bun;
124
+ if (bun && listenHooks.originalBunServe) bun.serve = listenHooks.originalBunServe;
125
+ }
97
126
  const handles = activationState.handles;
98
127
  if (!handles) return;
99
128
  handles.undiciInstrumentation?.disable();
@@ -300,6 +329,7 @@ function installBeforeExitHook(activationState) {
300
329
  }
301
330
  //#endregion
302
331
  exports.activate = activate;
332
+ exports.activateWhenHttpServerListens = activateWhenHttpServerListens;
303
333
  exports.activationFactories = activationFactories;
304
334
  exports.configure = configure;
305
335
  exports.flushTelemetry = flushTelemetry;
@@ -1 +1 @@
1
- {"version":3,"file":"activation.cjs","names":["setConfig","Spool","ExportWorker","VALIDATION_ERROR_EVENT_NAME","drainValidationErrors","SERVER_ERROR_EVENT_NAME","drainServerErrors","ROOT_CONTEXT","getDistroVersion","getConfig","isApitallySpanProcessorDeclared","resolveEnvAndCreateResource","ApitallySpanExporter","Redaction","BatchSpanProcessor","SpanPipeline","setupTracerProvider","BatchLogRecordProcessor","ApitallyLogRecordExporter","ApitallyLogRecordProcessor","createLoggerProvider","MetricsPipeline","UndiciInstrumentation","isMainThread"],"sources":["../src/activation.ts"],"sourcesContent":["import { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"activation.cjs","names":["setConfig","Spool","ExportWorker","VALIDATION_ERROR_EVENT_NAME","drainValidationErrors","SERVER_ERROR_EVENT_NAME","drainServerErrors","ROOT_CONTEXT","getDistroVersion","getConfig","isApitallySpanProcessorDeclared","resolveEnvAndCreateResource","ApitallySpanExporter","Redaction","BatchSpanProcessor","SpanPipeline","setupTracerProvider","BatchLogRecordProcessor","ApitallyLogRecordExporter","ApitallyLogRecordProcessor","createLoggerProvider","MetricsPipeline","UndiciInstrumentation","isMainThread"],"sources":["../src/activation.ts"],"sourcesContent":["import diagnosticsChannel from \"node:diagnostics_channel\";\nimport type { Server } from \"node:net\";\nimport { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\n// Published by Node >= 20.16 and >= 22.3 once a net.Server is listening.\nconst NET_SERVER_LISTEN_CHANNEL = \"tracing:net.server.listen:asyncEnd\";\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype BunServe = (this: unknown, ...args: unknown[]) => unknown;\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n httpServerListenHooks?: HttpServerListenHooks;\n}\n\ninterface HttpServerListenHooks {\n onNetServerListen: (message: unknown) => void;\n originalBunServe?: BunServe;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\n// For integrations without a framework startup hook. A server that started\n// listening before this call is missed and activates on its first request.\nexport function activateWhenHttpServerListens(): void {\n const activationState = getActivationState();\n if (activationState.httpServerListenHooks) {\n return;\n }\n // HTTP servers carry the app as a request listener; a cluster primary's\n // internal round-robin server has none, so only workers activate.\n const onNetServerListen = (message: unknown) => {\n if ((message as { server: Server }).server.listenerCount(\"request\") > 0) {\n activate();\n }\n };\n diagnosticsChannel.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);\n // Bun publishes no net listen channel, but every Bun HTTP server starts through Bun.serve.\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n const originalBunServe = bun?.serve;\n if (bun && originalBunServe) {\n bun.serve = function (this: unknown, ...args: unknown[]) {\n const server = originalBunServe.apply(this, args);\n activate();\n return server;\n };\n }\n activationState.httpServerListenHooks = { onNetServerListen, originalBunServe };\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const listenHooks = activationState.httpServerListenHooks;\n if (listenHooks) {\n diagnosticsChannel.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n if (bun && listenHooks.originalBunServe) {\n bun.serve = listenHooks.originalBunServe;\n }\n }\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
@@ -21,6 +21,7 @@ interface ActivationHandles {
21
21
  export declare function configure(options?: ApitallyOptions): ApitallyConfig;
22
22
  export declare function registerStartupEventInfo(info: StartupEventInfo): void;
23
23
  export declare function activate(): void;
24
+ export declare function activateWhenHttpServerListens(): void;
24
25
  export declare function isActivated(): boolean;
25
26
  export declare function getActivationHandles(): ActivationHandles | undefined;
26
27
  export declare function flushTelemetry(): Promise<void>;
@@ -21,6 +21,7 @@ interface ActivationHandles {
21
21
  export declare function configure(options?: ApitallyOptions): ApitallyConfig;
22
22
  export declare function registerStartupEventInfo(info: StartupEventInfo): void;
23
23
  export declare function activate(): void;
24
+ export declare function activateWhenHttpServerListens(): void;
24
25
  export declare function isActivated(): boolean;
25
26
  export declare function getActivationHandles(): ActivationHandles | undefined;
26
27
  export declare function flushTelemetry(): Promise<void>;
@@ -15,6 +15,7 @@ import { ApitallySpanExporter } from "./spanExporter.js";
15
15
  import { Spool } from "./spool.js";
16
16
  import { emitStartupEvent } from "./startup.js";
17
17
  import { VALIDATION_ERROR_EVENT_NAME, drainValidationErrors, resetValidationErrors } from "./validationErrors.js";
18
+ import diagnosticsChannel from "node:diagnostics_channel";
18
19
  import { isMainThread } from "node:worker_threads";
19
20
  import { ROOT_CONTEXT } from "@opentelemetry/api";
20
21
  import { UndiciInstrumentation } from "@opentelemetry/instrumentation-undici";
@@ -27,6 +28,7 @@ const BATCH_MAX_QUEUE_SIZE = 2048;
27
28
  const BATCH_MAX_EXPORT_BATCH_SIZE = 512;
28
29
  const BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;
29
30
  const SIGNAL_FLUSH_TIMEOUT_MILLIS = 5e3;
31
+ const NET_SERVER_LISTEN_CHANNEL = "tracing:net.server.listen:asyncEnd";
30
32
  const ACTIVATION_STATE_KEY = Symbol.for("apitally.activation");
31
33
  function configure(options = {}) {
32
34
  const config = setConfig(options);
@@ -53,6 +55,25 @@ function activate() {
53
55
  logError(`Apitally activation failed: ${String(error)}`);
54
56
  }
55
57
  }
58
+ function activateWhenHttpServerListens() {
59
+ const activationState = getActivationState();
60
+ if (activationState.httpServerListenHooks) return;
61
+ const onNetServerListen = (message) => {
62
+ if (message.server.listenerCount("request") > 0) activate();
63
+ };
64
+ diagnosticsChannel.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);
65
+ const bun = globalThis.Bun;
66
+ const originalBunServe = bun?.serve;
67
+ if (bun && originalBunServe) bun.serve = function(...args) {
68
+ const server = originalBunServe.apply(this, args);
69
+ activate();
70
+ return server;
71
+ };
72
+ activationState.httpServerListenHooks = {
73
+ onNetServerListen,
74
+ originalBunServe
75
+ };
76
+ }
56
77
  function isActivated() {
57
78
  return getActivationState().handles !== void 0;
58
79
  }
@@ -93,6 +114,12 @@ async function resetActivation() {
93
114
  resetServerErrors();
94
115
  if (!activationState) return;
95
116
  removeLifecycleHooks(activationState);
117
+ const listenHooks = activationState.httpServerListenHooks;
118
+ if (listenHooks) {
119
+ diagnosticsChannel.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);
120
+ const bun = globalThis.Bun;
121
+ if (bun && listenHooks.originalBunServe) bun.serve = listenHooks.originalBunServe;
122
+ }
96
123
  const handles = activationState.handles;
97
124
  if (!handles) return;
98
125
  handles.undiciInstrumentation?.disable();
@@ -298,6 +325,6 @@ function installBeforeExitHook(activationState) {
298
325
  process.on("beforeExit", listener);
299
326
  }
300
327
  //#endregion
301
- export { activate, activationFactories, configure, flushTelemetry, getActivationHandles, isActivated, registerStartupEventInfo, resetActivation, shutdown };
328
+ export { activate, activateWhenHttpServerListens, activationFactories, configure, flushTelemetry, getActivationHandles, isActivated, registerStartupEventInfo, resetActivation, shutdown };
302
329
 
303
330
  //# sourceMappingURL=activation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"activation.js","names":[],"sources":["../src/activation.ts"],"sourcesContent":["import { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"activation.js","names":[],"sources":["../src/activation.ts"],"sourcesContent":["import diagnosticsChannel from \"node:diagnostics_channel\";\nimport type { Server } from \"node:net\";\nimport { isMainThread } from \"node:worker_threads\";\nimport { ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport type { AnyValueMap } from \"@opentelemetry/api-logs\";\nimport { UndiciInstrumentation } from \"@opentelemetry/instrumentation-undici\";\nimport { BatchLogRecordProcessor, type LoggerProvider } from \"@opentelemetry/sdk-logs\";\nimport { BatchSpanProcessor } from \"@opentelemetry/sdk-trace-base\";\nimport type { NodeTracerProvider } from \"@opentelemetry/sdk-trace-node\";\nimport { type ApitallyConfig, type ApitallyOptions, getConfig, setConfig } from \"./config.js\";\nimport { ExportWorker, type ExportWorkerOptions } from \"./exportWorker.js\";\nimport {\n installConsoleCapture,\n installNestLoggerCapture,\n installPinoCapture,\n installWinstonCapture,\n} from \"./logCapture.js\";\nimport { logDebug, logError, logWarning } from \"./logger.js\";\nimport { ApitallyLogRecordExporter } from \"./logRecordExporter.js\";\nimport { ApitallyLogRecordProcessor } from \"./logRecordProcessor.js\";\nimport { MetricsPipeline } from \"./metrics.js\";\nimport { getDistroVersion } from \"./packageVersion.js\";\nimport {\n createLoggerProvider,\n resolveEnvAndCreateResource,\n setupTracerProvider,\n} from \"./providers.js\";\nimport { Redaction } from \"./redaction.js\";\nimport { installSentryEventIdRecording } from \"./sentry.js\";\nimport { drainServerErrors, resetServerErrors, SERVER_ERROR_EVENT_NAME } from \"./serverErrors.js\";\nimport { ApitallySpanExporter } from \"./spanExporter.js\";\nimport {\n isApitallySpanProcessorDeclared,\n SpanPipeline,\n setActiveSpanPipeline,\n setServerSpanActivationCallback,\n} from \"./spanProcessor.js\";\nimport { Spool } from \"./spool.js\";\nimport { emitStartupEvent, type StartupEventInfo } from \"./startup.js\";\nimport {\n drainValidationErrors,\n resetValidationErrors,\n VALIDATION_ERROR_EVENT_NAME,\n} from \"./validationErrors.js\";\n\n// The worker sends every 15 seconds, so batches only need to reach the spool\n// within that interval.\nconst BATCH_SCHEDULE_DELAY_MILLIS = 1_000;\nconst BATCH_EXPORT_TIMEOUT_MILLIS = 30_000;\nconst BATCH_MAX_QUEUE_SIZE = 2_048;\nconst BATCH_MAX_EXPORT_BATCH_SIZE = 512;\nconst BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE = 32;\nconst SIGNAL_FLUSH_TIMEOUT_MILLIS = 5_000;\n\n// Published by Node >= 20.16 and >= 22.3 once a net.Server is listening.\nconst NET_SERVER_LISTEN_CHANNEL = \"tracing:net.server.listen:asyncEnd\";\n\ntype TerminationSignal = \"SIGTERM\" | \"SIGINT\";\ntype BunServe = (this: unknown, ...args: unknown[]) => unknown;\ntype SignalListeners = Record<TerminationSignal, () => void>;\n\n// The ESM and CJS builds can load together, so a Symbol.for key gives both\n// copies the same activation state.\nconst ACTIVATION_STATE_KEY = Symbol.for(\"apitally.activation\");\n\ninterface ActivationState {\n sdkVersion: string;\n activationAttempted: boolean;\n startupEventInfo?: StartupEventInfo;\n handles?: ActivationHandles;\n runShutdown?: () => Promise<void>;\n shutdownPromise?: Promise<void>;\n beforeExitListener?: () => void;\n signalListeners?: SignalListeners;\n signalDrainPromise?: Promise<void>;\n httpServerListenHooks?: HttpServerListenHooks;\n}\n\ninterface HttpServerListenHooks {\n onNetServerListen: (message: unknown) => void;\n originalBunServe?: BunServe;\n}\n\ninterface ActivationHandles {\n spanPipeline: SpanPipeline;\n tracerProvider?: NodeTracerProvider;\n loggerProvider: LoggerProvider;\n // Consumer identifier to the hash of its last emitted consumer update, in LRU order.\n consumerUpdateHashes: Map<string, string>;\n metricsPipeline: MetricsPipeline;\n spool: Spool;\n worker: ExportWorker;\n undiciInstrumentation?: UndiciInstrumentation;\n}\n\n// Configuration stays synchronous; activate() defers timers and I/O.\nexport function configure(options: ApitallyOptions = {}): ApitallyConfig {\n const config = setConfig(options);\n // User instrumentations read this at initialization. `http/dup` adds stable\n // HTTP attributes alongside legacy ones; a user-set value takes precedence.\n if (!config.disabled && process.env.OTEL_SEMCONV_STABILITY_OPT_IN === undefined) {\n process.env.OTEL_SEMCONV_STABILITY_OPT_IN = \"http/dup\";\n }\n setServerSpanActivationCallback(activate);\n return config;\n}\n\n// The first integration registration wins so one process emits one startup event.\nexport function registerStartupEventInfo(info: StartupEventInfo): void {\n const activationState = getActivationState();\n activationState.startupEventInfo ??= info;\n}\n\n// Activation is synchronous and attempted once, so concurrent first requests\n// observe either no activation or completed activation.\nexport function activate(): void {\n const activationState = getActivationState();\n if (activationState.activationAttempted) {\n return;\n }\n activationState.activationAttempted = true;\n if (shouldSkipActivation()) {\n return;\n }\n try {\n const handles = startPipelines(activationState.startupEventInfo);\n activationState.handles = handles;\n activationState.runShutdown = () => drainAndStop(handles);\n installBeforeExitHook(activationState);\n installSignalHooks(activationState);\n } catch (error) {\n logError(`Apitally activation failed: ${String(error)}`);\n }\n}\n\n// For integrations without a framework startup hook. A server that started\n// listening before this call is missed and activates on its first request.\nexport function activateWhenHttpServerListens(): void {\n const activationState = getActivationState();\n if (activationState.httpServerListenHooks) {\n return;\n }\n // HTTP servers carry the app as a request listener; a cluster primary's\n // internal round-robin server has none, so only workers activate.\n const onNetServerListen = (message: unknown) => {\n if ((message as { server: Server }).server.listenerCount(\"request\") > 0) {\n activate();\n }\n };\n diagnosticsChannel.subscribe(NET_SERVER_LISTEN_CHANNEL, onNetServerListen);\n // Bun publishes no net listen channel, but every Bun HTTP server starts through Bun.serve.\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n const originalBunServe = bun?.serve;\n if (bun && originalBunServe) {\n bun.serve = function (this: unknown, ...args: unknown[]) {\n const server = originalBunServe.apply(this, args);\n activate();\n return server;\n };\n }\n activationState.httpServerListenHooks = { onNetServerListen, originalBunServe };\n}\n\nexport function isActivated(): boolean {\n return getActivationState().handles !== undefined;\n}\n\nexport function getActivationHandles(): ActivationHandles | undefined {\n return getActivationState().handles;\n}\n\nexport async function flushTelemetry(): Promise<void> {\n try {\n await getActivationState().handles?.worker.runCycle();\n } catch (error) {\n logDebug(`Error flushing telemetry: ${String(error)}`);\n }\n}\n\n// Concurrent calls and lifecycle hooks share one final drain; calls before\n// activation are no-ops.\nexport function shutdown(): Promise<void> {\n const activationState = getActivationState();\n const handles = activationState.handles;\n const runShutdown = activationState.runShutdown;\n if (!handles || !runShutdown) {\n return Promise.resolve();\n }\n if (!activationState.shutdownPromise) {\n removeLifecycleHooks(activationState);\n const signalDrainPromise = activationState.signalDrainPromise;\n activationState.shutdownPromise = (\n signalDrainPromise\n ? signalDrainPromise.then(() => handles.worker.waitForIdle())\n : Promise.resolve()\n ).then(runShutdown);\n }\n return activationState.shutdownPromise;\n}\n\n// Tests replace these factories to isolate spool files and worker timing.\nexport const activationFactories = {\n createSpool: (): Spool => new Spool(),\n createExportWorker: (options: ExportWorkerOptions): ExportWorker => new ExportWorker(options),\n};\nconst defaultFactories = { ...activationFactories };\n\n// Tests reset process-global activation and its side effects between cases.\nexport async function resetActivation(): Promise<void> {\n Object.assign(activationFactories, defaultFactories);\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const activationState = holder[ACTIVATION_STATE_KEY];\n delete holder[ACTIVATION_STATE_KEY];\n hasWarnedAboutVersionSkew = false;\n resetValidationErrors();\n resetServerErrors();\n if (!activationState) {\n return;\n }\n removeLifecycleHooks(activationState);\n const listenHooks = activationState.httpServerListenHooks;\n if (listenHooks) {\n diagnosticsChannel.unsubscribe(NET_SERVER_LISTEN_CHANNEL, listenHooks.onNetServerListen);\n const bun = (globalThis as { Bun?: { serve: BunServe } }).Bun;\n if (bun && listenHooks.originalBunServe) {\n bun.serve = listenHooks.originalBunServe;\n }\n }\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n handles.undiciInstrumentation?.disable();\n await handles.worker.stop();\n await handles.spanPipeline.shutdown();\n await handles.loggerProvider.shutdown();\n await handles.spool.clear();\n}\n\nlet hasWarnedAboutVersionSkew = false;\n\n// One root-context record per aggregated error, drained right before the log\n// processor flush so the records leave with the same export cycle.\nfunction emitErrorEvents(loggerProvider: LoggerProvider): void {\n const logger = loggerProvider.getLogger(\"apitally\");\n const events: [string, AnyValueMap[]][] = [\n [VALIDATION_ERROR_EVENT_NAME, drainValidationErrors()],\n [SERVER_ERROR_EVENT_NAME, drainServerErrors()],\n ];\n for (const [eventName, bodies] of events) {\n for (const body of bodies) {\n logger.emit({ timestamp: Date.now(), context: ROOT_CONTEXT, eventName, body });\n }\n }\n}\n\nfunction getActivationState(): ActivationState {\n const holder = globalThis as Record<symbol, ActivationState | undefined>;\n const existing = holder[ACTIVATION_STATE_KEY];\n if (existing) {\n if (!hasWarnedAboutVersionSkew && existing.sdkVersion !== getDistroVersion()) {\n hasWarnedAboutVersionSkew = true;\n logWarning(\n `Two copies of the apitally package with different versions (${existing.sdkVersion} and ${getDistroVersion()}) are loaded in this process; version ${existing.sdkVersion} stays active. To resolve this, deduplicate the apitally installation.`,\n );\n }\n return existing;\n }\n const activationState: ActivationState = {\n sdkVersion: getDistroVersion(),\n activationAttempted: false,\n };\n holder[ACTIVATION_STATE_KEY] = activationState;\n return activationState;\n}\n\nfunction shouldSkipActivation(): boolean {\n return (\n Boolean(process.env.JEST_WORKER_ID) ||\n Boolean(process.env.VITEST) ||\n process.env.NODE_ENV === \"test\" ||\n getConfig().disabled\n );\n}\n\nfunction startPipelines(startupEventInfo: StartupEventInfo | undefined): ActivationHandles {\n const config = getConfig();\n let hasUserProvider = isApitallySpanProcessorDeclared();\n const { env, resource } = resolveEnvAndCreateResource();\n const instanceId = resource.attributes[\"service.instance.id\"] as string;\n const spool = activationFactories.createSpool();\n const spanExporter = new ApitallySpanExporter({\n redaction: new Redaction(),\n env,\n instanceId,\n spool,\n maskRequestBody: config.maskRequestBody,\n maskResponseBody: config.maskResponseBody,\n });\n // Concrete options prevent OTel environment variables from changing batch\n // behavior. Each processor gets a fresh object because its config is mutated.\n const batchSpanProcessor = new BatchSpanProcessor(spanExporter, {\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize:\n config.captureRequestBody || config.captureResponseBody\n ? BATCH_MAX_EXPORT_BATCH_SIZE_WITH_BODY_CAPTURE\n : BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const spanPipeline = new SpanPipeline(batchSpanProcessor, () => spanExporter.forceFlush());\n let tracerProvider: NodeTracerProvider | undefined;\n if (!hasUserProvider) {\n tracerProvider = setupTracerProvider(resource, [spanPipeline]);\n if (!tracerProvider) {\n hasUserProvider = true;\n logWarning(\n \"Apitally could not register its OpenTelemetry tracer provider because another provider is already registered. Only metrics and the startup event are sent to Apitally until you add ApitallySpanProcessor (exported by the apitally package) to your tracer provider's spanProcessors constructor option or the NodeSDK spanProcessors option.\",\n );\n }\n }\n setActiveSpanPipeline(spanPipeline);\n // BatchLogRecordProcessor requires its single-options-object form; positional\n // arguments create a broken processor.\n const batchLogProcessor = new BatchLogRecordProcessor({\n exporter: new ApitallyLogRecordExporter(spool),\n scheduledDelayMillis: BATCH_SCHEDULE_DELAY_MILLIS,\n exportTimeoutMillis: BATCH_EXPORT_TIMEOUT_MILLIS,\n maxQueueSize: BATCH_MAX_QUEUE_SIZE,\n maxExportBatchSize: BATCH_MAX_EXPORT_BATCH_SIZE,\n });\n const logRecordProcessor = new ApitallyLogRecordProcessor(\n batchLogProcessor,\n spanPipeline,\n config.maskLogRecord,\n );\n const loggerProvider = createLoggerProvider(resource, [logRecordProcessor]);\n const metricsPipeline = new MetricsPipeline(resource, spool);\n spanPipeline.metricsRecorder = (record) => metricsPipeline.recordFromRequest(record);\n const worker = activationFactories.createExportWorker({\n spool,\n otlpEndpoint: config.otlpEndpoint,\n writeToken: config.writeToken,\n env,\n });\n worker.flushCallbacks.push(\n () => metricsPipeline.collectAndExport(),\n () => spanPipeline.forceFlush(),\n () => emitErrorEvents(loggerProvider),\n () => batchLogProcessor.forceFlush(),\n );\n if (config.captureLogs) {\n installConsoleCapture(loggerProvider);\n installNestLoggerCapture(loggerProvider);\n installWinstonCapture(loggerProvider);\n installPinoCapture(loggerProvider);\n }\n installSentryEventIdRecording();\n let undiciInstrumentation: UndiciInstrumentation | undefined;\n if (!hasUserProvider) {\n undiciInstrumentation = createUndiciInstrumentation(config.otlpEndpoint);\n }\n worker.start();\n if (startupEventInfo) {\n emitStartupEvent(loggerProvider, startupEventInfo);\n }\n return {\n spanPipeline,\n tracerProvider,\n loggerProvider,\n consumerUpdateHashes: new Map(),\n metricsPipeline,\n spool,\n worker,\n undiciInstrumentation,\n };\n}\n\n// ignoreRequestHook prevents telemetry for export POSTs. The request origin can\n// be a string or URL at runtime despite its string type.\nfunction createUndiciInstrumentation(otlpEndpoint: string): UndiciInstrumentation {\n const endpointOrigin = new URL(otlpEndpoint).origin;\n return new UndiciInstrumentation({\n ignoreRequestHook: (request) => {\n try {\n return new URL(String(request.origin)).origin === endpointOrigin;\n } catch {\n return false;\n }\n },\n });\n}\n\nasync function drainAndStop(handles: ActivationHandles): Promise<void> {\n try {\n await handles.spanPipeline.shutdown();\n await handles.worker.finalDrain();\n await handles.loggerProvider.shutdown();\n await handles.worker.stop();\n } catch (error) {\n logWarning(`Error draining telemetry on shutdown: ${String(error)}`);\n }\n}\n\nfunction installSignalHooks(activationState: ActivationState): void {\n if (process.platform === \"win32\" || !isMainThread) {\n return;\n }\n let listeners: SignalListeners;\n listeners = {\n SIGTERM: () => handleTerminationSignal(activationState, listeners, \"SIGTERM\"),\n SIGINT: () => handleTerminationSignal(activationState, listeners, \"SIGINT\"),\n };\n activationState.signalListeners = listeners;\n try {\n process.prependOnceListener(\"SIGTERM\", listeners.SIGTERM);\n process.prependOnceListener(\"SIGINT\", listeners.SIGINT);\n } catch (error) {\n removeSignalHooks(activationState, listeners);\n logWarning(`Unable to install Apitally signal handlers: ${String(error)}`);\n }\n}\n\nfunction handleTerminationSignal(\n activationState: ActivationState,\n listeners: SignalListeners,\n signal: TerminationSignal,\n): void {\n const hasApplicationListener = process\n .listeners(signal)\n .some((listener) => listener !== listeners[signal]);\n removeSignalHooks(activationState, listeners);\n const drainPromise = flushAfterTerminationSignal(activationState, signal, hasApplicationListener);\n activationState.signalDrainPromise = drainPromise;\n void drainPromise.catch((error: unknown) => {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n });\n}\n\nasync function flushAfterTerminationSignal(\n activationState: ActivationState,\n signal: TerminationSignal,\n hasApplicationListener: boolean,\n): Promise<void> {\n const handles = activationState.handles;\n if (!handles) {\n return;\n }\n try {\n if (activationState.shutdownPromise) {\n await waitForSignalDeadline(activationState.shutdownPromise);\n } else {\n await handles.worker.finalDrain(SIGNAL_FLUSH_TIMEOUT_MILLIS);\n }\n } catch (error) {\n logDebug(`Error flushing telemetry on ${signal}: ${String(error)}`);\n }\n if (hasApplicationListener || process.listeners(signal).length > 0) {\n return;\n }\n const exitCode = signal === \"SIGTERM\" ? 143 : 130;\n if (process.platform === \"linux\" && process.pid === 1) {\n process.exit(exitCode);\n }\n try {\n process.kill(process.pid, signal);\n } catch {\n process.exit(exitCode);\n }\n}\n\nasync function waitForSignalDeadline(promise: Promise<void>): Promise<void> {\n let deadlineTimer: NodeJS.Timeout | undefined;\n const deadlineReached = new Promise<void>((resolve) => {\n deadlineTimer = setTimeout(resolve, SIGNAL_FLUSH_TIMEOUT_MILLIS);\n });\n try {\n await Promise.race([promise, deadlineReached]);\n } finally {\n if (deadlineTimer) {\n clearTimeout(deadlineTimer);\n }\n }\n}\n\nfunction removeSignalHooks(\n activationState: ActivationState,\n listeners = activationState.signalListeners,\n): void {\n if (!listeners) {\n return;\n }\n process.removeListener(\"SIGTERM\", listeners.SIGTERM);\n process.removeListener(\"SIGINT\", listeners.SIGINT);\n if (activationState.signalListeners === listeners) {\n activationState.signalListeners = undefined;\n }\n}\n\nfunction removeLifecycleHooks(activationState: ActivationState): void {\n removeSignalHooks(activationState);\n if (activationState.beforeExitListener) {\n process.removeListener(\"beforeExit\", activationState.beforeExitListener);\n activationState.beforeExitListener = undefined;\n }\n}\n\nfunction installBeforeExitHook(activationState: ActivationState): void {\n const listener = () => {\n // The drain keeps the event loop alive until shutdown settles.\n void shutdown().catch((error: unknown) => {\n logDebug(`Error draining telemetry on shutdown: ${String(error)}`);\n });\n };\n activationState.beforeExitListener = listener;\n process.on(\"beforeExit\", listener);\n}\n"],"mappings":"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"}
@@ -9,7 +9,7 @@ const require_requestObservation = require("../requestObservation.cjs");
9
9
  const require_requestObservationNode = require("../requestObservationNode.cjs");
10
10
  let _opentelemetry_api = require("@opentelemetry/api");
11
11
  //#region src/adonisjs/middleware.ts
12
- const TRACER_NAME = "apitally.adonisjs";
12
+ const TRACER_NAME = "apitally/adonisjs";
13
13
  var ApitallyMiddleware = class {
14
14
  async handle(ctx, next) {
15
15
  if (!require_activation.isActivated()) return next();
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.cjs","names":["isActivated","startNodeRequestObservation","getConfig","context"],"sources":["../../src/adonisjs/middleware.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\nimport type { NextFn } from \"@adonisjs/core/types/http\";\nimport { type Context, context } from \"@opentelemetry/api\";\n\nimport { isActivated } from \"../activation.js\";\nimport { getConfig } from \"../config.js\";\nimport { logWarning } from \"../logger.js\";\nimport { finalizeRequestObservation } from \"../requestObservation.js\";\nimport { captureNodeResponse, startNodeRequestObservation } from \"../requestObservationNode.js\";\n\nconst TRACER_NAME = \"apitally.adonisjs\";\n\nexport default class ApitallyMiddleware {\n async handle(ctx: HttpContext, next: NextFn): Promise<unknown> {\n if (!isActivated()) {\n return next();\n }\n\n let requestContext: Context | undefined;\n try {\n const request = ctx.request.request;\n const response = ctx.response.response;\n const started = startNodeRequestObservation({ request, tracerName: TRACER_NAME });\n requestContext = started.requestContext;\n context.bind(requestContext, request);\n context.bind(requestContext, response);\n captureNodeResponse(\n response,\n getConfig().captureResponseBody &&\n started.observation.requestRecord.dropReason === undefined,\n started.observation.requestBodyCapture,\n (name) => ctx.response.getHeader(name),\n )\n .then((completion) => {\n finalizeRequestObservation({\n observation: started.observation,\n completedAtMillis: completion.completedAtMillis,\n statusCode: response.statusCode,\n route: ctx.route?.pattern,\n clientAddress: ctx.request.ip(),\n requestHeaders: request.headers,\n responseHeaders: ctx.response.getHeaders(),\n capturedRequestBody: completion.requestBody,\n capturedResponseBody: completion,\n });\n })\n .catch((error: unknown) => {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n });\n } catch (error) {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n }\n\n return requestContext ? context.with(requestContext, next) : next();\n }\n}\n"],"mappings":";;;;;;;;;;;AAUA,MAAM,cAAc;AAEpB,IAAqB,qBAArB,MAAwC;CACtC,MAAM,OAAO,KAAkB,MAAgC;EAC7D,IAAI,CAACA,mBAAAA,YAAY,GACf,OAAO,KAAK;EAGd,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,IAAI,QAAQ;GAC5B,MAAM,WAAW,IAAI,SAAS;GAC9B,MAAM,UAAUC,+BAAAA,4BAA4B;IAAE;IAAS,YAAY;GAAY,CAAC;GAChF,iBAAiB,QAAQ;GACzB,mBAAA,QAAQ,KAAK,gBAAgB,OAAO;GACpC,mBAAA,QAAQ,KAAK,gBAAgB,QAAQ;GACrC,+BAAA,oBACE,UACAC,eAAAA,UAAU,CAAC,CAAC,uBACV,QAAQ,YAAY,cAAc,eAAe,KAAA,GACnD,QAAQ,YAAY,qBACnB,SAAS,IAAI,SAAS,UAAU,IAAI,CACvC,CAAC,CACE,MAAM,eAAe;IACpB,2BAAA,2BAA2B;KACzB,aAAa,QAAQ;KACrB,mBAAmB,WAAW;KAC9B,YAAY,SAAS;KACrB,OAAO,IAAI,OAAO;KAClB,eAAe,IAAI,QAAQ,GAAG;KAC9B,gBAAgB,QAAQ;KACxB,iBAAiB,IAAI,SAAS,WAAW;KACzC,qBAAqB,WAAW;KAChC,sBAAsB;IACxB,CAAC;GACH,CAAC,CAAC,CACD,OAAO,UAAmB;IACzB,eAAA,WAAW,qCAAqC,OAAO,KAAK,GAAG;GACjE,CAAC;EACL,SAAS,OAAO;GACd,eAAA,WAAW,qCAAqC,OAAO,KAAK,GAAG;EACjE;EAEA,OAAO,iBAAiBC,mBAAAA,QAAQ,KAAK,gBAAgB,IAAI,IAAI,KAAK;CACpE;AACF"}
1
+ {"version":3,"file":"middleware.cjs","names":["isActivated","startNodeRequestObservation","getConfig","context"],"sources":["../../src/adonisjs/middleware.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\nimport type { NextFn } from \"@adonisjs/core/types/http\";\nimport { type Context, context } from \"@opentelemetry/api\";\n\nimport { isActivated } from \"../activation.js\";\nimport { getConfig } from \"../config.js\";\nimport { logWarning } from \"../logger.js\";\nimport { finalizeRequestObservation } from \"../requestObservation.js\";\nimport { captureNodeResponse, startNodeRequestObservation } from \"../requestObservationNode.js\";\n\nconst TRACER_NAME = \"apitally/adonisjs\";\n\nexport default class ApitallyMiddleware {\n async handle(ctx: HttpContext, next: NextFn): Promise<unknown> {\n if (!isActivated()) {\n return next();\n }\n\n let requestContext: Context | undefined;\n try {\n const request = ctx.request.request;\n const response = ctx.response.response;\n const started = startNodeRequestObservation({ request, tracerName: TRACER_NAME });\n requestContext = started.requestContext;\n context.bind(requestContext, request);\n context.bind(requestContext, response);\n captureNodeResponse(\n response,\n getConfig().captureResponseBody &&\n started.observation.requestRecord.dropReason === undefined,\n started.observation.requestBodyCapture,\n (name) => ctx.response.getHeader(name),\n )\n .then((completion) => {\n finalizeRequestObservation({\n observation: started.observation,\n completedAtMillis: completion.completedAtMillis,\n statusCode: response.statusCode,\n route: ctx.route?.pattern,\n clientAddress: ctx.request.ip(),\n requestHeaders: request.headers,\n responseHeaders: ctx.response.getHeaders(),\n capturedRequestBody: completion.requestBody,\n capturedResponseBody: completion,\n });\n })\n .catch((error: unknown) => {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n });\n } catch (error) {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n }\n\n return requestContext ? context.with(requestContext, next) : next();\n }\n}\n"],"mappings":";;;;;;;;;;;AAUA,MAAM,cAAc;AAEpB,IAAqB,qBAArB,MAAwC;CACtC,MAAM,OAAO,KAAkB,MAAgC;EAC7D,IAAI,CAACA,mBAAAA,YAAY,GACf,OAAO,KAAK;EAGd,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,IAAI,QAAQ;GAC5B,MAAM,WAAW,IAAI,SAAS;GAC9B,MAAM,UAAUC,+BAAAA,4BAA4B;IAAE;IAAS,YAAY;GAAY,CAAC;GAChF,iBAAiB,QAAQ;GACzB,mBAAA,QAAQ,KAAK,gBAAgB,OAAO;GACpC,mBAAA,QAAQ,KAAK,gBAAgB,QAAQ;GACrC,+BAAA,oBACE,UACAC,eAAAA,UAAU,CAAC,CAAC,uBACV,QAAQ,YAAY,cAAc,eAAe,KAAA,GACnD,QAAQ,YAAY,qBACnB,SAAS,IAAI,SAAS,UAAU,IAAI,CACvC,CAAC,CACE,MAAM,eAAe;IACpB,2BAAA,2BAA2B;KACzB,aAAa,QAAQ;KACrB,mBAAmB,WAAW;KAC9B,YAAY,SAAS;KACrB,OAAO,IAAI,OAAO;KAClB,eAAe,IAAI,QAAQ,GAAG;KAC9B,gBAAgB,QAAQ;KACxB,iBAAiB,IAAI,SAAS,WAAW;KACzC,qBAAqB,WAAW;KAChC,sBAAsB;IACxB,CAAC;GACH,CAAC,CAAC,CACD,OAAO,UAAmB;IACzB,eAAA,WAAW,qCAAqC,OAAO,KAAK,GAAG;GACjE,CAAC;EACL,SAAS,OAAO;GACd,eAAA,WAAW,qCAAqC,OAAO,KAAK,GAAG;EACjE;EAEA,OAAO,iBAAiBC,mBAAAA,QAAQ,KAAK,gBAAgB,IAAI,IAAI,KAAK;CACpE;AACF"}
@@ -5,7 +5,7 @@ import { finalizeRequestObservation } from "../requestObservation.js";
5
5
  import { captureNodeResponse, startNodeRequestObservation } from "../requestObservationNode.js";
6
6
  import { context } from "@opentelemetry/api";
7
7
  //#region src/adonisjs/middleware.ts
8
- const TRACER_NAME = "apitally.adonisjs";
8
+ const TRACER_NAME = "apitally/adonisjs";
9
9
  var ApitallyMiddleware = class {
10
10
  async handle(ctx, next) {
11
11
  if (!isActivated()) return next();
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","names":[],"sources":["../../src/adonisjs/middleware.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\nimport type { NextFn } from \"@adonisjs/core/types/http\";\nimport { type Context, context } from \"@opentelemetry/api\";\n\nimport { isActivated } from \"../activation.js\";\nimport { getConfig } from \"../config.js\";\nimport { logWarning } from \"../logger.js\";\nimport { finalizeRequestObservation } from \"../requestObservation.js\";\nimport { captureNodeResponse, startNodeRequestObservation } from \"../requestObservationNode.js\";\n\nconst TRACER_NAME = \"apitally.adonisjs\";\n\nexport default class ApitallyMiddleware {\n async handle(ctx: HttpContext, next: NextFn): Promise<unknown> {\n if (!isActivated()) {\n return next();\n }\n\n let requestContext: Context | undefined;\n try {\n const request = ctx.request.request;\n const response = ctx.response.response;\n const started = startNodeRequestObservation({ request, tracerName: TRACER_NAME });\n requestContext = started.requestContext;\n context.bind(requestContext, request);\n context.bind(requestContext, response);\n captureNodeResponse(\n response,\n getConfig().captureResponseBody &&\n started.observation.requestRecord.dropReason === undefined,\n started.observation.requestBodyCapture,\n (name) => ctx.response.getHeader(name),\n )\n .then((completion) => {\n finalizeRequestObservation({\n observation: started.observation,\n completedAtMillis: completion.completedAtMillis,\n statusCode: response.statusCode,\n route: ctx.route?.pattern,\n clientAddress: ctx.request.ip(),\n requestHeaders: request.headers,\n responseHeaders: ctx.response.getHeaders(),\n capturedRequestBody: completion.requestBody,\n capturedResponseBody: completion,\n });\n })\n .catch((error: unknown) => {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n });\n } catch (error) {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n }\n\n return requestContext ? context.with(requestContext, next) : next();\n }\n}\n"],"mappings":";;;;;;;AAUA,MAAM,cAAc;AAEpB,IAAqB,qBAArB,MAAwC;CACtC,MAAM,OAAO,KAAkB,MAAgC;EAC7D,IAAI,CAAC,YAAY,GACf,OAAO,KAAK;EAGd,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,IAAI,QAAQ;GAC5B,MAAM,WAAW,IAAI,SAAS;GAC9B,MAAM,UAAU,4BAA4B;IAAE;IAAS,YAAY;GAAY,CAAC;GAChF,iBAAiB,QAAQ;GACzB,QAAQ,KAAK,gBAAgB,OAAO;GACpC,QAAQ,KAAK,gBAAgB,QAAQ;GACrC,oBACE,UACA,UAAU,CAAC,CAAC,uBACV,QAAQ,YAAY,cAAc,eAAe,KAAA,GACnD,QAAQ,YAAY,qBACnB,SAAS,IAAI,SAAS,UAAU,IAAI,CACvC,CAAC,CACE,MAAM,eAAe;IACpB,2BAA2B;KACzB,aAAa,QAAQ;KACrB,mBAAmB,WAAW;KAC9B,YAAY,SAAS;KACrB,OAAO,IAAI,OAAO;KAClB,eAAe,IAAI,QAAQ,GAAG;KAC9B,gBAAgB,QAAQ;KACxB,iBAAiB,IAAI,SAAS,WAAW;KACzC,qBAAqB,WAAW;KAChC,sBAAsB;IACxB,CAAC;GACH,CAAC,CAAC,CACD,OAAO,UAAmB;IACzB,WAAW,qCAAqC,OAAO,KAAK,GAAG;GACjE,CAAC;EACL,SAAS,OAAO;GACd,WAAW,qCAAqC,OAAO,KAAK,GAAG;EACjE;EAEA,OAAO,iBAAiB,QAAQ,KAAK,gBAAgB,IAAI,IAAI,KAAK;CACpE;AACF"}
1
+ {"version":3,"file":"middleware.js","names":[],"sources":["../../src/adonisjs/middleware.ts"],"sourcesContent":["import type { HttpContext } from \"@adonisjs/core/http\";\nimport type { NextFn } from \"@adonisjs/core/types/http\";\nimport { type Context, context } from \"@opentelemetry/api\";\n\nimport { isActivated } from \"../activation.js\";\nimport { getConfig } from \"../config.js\";\nimport { logWarning } from \"../logger.js\";\nimport { finalizeRequestObservation } from \"../requestObservation.js\";\nimport { captureNodeResponse, startNodeRequestObservation } from \"../requestObservationNode.js\";\n\nconst TRACER_NAME = \"apitally/adonisjs\";\n\nexport default class ApitallyMiddleware {\n async handle(ctx: HttpContext, next: NextFn): Promise<unknown> {\n if (!isActivated()) {\n return next();\n }\n\n let requestContext: Context | undefined;\n try {\n const request = ctx.request.request;\n const response = ctx.response.response;\n const started = startNodeRequestObservation({ request, tracerName: TRACER_NAME });\n requestContext = started.requestContext;\n context.bind(requestContext, request);\n context.bind(requestContext, response);\n captureNodeResponse(\n response,\n getConfig().captureResponseBody &&\n started.observation.requestRecord.dropReason === undefined,\n started.observation.requestBodyCapture,\n (name) => ctx.response.getHeader(name),\n )\n .then((completion) => {\n finalizeRequestObservation({\n observation: started.observation,\n completedAtMillis: completion.completedAtMillis,\n statusCode: response.statusCode,\n route: ctx.route?.pattern,\n clientAddress: ctx.request.ip(),\n requestHeaders: request.headers,\n responseHeaders: ctx.response.getHeaders(),\n capturedRequestBody: completion.requestBody,\n capturedResponseBody: completion,\n });\n })\n .catch((error: unknown) => {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n });\n } catch (error) {\n logWarning(`Error in the Apitally middleware: ${String(error)}`);\n }\n\n return requestContext ? context.with(requestContext, next) : next();\n }\n}\n"],"mappings":";;;;;;;AAUA,MAAM,cAAc;AAEpB,IAAqB,qBAArB,MAAwC;CACtC,MAAM,OAAO,KAAkB,MAAgC;EAC7D,IAAI,CAAC,YAAY,GACf,OAAO,KAAK;EAGd,IAAI;EACJ,IAAI;GACF,MAAM,UAAU,IAAI,QAAQ;GAC5B,MAAM,WAAW,IAAI,SAAS;GAC9B,MAAM,UAAU,4BAA4B;IAAE;IAAS,YAAY;GAAY,CAAC;GAChF,iBAAiB,QAAQ;GACzB,QAAQ,KAAK,gBAAgB,OAAO;GACpC,QAAQ,KAAK,gBAAgB,QAAQ;GACrC,oBACE,UACA,UAAU,CAAC,CAAC,uBACV,QAAQ,YAAY,cAAc,eAAe,KAAA,GACnD,QAAQ,YAAY,qBACnB,SAAS,IAAI,SAAS,UAAU,IAAI,CACvC,CAAC,CACE,MAAM,eAAe;IACpB,2BAA2B;KACzB,aAAa,QAAQ;KACrB,mBAAmB,WAAW;KAC9B,YAAY,SAAS;KACrB,OAAO,IAAI,OAAO;KAClB,eAAe,IAAI,QAAQ,GAAG;KAC9B,gBAAgB,QAAQ;KACxB,iBAAiB,IAAI,SAAS,WAAW;KACzC,qBAAqB,WAAW;KAChC,sBAAsB;IACxB,CAAC;GACH,CAAC,CAAC,CACD,OAAO,UAAmB;IACzB,WAAW,qCAAqC,OAAO,KAAK,GAAG;GACjE,CAAC;EACL,SAAS,OAAO;GACd,WAAW,qCAAqC,OAAO,KAAK,GAAG;EACjE;EAEA,OAAO,iBAAiB,QAAQ,KAAK,gBAAgB,IAAI,IAAI,KAAK;CACpE;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["createElysiaPlugin","Elysia"],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { type AnyElysia, Elysia } from \"elysia\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { createElysiaPlugin, installElysiaIntegration } from \"./middleware.js\";\n\nexport type { ApitallyOptions };\n\nexport function apitallyPlugin(options?: ApitallyOptions): Elysia {\n return createElysiaPlugin(Elysia, options) as Elysia;\n}\n\n// Setup stays synchronous; activation begins on the first request.\nexport function useApitally(app: AnyElysia, options?: ApitallyOptions): void {\n installElysiaIntegration(app, options);\n}\n"],"mappings":";;;;AAMA,SAAgB,eAAe,SAAmC;CAChE,OAAOA,0BAAAA,mBAAmBC,OAAAA,QAAQ,OAAO;AAC3C;AAGA,SAAgB,YAAY,KAAgB,SAAiC;CAC3E,0BAAA,yBAAyB,KAAK,OAAO;AACvC"}
1
+ {"version":3,"file":"index.cjs","names":["createElysiaPlugin","Elysia"],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { type AnyElysia, Elysia } from \"elysia\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { createElysiaPlugin, installElysiaIntegration } from \"./middleware.js\";\n\nexport type { ApitallyOptions };\n\nexport function apitallyPlugin(options?: ApitallyOptions): Elysia {\n return createElysiaPlugin(Elysia, options) as Elysia;\n}\n\n// Setup stays synchronous; activation begins when listen() starts the server,\n// or on the first request.\nexport function useApitally(app: AnyElysia, options?: ApitallyOptions): void {\n installElysiaIntegration(app, options);\n}\n"],"mappings":";;;;AAMA,SAAgB,eAAe,SAAmC;CAChE,OAAOA,0BAAAA,mBAAmBC,OAAAA,QAAQ,OAAO;AAC3C;AAIA,SAAgB,YAAY,KAAgB,SAAiC;CAC3E,0BAAA,yBAAyB,KAAK,OAAO;AACvC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { type AnyElysia, Elysia } from \"elysia\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { createElysiaPlugin, installElysiaIntegration } from \"./middleware.js\";\n\nexport type { ApitallyOptions };\n\nexport function apitallyPlugin(options?: ApitallyOptions): Elysia {\n return createElysiaPlugin(Elysia, options) as Elysia;\n}\n\n// Setup stays synchronous; activation begins on the first request.\nexport function useApitally(app: AnyElysia, options?: ApitallyOptions): void {\n installElysiaIntegration(app, options);\n}\n"],"mappings":";;;AAMA,SAAgB,eAAe,SAAmC;CAChE,OAAO,mBAAmB,QAAQ,OAAO;AAC3C;AAGA,SAAgB,YAAY,KAAgB,SAAiC;CAC3E,yBAAyB,KAAK,OAAO;AACvC"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/elysia/index.ts"],"sourcesContent":["import { type AnyElysia, Elysia } from \"elysia\";\nimport type { ApitallyOptions } from \"../config.js\";\nimport { createElysiaPlugin, installElysiaIntegration } from \"./middleware.js\";\n\nexport type { ApitallyOptions };\n\nexport function apitallyPlugin(options?: ApitallyOptions): Elysia {\n return createElysiaPlugin(Elysia, options) as Elysia;\n}\n\n// Setup stays synchronous; activation begins when listen() starts the server,\n// or on the first request.\nexport function useApitally(app: AnyElysia, options?: ApitallyOptions): void {\n installElysiaIntegration(app, options);\n}\n"],"mappings":";;;AAMA,SAAgB,eAAe,SAAmC;CAChE,OAAO,mBAAmB,QAAQ,OAAO;AAC3C;AAIA,SAAgB,YAAY,KAAgB,SAAiC;CAC3E,yBAAyB,KAAK,OAAO;AACvC"}
@@ -12,18 +12,16 @@ let _opentelemetry_api = require("@opentelemetry/api");
12
12
  //#region src/elysia/middleware.ts
13
13
  const INSTALL_MARKER = Symbol.for("apitally.elysiaInstall");
14
14
  const PLUGIN_NAME = "apitally";
15
- const TRACER_NAME = "apitally.elysia";
15
+ const TRACER_NAME = "apitally/elysia";
16
16
  function createElysiaPlugin(ElysiaClass, options) {
17
17
  require_activation.configure(options);
18
- let app;
18
+ const plugin = buildElysiaPlugin(ElysiaClass);
19
19
  require_activation.registerStartupEventInfo({
20
20
  framework: "elysia",
21
21
  frameworkVersion: require_packageVersion.resolvePackageVersion("elysia"),
22
- resolvePaths: () => app ? require_elysia_routes.resolveStartupPaths(app) : []
23
- });
24
- return buildElysiaPlugin(ElysiaClass, (startedApp) => {
25
- app = startedApp;
22
+ resolvePaths: () => require_elysia_routes.resolveStartupPaths(plugin)
26
23
  });
24
+ return plugin;
27
25
  }
28
26
  function installElysiaIntegration(app, options) {
29
27
  require_activation.configure(options);
@@ -42,7 +40,7 @@ function installElysiaIntegration(app, options) {
42
40
  const ElysiaClass = app.constructor;
43
41
  app.use(buildElysiaPlugin(ElysiaClass));
44
42
  }
45
- function buildElysiaPlugin(ElysiaClass, recordStartedApp) {
43
+ function buildElysiaPlugin(ElysiaClass) {
46
44
  const observations = /* @__PURE__ */ new WeakMap();
47
45
  const plugin = new ElysiaClass({ name: PLUGIN_NAME });
48
46
  let startedApp;
@@ -54,7 +52,7 @@ function buildElysiaPlugin(ElysiaClass, recordStartedApp) {
54
52
  const started = require_requestObservationWeb.startWebRequestObservation({
55
53
  request,
56
54
  tracerName: TRACER_NAME,
57
- clientAddress: startedApp?.server?.requestIP(request)?.address
55
+ clientAddress: startedApp?.server?.requestIP(request)?.address ?? request.ip
58
56
  });
59
57
  observation = {
60
58
  ...started.observation,
@@ -81,8 +79,8 @@ function buildElysiaPlugin(ElysiaClass, recordStartedApp) {
81
79
  }));
82
80
  plugin.onStart((app) => {
83
81
  startedApp = app;
84
- recordStartedApp?.(app);
85
- if (app.config.aot === false) require_logger.logWarning("Apitally does not observe requests on an Elysia app with aot: false. To resolve this, remove the aot: false option.");
82
+ if (app.config?.aot === false) require_logger.logWarning("Apitally does not observe requests on an Elysia app with aot: false. To resolve this, remove the aot: false option.");
83
+ require_activation.activate();
86
84
  });
87
85
  plugin.onTransform({ as: "global" }, ({ request, route }) => {
88
86
  try {