autotel 7.10.1 → 8.1.0

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 (126) hide show
  1. package/README.md +38 -32
  2. package/dist/{attribute-redacting-processor-rkV_WL-k.d.ts → attribute-redacting-processor-BrrdojmP.d.ts} +5 -1
  3. package/dist/{attribute-redacting-processor-CvBE0z1p.d.cts → attribute-redacting-processor-Cq7K8Okp.d.cts} +5 -1
  4. package/dist/attribute-redacting-processor.cjs +18 -8
  5. package/dist/attribute-redacting-processor.d.cts +1 -1
  6. package/dist/attribute-redacting-processor.d.ts +1 -1
  7. package/dist/attribute-redacting-processor.js +18 -8
  8. package/dist/{attributes-Ii3jDPsW.cjs → attributes-BqgJl9qA.cjs} +1 -1
  9. package/dist/{attributes-CuGx6cOI.js → attributes-BtwTkuX7.js} +1 -1
  10. package/dist/attributes.cjs +1 -1
  11. package/dist/attributes.js +1 -1
  12. package/dist/auto.cjs +1 -1
  13. package/dist/auto.js +1 -1
  14. package/dist/business-baggage.cjs +1 -1
  15. package/dist/business-baggage.js +1 -1
  16. package/dist/{canonical-log-line-processor-DDGzm-wi.d.ts → canonical-log-line-processor-BaFqHO5l.d.ts} +1 -2
  17. package/dist/{canonical-log-line-processor-DLeAQjgb.d.cts → canonical-log-line-processor-C-RdV5af.d.cts} +1 -2
  18. package/dist/{canonical-log-line-processor-BU03jJeA.cjs → canonical-log-line-processor-DScNq1g8.cjs} +1 -2
  19. package/dist/{canonical-log-line-processor-BQ6NeZAk.js → canonical-log-line-processor-naZRETyk.js} +1 -2
  20. package/dist/{channel-D0eaVqn3.cjs → channel-3MV-4Aqv.cjs} +1 -1
  21. package/dist/{channel-BobQKsZd.js → channel-BNFp4Sfq.js} +1 -1
  22. package/dist/config.d.cts +1 -1
  23. package/dist/config.d.ts +1 -1
  24. package/dist/{correlated-events-BfpH5uS-.js → correlated-events-CZFe6Z1P.js} +1 -1
  25. package/dist/{correlated-events-DE_4A3oD.cjs → correlated-events-wCrXVUby.cjs} +1 -1
  26. package/dist/correlation-id.cjs +1 -1
  27. package/dist/correlation-id.js +1 -1
  28. package/dist/db.cjs +1 -1
  29. package/dist/db.js +1 -1
  30. package/dist/decorators.cjs +2 -2
  31. package/dist/decorators.d.cts +1 -1
  32. package/dist/decorators.d.ts +1 -1
  33. package/dist/decorators.js +2 -2
  34. package/dist/diagnostics.cjs +3 -3
  35. package/dist/diagnostics.js +3 -3
  36. package/dist/event.cjs +1 -1
  37. package/dist/event.d.cts +1 -1
  38. package/dist/event.d.ts +1 -1
  39. package/dist/event.js +1 -1
  40. package/dist/exception-fingerprint.cjs +1 -1
  41. package/dist/exception-fingerprint.js +1 -1
  42. package/dist/{functional-C4gGiBou.js → functional-7uwlAIJd.js} +4 -4
  43. package/dist/{functional-j8Joyrwd.d.cts → functional-CN_cqIX8.d.cts} +9 -2
  44. package/dist/{functional-DptEM9La.cjs → functional-DCfOaKoM.cjs} +4 -4
  45. package/dist/{functional-CbcInXMJ.d.ts → functional-IGZ-Urlq.d.ts} +9 -2
  46. package/dist/functional.cjs +1 -1
  47. package/dist/functional.d.cts +1 -1
  48. package/dist/functional.d.ts +1 -1
  49. package/dist/functional.js +1 -1
  50. package/dist/http.cjs +2 -2
  51. package/dist/http.js +2 -2
  52. package/dist/index.cjs +9 -8
  53. package/dist/index.d.cts +31 -7
  54. package/dist/index.d.ts +31 -7
  55. package/dist/index.js +9 -9
  56. package/dist/{init-Biyby8Br.d.ts → init-BYq2sUXg.d.ts} +26 -31
  57. package/dist/{init-BvUtwZNx.js → init-D4TpmUIg.js} +142 -27
  58. package/dist/{init-Cx1-ejLn.cjs → init-DlJvp1WH.cjs} +147 -26
  59. package/dist/{init-CHanKvOq.d.cts → init-axM4kgR4.d.cts} +26 -31
  60. package/dist/instrumentation.cjs +2 -2
  61. package/dist/instrumentation.js +2 -2
  62. package/dist/{logger-B2VPcBgZ.js → logger-4VXLbqWx.js} +11 -19
  63. package/dist/{logger-DLjHQAus.cjs → logger-CWFxTLtR.cjs} +11 -19
  64. package/dist/{logger-C9UT1aZ_.d.cts → logger-b0qgWFy7.d.cts} +10 -18
  65. package/dist/{logger-C9UT1aZ_.d.ts → logger-b0qgWFy7.d.ts} +10 -18
  66. package/dist/logger.cjs +1 -1
  67. package/dist/logger.d.cts +1 -1
  68. package/dist/logger.d.ts +1 -1
  69. package/dist/logger.js +1 -1
  70. package/dist/messaging-adapters.cjs +1 -1
  71. package/dist/messaging-adapters.js +1 -1
  72. package/dist/messaging.cjs +4 -4
  73. package/dist/messaging.js +4 -4
  74. package/dist/metric.d.cts +1 -1
  75. package/dist/metric.d.ts +1 -1
  76. package/dist/{node-require-BPsB09eC.cjs → node-require-BotQNkYw.cjs} +1 -1
  77. package/dist/{node-require-CkK_xzL-.js → node-require-CY0YUdvZ.js} +1 -1
  78. package/dist/parse-error.cjs +1 -1
  79. package/dist/parse-error.js +1 -1
  80. package/dist/policy.cjs +0 -0
  81. package/dist/policy.js +0 -0
  82. package/dist/processors.cjs +1 -1
  83. package/dist/processors.d.cts +1 -1
  84. package/dist/processors.d.ts +1 -1
  85. package/dist/processors.js +1 -1
  86. package/dist/register.cjs +1 -0
  87. package/dist/register.js +1 -0
  88. package/dist/{sampling-Dud4XU2m.d.cts → sampling-CLJmXMw0.d.cts} +1 -1
  89. package/dist/{sampling-B_8orhSB.d.ts → sampling-DBlX8Nv5.d.ts} +1 -1
  90. package/dist/sampling.cjs +1 -1
  91. package/dist/sampling.d.cts +1 -1
  92. package/dist/sampling.d.ts +1 -1
  93. package/dist/sampling.js +1 -1
  94. package/dist/semantic-helpers.cjs +2 -2
  95. package/dist/semantic-helpers.js +2 -2
  96. package/dist/{stable-hash-sLi1o4jj.cjs → stable-hash-58iP5-N-.cjs} +1 -1
  97. package/dist/{stable-hash-AOUgw1DW.js → stable-hash-DVEU2MqW.js} +1 -1
  98. package/dist/{structured-error-DynjWTTu.cjs → structured-error-Ci8s_M6u.cjs} +6 -6
  99. package/dist/{structured-error-Y9y-1Pae.js → structured-error-UEtlg9Uu.js} +6 -6
  100. package/dist/tail-sampling-processor.cjs +1 -1
  101. package/dist/tail-sampling-processor.js +1 -1
  102. package/dist/test-span-collector.cjs +1 -1
  103. package/dist/test-span-collector.js +1 -1
  104. package/dist/testing.cjs +11 -1
  105. package/dist/testing.d.cts +1 -1
  106. package/dist/testing.d.ts +1 -1
  107. package/dist/testing.js +12 -2
  108. package/dist/trace-helpers.cjs +2 -2
  109. package/dist/trace-helpers.js +2 -2
  110. package/dist/tracer-provider.cjs +1 -1
  111. package/dist/tracer-provider.js +1 -1
  112. package/dist/validate.cjs +3 -3
  113. package/dist/validate.js +3 -3
  114. package/dist/{values-AxGpgYBA.cjs → values-9A6nOyZm.cjs} +69 -3
  115. package/dist/{values-xBtdXtjA.js → values-Dm0yEC5p.js} +58 -4
  116. package/dist/webhook.cjs +3 -3
  117. package/dist/webhook.js +3 -3
  118. package/dist/workflow-distributed.cjs +3 -3
  119. package/dist/workflow-distributed.js +3 -3
  120. package/dist/workflow.cjs +3 -3
  121. package/dist/workflow.js +3 -3
  122. package/dist/yaml-config.cjs +1 -1
  123. package/dist/yaml-config.d.cts +2 -2
  124. package/dist/yaml-config.d.ts +2 -2
  125. package/dist/yaml-config.js +1 -1
  126. package/package.json +1 -1
@@ -1,15 +1,15 @@
1
- import { _ as readProperty, d as asStringRecord, f as describeValue, h as isFunction, i as asNumber, l as asString, r as asFunction, s as asRecord, t as asBoolean } from "./values-xBtdXtjA.js";
1
+ import { d as asStringRecord, f as describeValue, g as isFunction, i as asNumber, l as asString, r as asFunction, s as asRecord, t as asBoolean, v as readProperty } from "./values-Dm0yEC5p.js";
2
2
  import { getForceFlushableProvider } from "./tracer-provider.js";
3
3
  import { getConfig as getConfig$1 } from "./config.js";
4
- import { a as flattenToAttributes, o as toAttributeValue, r as recordStructuredError } from "./structured-error-Y9y-1Pae.js";
5
- import { n as safeRequire, t as requireModule } from "./node-require-CkK_xzL-.js";
4
+ import { a as flattenToAttributes, o as toAttributeValue, r as recordStructuredError } from "./structured-error-UEtlg9Uu.js";
5
+ import { n as safeRequire, t as requireModule } from "./node-require-CY0YUdvZ.js";
6
6
  import { FilteringSpanProcessor } from "./filtering-span-processor.js";
7
7
  import { PolicyLogRecordProcessor, policySpanFilter, setPolicies, watchPolicyFile } from "./policy.js";
8
8
  import { SpanNameNormalizingProcessor } from "./span-name-normalizer.js";
9
9
  import { AttributeRedactingProcessor, REDACTOR_PRESETS, normalizeAttributeRedactorConfig } from "./attribute-redacting-processor.js";
10
10
  import { t as PrettyConsoleExporter } from "./pretty-console-exporter-DqKl_q9z.js";
11
- import { t as CanonicalLogLineProcessor } from "./canonical-log-line-processor-BQ6NeZAk.js";
12
- import { n as subscribeChannel } from "./channel-BobQKsZd.js";
11
+ import { t as CanonicalLogLineProcessor } from "./canonical-log-line-processor-naZRETyk.js";
12
+ import { n as subscribeChannel } from "./channel-BNFp4Sfq.js";
13
13
  import { resetMetrics } from "./metric.js";
14
14
  import { DiagConsoleLogger, DiagLogLevel, TraceFlags, context, createContextKey, diag, metrics, propagation, trace } from "@opentelemetry/api";
15
15
  import { logs } from "@opentelemetry/api-logs";
@@ -1959,15 +1959,15 @@ const silentLogger = {
1959
1959
  function wrapLogger(base, silent, minLevel) {
1960
1960
  if (silent) return silentLogger;
1961
1961
  const threshold = LOG_LEVELS[minLevel];
1962
- const wrap = (fn, level) => {
1962
+ const wrap = (level) => {
1963
1963
  if (LOG_LEVELS[level] < threshold) return (() => {});
1964
- return ((...args) => fn(...args));
1964
+ return ((...args) => base[level](...args));
1965
1965
  };
1966
1966
  return {
1967
- debug: wrap(base.debug, "debug"),
1968
- info: wrap(base.info, "info"),
1969
- warn: wrap(base.warn, "warn"),
1970
- error: wrap(base.error, "error")
1967
+ debug: wrap("debug"),
1968
+ info: wrap("info"),
1969
+ warn: wrap("warn"),
1970
+ error: wrap("error")
1971
1971
  };
1972
1972
  }
1973
1973
 
@@ -2168,6 +2168,47 @@ var RequestAttributesSpanProcessor = class {
2168
2168
  }
2169
2169
  };
2170
2170
 
2171
+ //#endregion
2172
+ //#region src/enriched-span-processor.ts
2173
+ /**
2174
+ * `spanEnrichers` in front of the processors that export, as one processor.
2175
+ *
2176
+ * Spans reach the enrichers first, as they would in a flat list. The
2177
+ * difference is flush and shutdown: the SDK runs those on every processor at
2178
+ * once, so an enricher that ends a span of its own while it drains (an async
2179
+ * judgment, say) would hand it to an exporter that had already closed. Here the
2180
+ * enrichers drain first and the exporters flush after them.
2181
+ */
2182
+ var EnrichedSpanProcessor = class {
2183
+ enrichers;
2184
+ downstream;
2185
+ /** Every processor in call order: the enrichers, then the rest. */
2186
+ processors;
2187
+ constructor(enrichers, downstream) {
2188
+ this.enrichers = enrichers;
2189
+ this.downstream = downstream;
2190
+ this.processors = [...enrichers, ...downstream];
2191
+ }
2192
+ onStart(span, parentContext) {
2193
+ for (const processor of this.processors) processor.onStart(span, parentContext);
2194
+ }
2195
+ onEnd(span) {
2196
+ for (const processor of this.processors) processor.onEnd(span);
2197
+ }
2198
+ forceFlush() {
2199
+ return this.drainThenRun((p) => p.forceFlush());
2200
+ }
2201
+ shutdown() {
2202
+ return this.drainThenRun((p) => p.shutdown());
2203
+ }
2204
+ async drainThenRun(run) {
2205
+ const drained = await Promise.allSettled(this.enrichers.map(async (p) => run(p)));
2206
+ await Promise.all(this.downstream.map(run));
2207
+ const failed = drained.find((r) => r.status === "rejected");
2208
+ if (failed) throw failed.reason;
2209
+ }
2210
+ };
2211
+
2171
2212
  //#endregion
2172
2213
  //#region src/redact-values.ts
2173
2214
  /** Standalone string redaction for use outside the span processor pipeline. */
@@ -4137,20 +4178,68 @@ function toPackageName(name) {
4137
4178
  return name.startsWith("@opentelemetry/instrumentation-") ? name : `@opentelemetry/instrumentation-${name}`;
4138
4179
  }
4139
4180
  /**
4140
- * Detect if we're running in ESM mode
4181
+ * Whether the app's entry runs as ESM: its extension when it has an explicit
4182
+ * one (`.mjs`/`.cjs`, and `.mts`/`.cts` under tsx), else the cwd
4183
+ * package.json's `type`.
4141
4184
  */
4142
- function isESMMode() {
4185
+ function isESMMode(entry = process.argv[1] ?? "") {
4186
+ if (/\.c[jt]s$/.test(entry)) return false;
4187
+ if (/\.m[jt]s$/.test(entry)) return true;
4143
4188
  try {
4144
4189
  const fs = requireModule("node:fs");
4145
- try {
4146
- return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).type === "module";
4147
- } catch {
4148
- return false;
4149
- }
4190
+ return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).type === "module";
4150
4191
  } catch {
4151
4192
  return false;
4152
4193
  }
4153
4194
  }
4195
+ /** Set by `autotel/register` so `init()` can tell the ESM hook is in place. */
4196
+ const REGISTER_FLAG = Symbol.for("autotel.register");
4197
+ /**
4198
+ * Whether the OTel ESM loader hook is registered: by `autotel/register`, or
4199
+ * by pointing node at a `hook.mjs` directly.
4200
+ */
4201
+ function isEsmHookLoaded(flags = `${process.execArgv.join(" ")} ${process.env.NODE_OPTIONS ?? ""}`) {
4202
+ return globalThis[REGISTER_FLAG] === true || flags.includes("hook.mjs");
4203
+ }
4204
+ const LOGGER_PACKAGES = [
4205
+ "pino",
4206
+ "winston",
4207
+ "bunyan"
4208
+ ];
4209
+ function loadedModulePaths() {
4210
+ try {
4211
+ const { createRequire } = requireModule("node:module");
4212
+ return Object.entries(createRequire(`${process.cwd()}/`).cache).filter(([, mod]) => mod?.loaded).map(([path]) => path);
4213
+ } catch {
4214
+ return [];
4215
+ }
4216
+ }
4217
+ /**
4218
+ * Names in the array form that loaded nothing: a typo, or a library
4219
+ * auto-instrumentations-node has no instrumentation for (`fastify`, `next`).
4220
+ * Upstream only reports these through `diag`, which is silent by default.
4221
+ * Names a manual instrumentation replaced are not missing.
4222
+ */
4223
+ function missingInstrumentations(names, loaded, manualInstrumentationNames = /* @__PURE__ */ new Set()) {
4224
+ const loadedNames = new Set(loaded.map((i) => i.instrumentationName));
4225
+ const replaced = new Set([...manualInstrumentationNames].map((className) => INSTRUMENTATION_CLASS_TO_PACKAGE.get(className)));
4226
+ return names.filter((name) => {
4227
+ const packageName = toPackageName(name);
4228
+ return !loadedNames.has(packageName) && !replaced.has(packageName);
4229
+ });
4230
+ }
4231
+ /**
4232
+ * Logger packages the config instruments that were already loaded when
4233
+ * `init()` ran. Instrumentations patch a package as it loads, so these never
4234
+ * get trace context: the logger module was imported before `init()`.
4235
+ */
4236
+ function loggersLoadedBeforeInit(integrations, loadedPaths = loadedModulePaths()) {
4237
+ if (integrations === false) return [];
4238
+ const requested = integrations === true ? LOGGER_PACKAGES : Array.isArray(integrations) ? integrations : Object.entries(integrations).filter(([, options]) => options.enabled !== false).map(([name]) => name);
4239
+ const wanted = new Set(requested.map((name) => toPackageName(name)));
4240
+ const paths = loadedPaths.map((path) => path.replaceAll("\\", "/"));
4241
+ return LOGGER_PACKAGES.filter((name) => wanted.has(toPackageName(name)) && paths.some((path) => path.includes(`/node_modules/${name}/`)));
4242
+ }
4154
4243
  /**
4155
4244
  * Lazy-load auto-instrumentations (optional peer dependency)
4156
4245
  * Only loads when integrations config is truthy, avoiding ~40+ package imports at startup.
@@ -4179,11 +4268,12 @@ See: https://github.com/jagreehal/autotel#esm-setup`);
4179
4268
  * @internal
4180
4269
  */
4181
4270
  let _autoInstrumentationsLoader = null;
4271
+ const HTTP_PACKAGE = "@opentelemetry/instrumentation-http";
4182
4272
  /**
4183
4273
  * Get auto-instrumentations based on simple integration names
4184
4274
  * Excludes instrumentations that are manually provided to avoid conflicts
4185
4275
  */
4186
- function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @__PURE__ */ new Set()) {
4276
+ function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @__PURE__ */ new Set(), ignoredServerPorts = []) {
4187
4277
  if (integrations === false) return [];
4188
4278
  const getNodeAutoInstrumentations = _autoInstrumentationsLoader ? _autoInstrumentationsLoader() : loadNodeAutoInstrumentations();
4189
4279
  const exclusionConfig = {};
@@ -4198,7 +4288,18 @@ function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @
4198
4288
  if (packageName in exclusionConfig) continue;
4199
4289
  config[packageName] = options;
4200
4290
  }
4201
- return getNodeAutoInstrumentations(withAutotelDefaults(config));
4291
+ const http = config[HTTP_PACKAGE] ?? {};
4292
+ if (ignoredServerPorts.length > 0 && http.enabled !== false) {
4293
+ const userHook = http.ignoreIncomingRequestHook;
4294
+ config[HTTP_PACKAGE] = {
4295
+ ...http,
4296
+ ignoreIncomingRequestHook: (request) => ignoredServerPorts.includes(request.socket?.localPort ?? -1) || (userHook?.(request) ?? false)
4297
+ };
4298
+ }
4299
+ const resolved = withAutotelDefaults(config);
4300
+ if (!Array.isArray(integrations)) return getNodeAutoInstrumentations(resolved);
4301
+ const listed = new Set(Object.keys(config).filter((name) => config[name]?.enabled === true));
4302
+ return getNodeAutoInstrumentations(new Proxy(resolved, { get: (target, name) => typeof name === "string" && listed.has(name) ? target[name] : { enabled: false } }));
4202
4303
  }
4203
4304
 
4204
4305
  //#endregion
@@ -4363,6 +4464,10 @@ function init(cfg) {
4363
4464
  const minLevel = mergedConfig.minLevel ?? "info";
4364
4465
  const baseLogger = mergedConfig.logger || silentLogger;
4365
4466
  logger = wrapLogger(baseLogger, silent, minLevel);
4467
+ const setupWarn = (msg) => {
4468
+ if (mergedConfig.logger) logger.warn({}, msg);
4469
+ else if (!silent) console.warn(msg);
4470
+ };
4366
4471
  if (initialized) logger.warn({}, "[autotel] init() called again - last config wins. This may cause unexpected behavior.");
4367
4472
  config = mergedConfig;
4368
4473
  validationConfig = mergedConfig.validation || null;
@@ -4371,19 +4476,24 @@ function init(cfg) {
4371
4476
  const version = mergedConfig.version || detectVersion();
4372
4477
  const environment = mergedConfig.environment || process.env.NODE_ENV || "development";
4373
4478
  const metricsEnabled = resolveMetricsFlag(mergedConfig.metrics);
4374
- const canonicalLogger = mergedConfig.canonicalLogLines?.logger ?? mergedConfig.logger;
4479
+ const canonicalLogger = mergedConfig.canonicalLogLines?.logger;
4375
4480
  const hasCanonicalLogger = Array.isArray(canonicalLogger) ? canonicalLogger.length > 0 : canonicalLogger !== void 0;
4376
4481
  const canonicalUsesOtel = mergedConfig.canonicalLogLines?.enabled === true && (mergedConfig.canonicalLogLines.otel ?? !hasCanonicalLogger);
4377
4482
  const logsEnabled = resolveLogsFlag(mergedConfig.logs ?? (canonicalUsesOtel ? true : "auto"));
4483
+ let devtoolsPort;
4378
4484
  if (devtoolsConfig.enabled && devtoolsConfig.embedded) {
4379
4485
  const devtoolsModule = _optionalRequire("autotel-devtools");
4380
4486
  if (devtoolsModule?.createDevtools) {
4487
+ if (devtoolsConfig.port === 0) throw new Error("[autotel] devtools.embedded needs a fixed devtools.port; 0 is not supported");
4381
4488
  const devtoolsInstance = devtoolsModule.createDevtools({
4382
4489
  port: devtoolsConfig.port,
4383
4490
  host: devtoolsConfig.host,
4384
- verbose: devtoolsConfig.verbose
4491
+ verbose: devtoolsConfig.verbose,
4492
+ maxPortTries: 1
4385
4493
  });
4494
+ devtoolsInstance.ready?.catch((error) => setupWarn(`[autotel] autotel-devtools could not start (${error instanceof Error ? error.message : String(error)}). Telemetry is still sent to ${endpoint}; free the port or set devtools.port.`));
4386
4495
  _devtoolsClose = devtoolsInstance.close;
4496
+ devtoolsPort = devtoolsInstance.port;
4387
4497
  endpoint = `http://${devtoolsConfig.host}:${devtoolsInstance.port}`;
4388
4498
  logger.info({}, `[autotel] autotel-devtools embedded server started at ${endpoint}`);
4389
4499
  } else logger.warn({}, "[autotel] devtools.embedded requested but autotel-devtools is not installed. Falling back to endpoint-only mode.");
@@ -4455,7 +4565,7 @@ function init(cfg) {
4455
4565
  }
4456
4566
  if (mergedConfig.spanFilter && spanProcessors.length > 0) spanProcessors = spanProcessors.map((processor) => new FilteringSpanProcessor(processor, { filter: mergedConfig.spanFilter }));
4457
4567
  if (spanProcessors.length > 0) spanProcessors.unshift(new RequestAttributesSpanProcessor());
4458
- if (mergedConfig.spanEnrichers && mergedConfig.spanEnrichers.length > 0) spanProcessors.unshift(...mergedConfig.spanEnrichers);
4568
+ if (mergedConfig.spanEnrichers && mergedConfig.spanEnrichers.length > 0) spanProcessors = [new EnrichedSpanProcessor(mergedConfig.spanEnrichers, spanProcessors)];
4459
4569
  const metricReaders = [];
4460
4570
  if (configuredMetricReaders && configuredMetricReaders.length > 0) metricReaders.push(...configuredMetricReaders);
4461
4571
  else if (metricsEnabled) for (const destination of otlpDestinations) {
@@ -4496,17 +4606,22 @@ function init(cfg) {
4496
4606
  if (mergedConfig.policies && logRecordProcessors) logRecordProcessors = logRecordProcessors.map((processor) => new PolicyLogRecordProcessor(processor));
4497
4607
  let finalInstrumentations = mergedConfig.instrumentations ? [...mergedConfig.instrumentations] : [];
4498
4608
  if (mergedConfig.autoInstrumentations !== void 0 && mergedConfig.autoInstrumentations !== false) {
4499
- if (isESMMode()) logger.info({}, "[autotel] ESM mode detected. For auto-instrumentation to work:\n 1. Install @opentelemetry/auto-instrumentations-node as a direct dependency\n 2. Import autotel/register FIRST in your instrumentation file\n 3. Use getNodeAutoInstrumentations() directly instead of autoInstrumentations\n See: https://github.com/jagreehal/autotel#esm-setup");
4609
+ if (isESMMode() && !isEsmHookLoaded()) setupWarn("[autotel] ESM app without the OTel loader hook: packages loaded with `import` (pino, express, ...) will not be instrumented. Start node with `--import autotel/register`. See: https://github.com/jagreehal/autotel#esm-setup");
4610
+ for (const name of loggersLoadedBeforeInit(mergedConfig.autoInstrumentations)) setupWarn(`[autotel] ${name} was loaded before init(), so its logs get no trace context. Run init() first, and don't create your ${name} logger in the module that calls it.`);
4500
4611
  try {
4501
4612
  const manualInstrumentationNames = getInstrumentationNames(mergedConfig.instrumentations ?? []);
4502
4613
  if (manualInstrumentationNames.size > 0) {
4503
4614
  const manualNames = [...manualInstrumentationNames].join(", ");
4504
4615
  logger.info({}, `[autotel] Detected manual instrumentations (${manualNames}). These will take precedence over auto-instrumentations. Tip: Set autoInstrumentations:false if you want full manual control, or remove manual configs to use auto-instrumentations.`);
4505
4616
  }
4506
- const autoInstrumentations = getAutoInstrumentations(mergedConfig.autoInstrumentations, manualInstrumentationNames);
4617
+ const autoInstrumentations = getAutoInstrumentations(mergedConfig.autoInstrumentations, manualInstrumentationNames, devtoolsPort === void 0 ? [] : [devtoolsPort]);
4618
+ if (Array.isArray(mergedConfig.autoInstrumentations)) {
4619
+ const missing = missingInstrumentations(mergedConfig.autoInstrumentations, autoInstrumentations ?? [], manualInstrumentationNames);
4620
+ if (missing.length > 0) setupWarn(`[autotel] autoInstrumentations: no instrumentation loaded for ${missing.join(", ")}. Check the spelling; @opentelemetry/auto-instrumentations-node has none for some libraries (fastify, next).`);
4621
+ }
4507
4622
  if (autoInstrumentations && autoInstrumentations.length > 0) finalInstrumentations = [...finalInstrumentations, ...autoInstrumentations];
4508
4623
  } catch (error) {
4509
- logger.warn({}, `[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`);
4624
+ setupWarn(`[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`);
4510
4625
  }
4511
4626
  }
4512
4627
  const autotelSampler = mergedConfig.sampler ?? (mergedConfig.sampling ? resolveSamplingPreset(mergedConfig.sampling) : void 0);
@@ -4623,4 +4738,4 @@ function getSdk() {
4623
4738
  }
4624
4739
 
4625
4740
  //#endregion
4626
- export { generateCorrelationId as $, CompositeSampler as A, hashUnitInterval as B, TailSamplingSpanProcessor as C, AUTOTEL_SAMPLING_TAIL_KEEP as D, AUTOTEL_SAMPLING_TAIL_EVALUATED as E, RandomSampler as F, createTraceContext as G, markForceKept as H, UserIdSampler as I, getActiveContextWithBaggage as J, defineBaggageSchema as K, createLinkFromHeaders as L, FeatureFlagSampler as M, KeyTargetRateSampler as N, AdaptiveSampler as O, NeverSampler as P, CORRELATION_ID_BAGGAGE_KEY as Q, debugCaptureRequested as R, BaggageSpanProcessor as S, AUTOTEL_SAMPLING_RATE as T, resolveSamplingPreset as U, isForceKept as V, samplingPresets as W, getEventQueue as X, getContextStorage as Y, track as Z, loadYamlConfig as _, init as a, setCorrelationIdInBaggage as at, getRequestSpanIn as b, lockLogger as c, Event as d, getCorrelationId as et, getEvents as f, hasYamlConfig as g, runInOperationContext as h, getSdk as i, setCorrelationId as it, DeterministicSampler as j, AlwaysSampler as k, flush as l, getOperationContext as m, getConfiguredSampler as n, getOrCreateCorrelationId as nt, isInitialized as o, resetEvents as p, explicitSpanStatus as q, getLogger as r, runWithCorrelationId as rt, isLoggerLocked as s, getConfig as t, getCorrelationStorage as tt, shutdown as u, loadYamlConfigFromFile as v, AUTOTEL_DEBUG_BAGGAGE_KEY as w, rememberRequestAttributes as x, createStringRedactor as y, extractLinksFromBatch as z };
4741
+ export { CORRELATION_ID_BAGGAGE_KEY as $, AlwaysSampler as A, extractLinksFromBatch as B, BaggageSpanProcessor as C, AUTOTEL_SAMPLING_TAIL_EVALUATED as D, AUTOTEL_SAMPLING_RATE as E, NeverSampler as F, samplingPresets as G, isForceKept as H, RandomSampler as I, explicitSpanStatus as J, createTraceContext as K, UserIdSampler as L, DeterministicSampler as M, FeatureFlagSampler as N, AUTOTEL_SAMPLING_TAIL_KEEP as O, KeyTargetRateSampler as P, track as Q, createLinkFromHeaders as R, rememberRequestAttributes as S, AUTOTEL_DEBUG_BAGGAGE_KEY as T, markForceKept as U, hashUnitInterval as V, resolveSamplingPreset as W, getContextStorage as X, getActiveContextWithBaggage as Y, getEventQueue as Z, loadYamlConfig as _, init as a, setCorrelationId as at, EnrichedSpanProcessor as b, lockLogger as c, Event as d, generateCorrelationId as et, getEvents as f, hasYamlConfig as g, runInOperationContext as h, getSdk as i, runWithCorrelationId as it, CompositeSampler as j, AdaptiveSampler as k, flush as l, getOperationContext as m, getConfiguredSampler as n, getCorrelationStorage as nt, isInitialized as o, setCorrelationIdInBaggage as ot, resetEvents as p, defineBaggageSchema as q, getLogger as r, getOrCreateCorrelationId as rt, isLoggerLocked as s, getConfig as t, getCorrelationId as tt, shutdown as u, loadYamlConfigFromFile as v, TailSamplingSpanProcessor as w, getRequestSpanIn as x, createStringRedactor as y, debugCaptureRequested as z };
@@ -1,16 +1,16 @@
1
1
  const require_rolldown_runtime = require('./rolldown-runtime-C24Yb2bl.cjs');
2
- const require_values = require('./values-AxGpgYBA.cjs');
2
+ const require_values = require('./values-9A6nOyZm.cjs');
3
3
  const require_tracer_provider = require('./tracer-provider.cjs');
4
4
  const require_config = require('./config.cjs');
5
- const require_structured_error = require('./structured-error-DynjWTTu.cjs');
6
- const require_node_require = require('./node-require-BPsB09eC.cjs');
5
+ const require_structured_error = require('./structured-error-Ci8s_M6u.cjs');
6
+ const require_node_require = require('./node-require-BotQNkYw.cjs');
7
7
  const require_filtering_span_processor = require('./filtering-span-processor.cjs');
8
8
  const require_policy = require('./policy.cjs');
9
9
  const require_span_name_normalizer = require('./span-name-normalizer.cjs');
10
10
  const require_attribute_redacting_processor = require('./attribute-redacting-processor.cjs');
11
11
  const require_pretty_console_exporter = require('./pretty-console-exporter-CMzlrRNg.cjs');
12
- const require_canonical_log_line_processor = require('./canonical-log-line-processor-BU03jJeA.cjs');
13
- const require_channel = require('./channel-D0eaVqn3.cjs');
12
+ const require_canonical_log_line_processor = require('./canonical-log-line-processor-DScNq1g8.cjs');
13
+ const require_channel = require('./channel-3MV-4Aqv.cjs');
14
14
  const require_metric = require('./metric.cjs');
15
15
  let _opentelemetry_api = require("@opentelemetry/api");
16
16
  let _opentelemetry_api_logs = require("@opentelemetry/api-logs");
@@ -1964,15 +1964,15 @@ const silentLogger = {
1964
1964
  function wrapLogger(base, silent, minLevel) {
1965
1965
  if (silent) return silentLogger;
1966
1966
  const threshold = LOG_LEVELS[minLevel];
1967
- const wrap = (fn, level) => {
1967
+ const wrap = (level) => {
1968
1968
  if (LOG_LEVELS[level] < threshold) return (() => {});
1969
- return ((...args) => fn(...args));
1969
+ return ((...args) => base[level](...args));
1970
1970
  };
1971
1971
  return {
1972
- debug: wrap(base.debug, "debug"),
1973
- info: wrap(base.info, "info"),
1974
- warn: wrap(base.warn, "warn"),
1975
- error: wrap(base.error, "error")
1972
+ debug: wrap("debug"),
1973
+ info: wrap("info"),
1974
+ warn: wrap("warn"),
1975
+ error: wrap("error")
1976
1976
  };
1977
1977
  }
1978
1978
 
@@ -2173,6 +2173,47 @@ var RequestAttributesSpanProcessor = class {
2173
2173
  }
2174
2174
  };
2175
2175
 
2176
+ //#endregion
2177
+ //#region src/enriched-span-processor.ts
2178
+ /**
2179
+ * `spanEnrichers` in front of the processors that export, as one processor.
2180
+ *
2181
+ * Spans reach the enrichers first, as they would in a flat list. The
2182
+ * difference is flush and shutdown: the SDK runs those on every processor at
2183
+ * once, so an enricher that ends a span of its own while it drains (an async
2184
+ * judgment, say) would hand it to an exporter that had already closed. Here the
2185
+ * enrichers drain first and the exporters flush after them.
2186
+ */
2187
+ var EnrichedSpanProcessor = class {
2188
+ enrichers;
2189
+ downstream;
2190
+ /** Every processor in call order: the enrichers, then the rest. */
2191
+ processors;
2192
+ constructor(enrichers, downstream) {
2193
+ this.enrichers = enrichers;
2194
+ this.downstream = downstream;
2195
+ this.processors = [...enrichers, ...downstream];
2196
+ }
2197
+ onStart(span, parentContext) {
2198
+ for (const processor of this.processors) processor.onStart(span, parentContext);
2199
+ }
2200
+ onEnd(span) {
2201
+ for (const processor of this.processors) processor.onEnd(span);
2202
+ }
2203
+ forceFlush() {
2204
+ return this.drainThenRun((p) => p.forceFlush());
2205
+ }
2206
+ shutdown() {
2207
+ return this.drainThenRun((p) => p.shutdown());
2208
+ }
2209
+ async drainThenRun(run) {
2210
+ const drained = await Promise.allSettled(this.enrichers.map(async (p) => run(p)));
2211
+ await Promise.all(this.downstream.map(run));
2212
+ const failed = drained.find((r) => r.status === "rejected");
2213
+ if (failed) throw failed.reason;
2214
+ }
2215
+ };
2216
+
2176
2217
  //#endregion
2177
2218
  //#region src/redact-values.ts
2178
2219
  /** Standalone string redaction for use outside the span processor pipeline. */
@@ -4142,20 +4183,68 @@ function toPackageName(name) {
4142
4183
  return name.startsWith("@opentelemetry/instrumentation-") ? name : `@opentelemetry/instrumentation-${name}`;
4143
4184
  }
4144
4185
  /**
4145
- * Detect if we're running in ESM mode
4186
+ * Whether the app's entry runs as ESM: its extension when it has an explicit
4187
+ * one (`.mjs`/`.cjs`, and `.mts`/`.cts` under tsx), else the cwd
4188
+ * package.json's `type`.
4146
4189
  */
4147
- function isESMMode() {
4190
+ function isESMMode(entry = process.argv[1] ?? "") {
4191
+ if (/\.c[jt]s$/.test(entry)) return false;
4192
+ if (/\.m[jt]s$/.test(entry)) return true;
4148
4193
  try {
4149
4194
  const fs = require_node_require.requireModule("node:fs");
4150
- try {
4151
- return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).type === "module";
4152
- } catch {
4153
- return false;
4154
- }
4195
+ return JSON.parse(fs.readFileSync(`${process.cwd()}/package.json`, "utf8")).type === "module";
4155
4196
  } catch {
4156
4197
  return false;
4157
4198
  }
4158
4199
  }
4200
+ /** Set by `autotel/register` so `init()` can tell the ESM hook is in place. */
4201
+ const REGISTER_FLAG = Symbol.for("autotel.register");
4202
+ /**
4203
+ * Whether the OTel ESM loader hook is registered: by `autotel/register`, or
4204
+ * by pointing node at a `hook.mjs` directly.
4205
+ */
4206
+ function isEsmHookLoaded(flags = `${process.execArgv.join(" ")} ${process.env.NODE_OPTIONS ?? ""}`) {
4207
+ return globalThis[REGISTER_FLAG] === true || flags.includes("hook.mjs");
4208
+ }
4209
+ const LOGGER_PACKAGES = [
4210
+ "pino",
4211
+ "winston",
4212
+ "bunyan"
4213
+ ];
4214
+ function loadedModulePaths() {
4215
+ try {
4216
+ const { createRequire } = require_node_require.requireModule("node:module");
4217
+ return Object.entries(createRequire(`${process.cwd()}/`).cache).filter(([, mod]) => mod?.loaded).map(([path]) => path);
4218
+ } catch {
4219
+ return [];
4220
+ }
4221
+ }
4222
+ /**
4223
+ * Names in the array form that loaded nothing: a typo, or a library
4224
+ * auto-instrumentations-node has no instrumentation for (`fastify`, `next`).
4225
+ * Upstream only reports these through `diag`, which is silent by default.
4226
+ * Names a manual instrumentation replaced are not missing.
4227
+ */
4228
+ function missingInstrumentations(names, loaded, manualInstrumentationNames = /* @__PURE__ */ new Set()) {
4229
+ const loadedNames = new Set(loaded.map((i) => i.instrumentationName));
4230
+ const replaced = new Set([...manualInstrumentationNames].map((className) => INSTRUMENTATION_CLASS_TO_PACKAGE.get(className)));
4231
+ return names.filter((name) => {
4232
+ const packageName = toPackageName(name);
4233
+ return !loadedNames.has(packageName) && !replaced.has(packageName);
4234
+ });
4235
+ }
4236
+ /**
4237
+ * Logger packages the config instruments that were already loaded when
4238
+ * `init()` ran. Instrumentations patch a package as it loads, so these never
4239
+ * get trace context: the logger module was imported before `init()`.
4240
+ */
4241
+ function loggersLoadedBeforeInit(integrations, loadedPaths = loadedModulePaths()) {
4242
+ if (integrations === false) return [];
4243
+ const requested = integrations === true ? LOGGER_PACKAGES : Array.isArray(integrations) ? integrations : Object.entries(integrations).filter(([, options]) => options.enabled !== false).map(([name]) => name);
4244
+ const wanted = new Set(requested.map((name) => toPackageName(name)));
4245
+ const paths = loadedPaths.map((path) => path.replaceAll("\\", "/"));
4246
+ return LOGGER_PACKAGES.filter((name) => wanted.has(toPackageName(name)) && paths.some((path) => path.includes(`/node_modules/${name}/`)));
4247
+ }
4159
4248
  /**
4160
4249
  * Lazy-load auto-instrumentations (optional peer dependency)
4161
4250
  * Only loads when integrations config is truthy, avoiding ~40+ package imports at startup.
@@ -4184,11 +4273,12 @@ See: https://github.com/jagreehal/autotel#esm-setup`);
4184
4273
  * @internal
4185
4274
  */
4186
4275
  let _autoInstrumentationsLoader = null;
4276
+ const HTTP_PACKAGE = "@opentelemetry/instrumentation-http";
4187
4277
  /**
4188
4278
  * Get auto-instrumentations based on simple integration names
4189
4279
  * Excludes instrumentations that are manually provided to avoid conflicts
4190
4280
  */
4191
- function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @__PURE__ */ new Set()) {
4281
+ function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @__PURE__ */ new Set(), ignoredServerPorts = []) {
4192
4282
  if (integrations === false) return [];
4193
4283
  const getNodeAutoInstrumentations = _autoInstrumentationsLoader ? _autoInstrumentationsLoader() : loadNodeAutoInstrumentations();
4194
4284
  const exclusionConfig = {};
@@ -4203,7 +4293,18 @@ function getAutoInstrumentations(integrations, manualInstrumentationNames = /* @
4203
4293
  if (packageName in exclusionConfig) continue;
4204
4294
  config[packageName] = options;
4205
4295
  }
4206
- return getNodeAutoInstrumentations(withAutotelDefaults(config));
4296
+ const http = config[HTTP_PACKAGE] ?? {};
4297
+ if (ignoredServerPorts.length > 0 && http.enabled !== false) {
4298
+ const userHook = http.ignoreIncomingRequestHook;
4299
+ config[HTTP_PACKAGE] = {
4300
+ ...http,
4301
+ ignoreIncomingRequestHook: (request) => ignoredServerPorts.includes(request.socket?.localPort ?? -1) || (userHook?.(request) ?? false)
4302
+ };
4303
+ }
4304
+ const resolved = withAutotelDefaults(config);
4305
+ if (!Array.isArray(integrations)) return getNodeAutoInstrumentations(resolved);
4306
+ const listed = new Set(Object.keys(config).filter((name) => config[name]?.enabled === true));
4307
+ return getNodeAutoInstrumentations(new Proxy(resolved, { get: (target, name) => typeof name === "string" && listed.has(name) ? target[name] : { enabled: false } }));
4207
4308
  }
4208
4309
 
4209
4310
  //#endregion
@@ -4368,6 +4469,10 @@ function init(cfg) {
4368
4469
  const minLevel = mergedConfig.minLevel ?? "info";
4369
4470
  const baseLogger = mergedConfig.logger || silentLogger;
4370
4471
  logger = wrapLogger(baseLogger, silent, minLevel);
4472
+ const setupWarn = (msg) => {
4473
+ if (mergedConfig.logger) logger.warn({}, msg);
4474
+ else if (!silent) console.warn(msg);
4475
+ };
4371
4476
  if (initialized) logger.warn({}, "[autotel] init() called again - last config wins. This may cause unexpected behavior.");
4372
4477
  config = mergedConfig;
4373
4478
  validationConfig = mergedConfig.validation || null;
@@ -4376,19 +4481,24 @@ function init(cfg) {
4376
4481
  const version = mergedConfig.version || detectVersion();
4377
4482
  const environment = mergedConfig.environment || process.env.NODE_ENV || "development";
4378
4483
  const metricsEnabled = resolveMetricsFlag(mergedConfig.metrics);
4379
- const canonicalLogger = mergedConfig.canonicalLogLines?.logger ?? mergedConfig.logger;
4484
+ const canonicalLogger = mergedConfig.canonicalLogLines?.logger;
4380
4485
  const hasCanonicalLogger = Array.isArray(canonicalLogger) ? canonicalLogger.length > 0 : canonicalLogger !== void 0;
4381
4486
  const canonicalUsesOtel = mergedConfig.canonicalLogLines?.enabled === true && (mergedConfig.canonicalLogLines.otel ?? !hasCanonicalLogger);
4382
4487
  const logsEnabled = resolveLogsFlag(mergedConfig.logs ?? (canonicalUsesOtel ? true : "auto"));
4488
+ let devtoolsPort;
4383
4489
  if (devtoolsConfig.enabled && devtoolsConfig.embedded) {
4384
4490
  const devtoolsModule = _optionalRequire("autotel-devtools");
4385
4491
  if (devtoolsModule?.createDevtools) {
4492
+ if (devtoolsConfig.port === 0) throw new Error("[autotel] devtools.embedded needs a fixed devtools.port; 0 is not supported");
4386
4493
  const devtoolsInstance = devtoolsModule.createDevtools({
4387
4494
  port: devtoolsConfig.port,
4388
4495
  host: devtoolsConfig.host,
4389
- verbose: devtoolsConfig.verbose
4496
+ verbose: devtoolsConfig.verbose,
4497
+ maxPortTries: 1
4390
4498
  });
4499
+ devtoolsInstance.ready?.catch((error) => setupWarn(`[autotel] autotel-devtools could not start (${error instanceof Error ? error.message : String(error)}). Telemetry is still sent to ${endpoint}; free the port or set devtools.port.`));
4391
4500
  _devtoolsClose = devtoolsInstance.close;
4501
+ devtoolsPort = devtoolsInstance.port;
4392
4502
  endpoint = `http://${devtoolsConfig.host}:${devtoolsInstance.port}`;
4393
4503
  logger.info({}, `[autotel] autotel-devtools embedded server started at ${endpoint}`);
4394
4504
  } else logger.warn({}, "[autotel] devtools.embedded requested but autotel-devtools is not installed. Falling back to endpoint-only mode.");
@@ -4460,7 +4570,7 @@ function init(cfg) {
4460
4570
  }
4461
4571
  if (mergedConfig.spanFilter && spanProcessors.length > 0) spanProcessors = spanProcessors.map((processor) => new require_filtering_span_processor.FilteringSpanProcessor(processor, { filter: mergedConfig.spanFilter }));
4462
4572
  if (spanProcessors.length > 0) spanProcessors.unshift(new RequestAttributesSpanProcessor());
4463
- if (mergedConfig.spanEnrichers && mergedConfig.spanEnrichers.length > 0) spanProcessors.unshift(...mergedConfig.spanEnrichers);
4573
+ if (mergedConfig.spanEnrichers && mergedConfig.spanEnrichers.length > 0) spanProcessors = [new EnrichedSpanProcessor(mergedConfig.spanEnrichers, spanProcessors)];
4464
4574
  const metricReaders = [];
4465
4575
  if (configuredMetricReaders && configuredMetricReaders.length > 0) metricReaders.push(...configuredMetricReaders);
4466
4576
  else if (metricsEnabled) for (const destination of otlpDestinations) {
@@ -4501,17 +4611,22 @@ function init(cfg) {
4501
4611
  if (mergedConfig.policies && logRecordProcessors) logRecordProcessors = logRecordProcessors.map((processor) => new require_policy.PolicyLogRecordProcessor(processor));
4502
4612
  let finalInstrumentations = mergedConfig.instrumentations ? [...mergedConfig.instrumentations] : [];
4503
4613
  if (mergedConfig.autoInstrumentations !== void 0 && mergedConfig.autoInstrumentations !== false) {
4504
- if (isESMMode()) logger.info({}, "[autotel] ESM mode detected. For auto-instrumentation to work:\n 1. Install @opentelemetry/auto-instrumentations-node as a direct dependency\n 2. Import autotel/register FIRST in your instrumentation file\n 3. Use getNodeAutoInstrumentations() directly instead of autoInstrumentations\n See: https://github.com/jagreehal/autotel#esm-setup");
4614
+ if (isESMMode() && !isEsmHookLoaded()) setupWarn("[autotel] ESM app without the OTel loader hook: packages loaded with `import` (pino, express, ...) will not be instrumented. Start node with `--import autotel/register`. See: https://github.com/jagreehal/autotel#esm-setup");
4615
+ for (const name of loggersLoadedBeforeInit(mergedConfig.autoInstrumentations)) setupWarn(`[autotel] ${name} was loaded before init(), so its logs get no trace context. Run init() first, and don't create your ${name} logger in the module that calls it.`);
4505
4616
  try {
4506
4617
  const manualInstrumentationNames = getInstrumentationNames(mergedConfig.instrumentations ?? []);
4507
4618
  if (manualInstrumentationNames.size > 0) {
4508
4619
  const manualNames = [...manualInstrumentationNames].join(", ");
4509
4620
  logger.info({}, `[autotel] Detected manual instrumentations (${manualNames}). These will take precedence over auto-instrumentations. Tip: Set autoInstrumentations:false if you want full manual control, or remove manual configs to use auto-instrumentations.`);
4510
4621
  }
4511
- const autoInstrumentations = getAutoInstrumentations(mergedConfig.autoInstrumentations, manualInstrumentationNames);
4622
+ const autoInstrumentations = getAutoInstrumentations(mergedConfig.autoInstrumentations, manualInstrumentationNames, devtoolsPort === void 0 ? [] : [devtoolsPort]);
4623
+ if (Array.isArray(mergedConfig.autoInstrumentations)) {
4624
+ const missing = missingInstrumentations(mergedConfig.autoInstrumentations, autoInstrumentations ?? [], manualInstrumentationNames);
4625
+ if (missing.length > 0) setupWarn(`[autotel] autoInstrumentations: no instrumentation loaded for ${missing.join(", ")}. Check the spelling; @opentelemetry/auto-instrumentations-node has none for some libraries (fastify, next).`);
4626
+ }
4512
4627
  if (autoInstrumentations && autoInstrumentations.length > 0) finalInstrumentations = [...finalInstrumentations, ...autoInstrumentations];
4513
4628
  } catch (error) {
4514
- logger.warn({}, `[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`);
4629
+ setupWarn(`[autotel] Failed to configure auto-instrumentations: ${error instanceof Error ? error.message : String(error)}`);
4515
4630
  }
4516
4631
  }
4517
4632
  const autotelSampler = mergedConfig.sampler ?? (mergedConfig.sampling ? resolveSamplingPreset(mergedConfig.sampling) : void 0);
@@ -4688,6 +4803,12 @@ Object.defineProperty(exports, 'DeterministicSampler', {
4688
4803
  return DeterministicSampler;
4689
4804
  }
4690
4805
  });
4806
+ Object.defineProperty(exports, 'EnrichedSpanProcessor', {
4807
+ enumerable: true,
4808
+ get: function () {
4809
+ return EnrichedSpanProcessor;
4810
+ }
4811
+ });
4691
4812
  Object.defineProperty(exports, 'Event', {
4692
4813
  enumerable: true,
4693
4814
  get: function () {