autotel 7.1.0 → 7.2.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 (58) hide show
  1. package/README.md +25 -0
  2. package/dist/analysis.cjs +17 -0
  3. package/dist/analysis.d.cts +9 -1
  4. package/dist/analysis.d.ts +9 -1
  5. package/dist/analysis.js +17 -1
  6. package/dist/auto.cjs +2 -3
  7. package/dist/auto.js +1 -2
  8. package/dist/correlation-id.cjs +1 -1
  9. package/dist/correlation-id.js +1 -1
  10. package/dist/decorators.cjs +1 -1
  11. package/dist/decorators.d.cts +1 -1
  12. package/dist/decorators.d.ts +1 -1
  13. package/dist/decorators.js +1 -1
  14. package/dist/event.cjs +1 -1
  15. package/dist/event.js +1 -1
  16. package/dist/{functional-BhhP4Er_.cjs → functional-C925G95W.cjs} +44 -10
  17. package/dist/{functional-CJn2zY4o.d.cts → functional-CgWcRXGX.d.cts} +12 -5
  18. package/dist/{functional-Cub1ku-C.js → functional-Doi0hFm3.js} +40 -6
  19. package/dist/{functional-DXy1cHFF.d.ts → functional-RFFpQzAV.d.ts} +12 -5
  20. package/dist/functional.cjs +1 -1
  21. package/dist/functional.d.cts +1 -1
  22. package/dist/functional.d.ts +1 -1
  23. package/dist/functional.js +1 -1
  24. package/dist/http.cjs +1 -1
  25. package/dist/http.js +1 -1
  26. package/dist/index.cjs +53 -15
  27. package/dist/index.d.cts +24 -4
  28. package/dist/index.d.ts +24 -4
  29. package/dist/index.js +40 -5
  30. package/dist/{init-DrlL1eis.d.cts → init-8GSy2bza.d.cts} +1 -1
  31. package/dist/{init-DDyaLzeg.js → init-DzAdgcFM.js} +2181 -1303
  32. package/dist/{init-BgnYi2sm.d.ts → init-UnKrXhpq.d.ts} +1 -1
  33. package/dist/{init-C5aHRqi2.cjs → init-aTZKsAwy.cjs} +2324 -1294
  34. package/dist/instrumentation.cjs +2 -3
  35. package/dist/instrumentation.js +1 -2
  36. package/dist/messaging.cjs +5 -5
  37. package/dist/messaging.js +2 -2
  38. package/dist/{sampling-CM5S2Lp3.d.ts → sampling-DBng4Foa.d.ts} +20 -1
  39. package/dist/{sampling-CmRdnXUi.d.cts → sampling-Er217Mge.d.cts} +20 -1
  40. package/dist/sampling.cjs +22 -601
  41. package/dist/sampling.d.cts +2 -2
  42. package/dist/sampling.d.ts +2 -2
  43. package/dist/sampling.js +2 -585
  44. package/dist/semantic-helpers.cjs +1 -1
  45. package/dist/semantic-helpers.js +1 -1
  46. package/dist/tail-sampling-processor.cjs +2 -26
  47. package/dist/tail-sampling-processor.js +1 -25
  48. package/dist/webhook.cjs +1 -1
  49. package/dist/webhook.js +1 -1
  50. package/dist/workflow-distributed.cjs +1 -1
  51. package/dist/workflow-distributed.js +1 -1
  52. package/dist/workflow.cjs +1 -1
  53. package/dist/workflow.js +1 -1
  54. package/dist/yaml-config.cjs +4 -248
  55. package/dist/yaml-config.d.cts +2 -2
  56. package/dist/yaml-config.d.ts +2 -2
  57. package/dist/yaml-config.js +1 -242
  58. package/package.json +1 -1
package/README.md CHANGED
@@ -775,6 +775,31 @@ app.use((req, res, next) => {
775
775
  - Baggage values are strings (convert numbers/objects before setting)
776
776
  - Never put PII in baggage - it propagates in HTTP headers across services!
777
777
 
778
+ ### Getting the trace id, and a link to it
779
+
780
+ `getActiveTraceContext()` reads the trace currently in scope, and
781
+ `resolveTraceUrl()` turns its id into a link to wherever you view traces. Printing
782
+ that link beside a slow request is the shortest path from "this was slow" to
783
+ looking at why:
784
+
785
+ ```typescript
786
+ import { getActiveTraceContext, resolveTraceUrl, span } from 'autotel';
787
+
788
+ await span('GET /feed', async () => {
789
+ const traceId = getActiveTraceContext()?.traceId;
790
+ const url = resolveTraceUrl(
791
+ 'http://localhost:4318/#trace={traceId}',
792
+ traceId,
793
+ );
794
+ console.log(`feed request ${url ?? traceId}`);
795
+ });
796
+ ```
797
+
798
+ `resolveTraceUrl(template, traceId)` substitutes `{traceId}`. Pass `undefined`
799
+ as the template and it falls back to `OTEL_TRACE_URL_TEMPLATE`, so the same code
800
+ points at devtools locally and at your vendor in production without a branch.
801
+ It returns `undefined` when neither is set.
802
+
778
803
  ### Reusable Middleware Helpers
779
804
 
780
805
  - `withTracing(options)` : create a preconfigured wrapper (service name, default attributes, skip rules).
package/dist/analysis.cjs CHANGED
@@ -81,6 +81,23 @@ function compareCohorts(options) {
81
81
  results.sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference) || b.difference - a.difference || a.field.localeCompare(b.field) || a.value.localeCompare(b.value));
82
82
  return results.slice(0, limit);
83
83
  }
84
+ /**
85
+ * Label a numeric value with the range it falls in.
86
+ *
87
+ * `compareCohorts` skips a field whose values never repeat, which is what a
88
+ * raw duration or byte count does. Bucketing at instrumentation time turns
89
+ * such a field into one that can describe a cohort.
90
+ */
91
+ function bucket(value, boundaries) {
92
+ if (!Number.isFinite(value) || boundaries.length === 0) return "unknown";
93
+ const ordered = [...boundaries].sort((a, b) => a - b);
94
+ for (const [index, boundary] of ordered.entries()) if (value < boundary) {
95
+ const lower = ordered[index - 1];
96
+ return lower === void 0 ? `<${boundary}` : `${lower}-${boundary}`;
97
+ }
98
+ return `>=${ordered.at(-1)}`;
99
+ }
84
100
 
85
101
  //#endregion
102
+ exports.bucket = bucket;
86
103
  exports.compareCohorts = compareCohorts;
@@ -82,5 +82,13 @@ interface CompareCohortsOptions {
82
82
  * @returns Differences sorted by absolute strength, strongest first
83
83
  */
84
84
  declare function compareCohorts(options: CompareCohortsOptions): CohortDifference[];
85
+ /**
86
+ * Label a numeric value with the range it falls in.
87
+ *
88
+ * `compareCohorts` skips a field whose values never repeat, which is what a
89
+ * raw duration or byte count does. Bucketing at instrumentation time turns
90
+ * such a field into one that can describe a cohort.
91
+ */
92
+ declare function bucket(value: number, boundaries: readonly number[]): string;
85
93
  //#endregion
86
- export { AnalysisEvent, CohortDifference, CompareCohortsOptions, compareCohorts };
94
+ export { AnalysisEvent, CohortDifference, CompareCohortsOptions, bucket, compareCohorts };
@@ -82,5 +82,13 @@ interface CompareCohortsOptions {
82
82
  * @returns Differences sorted by absolute strength, strongest first
83
83
  */
84
84
  declare function compareCohorts(options: CompareCohortsOptions): CohortDifference[];
85
+ /**
86
+ * Label a numeric value with the range it falls in.
87
+ *
88
+ * `compareCohorts` skips a field whose values never repeat, which is what a
89
+ * raw duration or byte count does. Bucketing at instrumentation time turns
90
+ * such a field into one that can describe a cohort.
91
+ */
92
+ declare function bucket(value: number, boundaries: readonly number[]): string;
85
93
  //#endregion
86
- export { AnalysisEvent, CohortDifference, CompareCohortsOptions, compareCohorts };
94
+ export { AnalysisEvent, CohortDifference, CompareCohortsOptions, bucket, compareCohorts };
package/dist/analysis.js CHANGED
@@ -79,6 +79,22 @@ function compareCohorts(options) {
79
79
  results.sort((a, b) => Math.abs(b.difference) - Math.abs(a.difference) || b.difference - a.difference || a.field.localeCompare(b.field) || a.value.localeCompare(b.value));
80
80
  return results.slice(0, limit);
81
81
  }
82
+ /**
83
+ * Label a numeric value with the range it falls in.
84
+ *
85
+ * `compareCohorts` skips a field whose values never repeat, which is what a
86
+ * raw duration or byte count does. Bucketing at instrumentation time turns
87
+ * such a field into one that can describe a cohort.
88
+ */
89
+ function bucket(value, boundaries) {
90
+ if (!Number.isFinite(value) || boundaries.length === 0) return "unknown";
91
+ const ordered = [...boundaries].sort((a, b) => a - b);
92
+ for (const [index, boundary] of ordered.entries()) if (value < boundary) {
93
+ const lower = ordered[index - 1];
94
+ return lower === void 0 ? `<${boundary}` : `${lower}-${boundary}`;
95
+ }
96
+ return `>=${ordered.at(-1)}`;
97
+ }
82
98
 
83
99
  //#endregion
84
- export { compareCohorts };
100
+ export { bucket, compareCohorts };
package/dist/auto.cjs CHANGED
@@ -1,6 +1,5 @@
1
1
  const require_rolldown_runtime = require('./rolldown-runtime-C_NdSu1c.cjs');
2
- const require_init = require('./init-C5aHRqi2.cjs');
3
- const require_yaml_config = require('./yaml-config.cjs');
2
+ const require_init = require('./init-aTZKsAwy.cjs');
4
3
  let node_module = require("node:module");
5
4
  node_module = require_rolldown_runtime.__toESM(node_module, 1);
6
5
  let import_in_the_middle = require("import-in-the-middle");
@@ -42,7 +41,7 @@ let import_in_the_middle = require("import-in-the-middle");
42
41
  */
43
42
  const { registerOptions } = (0, import_in_the_middle.createAddHookMessageChannel)();
44
43
  node_module.register("import-in-the-middle/hook.mjs", require("url").pathToFileURL(__filename).href, registerOptions);
45
- const yamlConfig = require_yaml_config.loadYamlConfig();
44
+ const yamlConfig = require_init.loadYamlConfig();
46
45
  const autoInstrumentationsEnv = process.env.AUTOTEL_INTEGRATIONS;
47
46
  const autoInstrumentations = autoInstrumentationsEnv === "true" ? true : autoInstrumentationsEnv ? autoInstrumentationsEnv.split(",").map((s) => s.trim()) : yamlConfig?.autoInstrumentations ?? ["http", "express"];
48
47
  require_init.init({
package/dist/auto.js CHANGED
@@ -1,5 +1,4 @@
1
- import { i as init } from "./init-DDyaLzeg.js";
2
- import { loadYamlConfig } from "./yaml-config.js";
1
+ import { g as loadYamlConfig, i as init } from "./init-DzAdgcFM.js";
3
2
  import * as nodeModule from "node:module";
4
3
  import { createAddHookMessageChannel } from "import-in-the-middle";
5
4
 
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_init = require('./init-C5aHRqi2.cjs');
2
+ const require_init = require('./init-aTZKsAwy.cjs');
3
3
 
4
4
  exports.CORRELATION_ID_BAGGAGE_KEY = require_init.CORRELATION_ID_BAGGAGE_KEY;
5
5
  exports.generateCorrelationId = require_init.generateCorrelationId;
@@ -1,3 +1,3 @@
1
- import { C as setCorrelationId, S as runWithCorrelationId, _ as CORRELATION_ID_BAGGAGE_KEY, b as getCorrelationStorage, v as generateCorrelationId, w as setCorrelationIdInBaggage, x as getOrCreateCorrelationId, y as getCorrelationId } from "./init-DDyaLzeg.js";
1
+ import { $ as getOrCreateCorrelationId, Q as getCorrelationStorage, X as generateCorrelationId, Y as CORRELATION_ID_BAGGAGE_KEY, Z as getCorrelationId, et as runWithCorrelationId, nt as setCorrelationIdInBaggage, tt as setCorrelationId } from "./init-DzAdgcFM.js";
2
2
 
3
3
  export { CORRELATION_ID_BAGGAGE_KEY, generateCorrelationId, getCorrelationId, getCorrelationStorage, getOrCreateCorrelationId, runWithCorrelationId, setCorrelationId, setCorrelationIdInBaggage };
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_values = require('./values-DApyq53y.cjs');
3
3
  const require_config = require('./config.cjs');
4
- const require_init = require('./init-C5aHRqi2.cjs');
4
+ const require_init = require('./init-aTZKsAwy.cjs');
5
5
  let _opentelemetry_api = require("@opentelemetry/api");
6
6
 
7
7
  //#region src/decorators.ts
@@ -1,5 +1,5 @@
1
1
  import { n as TraceContext } from "./trace-context-C1Cn1q0y.cjs";
2
- import { m as TracingOptions } from "./functional-CJn2zY4o.cjs";
2
+ import { m as TracingOptions } from "./functional-CgWcRXGX.cjs";
3
3
  //#region src/decorators.d.ts
4
4
  /**
5
5
  * Options for @Trace method decorator
@@ -1,5 +1,5 @@
1
1
  import { n as TraceContext } from "./trace-context-f89xPJbK.js";
2
- import { m as TracingOptions } from "./functional-DXy1cHFF.js";
2
+ import { m as TracingOptions } from "./functional-RFFpQzAV.js";
3
3
  //#region src/decorators.d.ts
4
4
  /**
5
5
  * Options for @Trace method decorator
@@ -1,6 +1,6 @@
1
1
  import { y as splitNameOrOptions } from "./values-BenyvWKz.js";
2
2
  import { getConfig } from "./config.js";
3
- import { T as createTraceContext } from "./init-DDyaLzeg.js";
3
+ import { H as createTraceContext } from "./init-DzAdgcFM.js";
4
4
  import { SpanStatusCode } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/decorators.ts
package/dist/event.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_init = require('./init-C5aHRqi2.cjs');
2
+ const require_init = require('./init-aTZKsAwy.cjs');
3
3
 
4
4
  exports.Event = require_init.Event;
5
5
  exports.getEvents = require_init.getEvents;
package/dist/event.js CHANGED
@@ -1,3 +1,3 @@
1
- import { d as getEvents, f as resetEvents, u as Event } from "./init-DDyaLzeg.js";
1
+ import { d as getEvents, f as resetEvents, u as Event } from "./init-DzAdgcFM.js";
2
2
 
3
3
  export { Event, getEvents, resetEvents };
@@ -2,8 +2,7 @@ const require_rolldown_runtime = require('./rolldown-runtime-C_NdSu1c.cjs');
2
2
  const require_values = require('./values-DApyq53y.cjs');
3
3
  const require_tracer_provider = require('./tracer-provider.cjs');
4
4
  const require_config = require('./config.cjs');
5
- const require_sampling = require('./sampling.cjs');
6
- const require_init = require('./init-C5aHRqi2.cjs');
5
+ const require_init = require('./init-aTZKsAwy.cjs');
7
6
  const require_evidence = require('./evidence.cjs');
8
7
  const require_trace_helpers = require('./trace-helpers.cjs');
9
8
  let _opentelemetry_api = require("@opentelemetry/api");
@@ -12,6 +11,36 @@ node_fs = require_rolldown_runtime.__toESM(node_fs, 1);
12
11
  let node_url = require("node:url");
13
12
  node_url = require_rolldown_runtime.__toESM(node_url, 1);
14
13
 
14
+ //#region src/is-thenable.ts
15
+ /**
16
+ * Convert anything `await` would wait on into a native Promise, or return
17
+ * `undefined` for a synchronous value.
18
+ *
19
+ * `instanceof Promise` is not enough. ORM query builders (drizzle, knex,
20
+ * Prisma, Sequelize) are lazy thenables that are not native Promises, and a
21
+ * promise created in another realm fails the check too. Treating those as
22
+ * synchronous ends the span before the work runs, which produces a short
23
+ * parent span with its real children orphaned outside it.
24
+ */
25
+ function promiseFromThenable(value) {
26
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return;
27
+ let then;
28
+ try {
29
+ then = value.then;
30
+ } catch (error) {
31
+ return Promise.reject(error);
32
+ }
33
+ if (typeof then !== "function") return void 0;
34
+ return new Promise((resolve, reject) => {
35
+ try {
36
+ then.call(value, resolve, reject);
37
+ } catch (error) {
38
+ reject(error);
39
+ }
40
+ });
41
+ }
42
+
43
+ //#endregion
15
44
  //#region src/variable-name-inference.ts
16
45
  /**
17
46
  * Variable Name Inference Utility
@@ -319,7 +348,7 @@ function runWithTraceContextStorage(fn) {
319
348
  }
320
349
  function wrapWithTracingSync(fnFactory, options, variableName) {
321
350
  const { tracer, meter } = require_config.getConfig();
322
- const sampler = options.sampler || new require_sampling.AlwaysSampler();
351
+ const sampler = options.sampler || new require_init.AlwaysSampler();
323
352
  const spanName = getSpanName(options, fnFactory, variableName);
324
353
  const callCounter = options.withMetrics ? meter.createCounter(`${spanName}.calls`, {
325
354
  description: `Call count for ${spanName}`,
@@ -338,7 +367,10 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
338
367
  const shouldSample = sampler.shouldSample(samplingContext);
339
368
  const sampleRate = sampler.sampleRate?.(samplingContext);
340
369
  const needsTailSampling = sampler.needsTailSampling?.() ?? false;
341
- if (!shouldSample && !needsTailSampling) return fnFactory(createDummyCtx()).call(this, ...args);
370
+ if (!shouldSample && !needsTailSampling) {
371
+ const unsampled = fnFactory(createDummyCtx()).call(this, ...args);
372
+ return promiseFromThenable(unsampled) ?? unsampled;
373
+ }
342
374
  const startTime = performance.now();
343
375
  const flushRootTelemetry = createRootTelemetryFlusher(options, options.startNewRoot || _opentelemetry_api.trace.getActiveSpan() === void 0);
344
376
  const spanOptions = {};
@@ -347,21 +379,21 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
347
379
  return tracer.startActiveSpan(spanName, spanOptions, require_init.getActiveContextWithBaggage(), (span) => require_init.runInOperationContext(spanName, () => runWithTraceContextStorage(() => {
348
380
  let shouldKeepSpan = true;
349
381
  require_trace_helpers.setSpanName(span, spanName);
350
- if (sampleRate !== void 0 && sampleRate > 1) span.setAttribute(require_sampling.AUTOTEL_SAMPLING_RATE, sampleRate);
382
+ if (sampleRate !== void 0 && sampleRate > 1) span.setAttribute(require_init.AUTOTEL_SAMPLING_RATE, sampleRate);
351
383
  const fn = fnFactory(require_init.createTraceContext(span));
352
384
  const argsAttributes = {
353
385
  ...captureInputAttrs(args, options.captureInput),
354
386
  ...options.attributesFromArgs?.(args)
355
387
  };
356
388
  const handleTailSampling = (success, duration, error) => {
357
- if (needsTailSampling && sampler.shouldKeepTrace) {
389
+ if (needsTailSampling && sampler.shouldKeepTrace && !require_init.isForceKept(span) && !require_init.debugCaptureRequested()) {
358
390
  shouldKeepSpan = sampler.shouldKeepTrace(samplingContext, {
359
391
  success,
360
392
  duration,
361
393
  error
362
394
  });
363
- span.setAttribute(require_sampling.AUTOTEL_SAMPLING_TAIL_KEEP, shouldKeepSpan);
364
- span.setAttribute(require_sampling.AUTOTEL_SAMPLING_TAIL_EVALUATED, true);
395
+ span.setAttribute(require_init.AUTOTEL_SAMPLING_TAIL_KEEP, shouldKeepSpan);
396
+ span.setAttribute(require_init.AUTOTEL_SAMPLING_TAIL_EVALUATED, true);
365
397
  }
366
398
  };
367
399
  const onSuccess = (result) => {
@@ -409,7 +441,8 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
409
441
  status: "started"
410
442
  });
411
443
  const result = _opentelemetry_api.context.with(_opentelemetry_api.trace.setSpan(require_init.getActiveContextWithBaggage(), span), () => fn.call(this, ...args));
412
- if (result instanceof Promise) return result.then(async (value) => {
444
+ const resultPromise = promiseFromThenable(result);
445
+ if (resultPromise) return resultPromise.then(async (value) => {
413
446
  const completed = onSuccess(value);
414
447
  await flushRootTelemetry();
415
448
  return completed;
@@ -659,7 +692,8 @@ function span(nameOrOptions, fn) {
659
692
  try {
660
693
  if (attributes) for (const [key, value] of Object.entries(attributes)) span.setAttribute(key, value);
661
694
  const result = fn(span);
662
- if (result instanceof Promise) return result.then((resolved) => {
695
+ const resultPromise = promiseFromThenable(result);
696
+ if (resultPromise) return resultPromise.then((resolved) => {
663
697
  span.setStatus({ code: _opentelemetry_api.SpanStatusCode.OK });
664
698
  span.end();
665
699
  return resolved;
@@ -1,5 +1,5 @@
1
1
  import { n as TraceContext } from "./trace-context-C1Cn1q0y.cjs";
2
- import { p as Sampler } from "./sampling-CmRdnXUi.cjs";
2
+ import { m as Sampler } from "./sampling-Er217Mge.cjs";
3
3
  import { Attributes, Span, SpanKind } from "@opentelemetry/api";
4
4
  //#region src/functional-wrapper.d.ts
5
5
  type WrappedFunction<TArgs extends unknown[], TReturn> = (...args: TArgs) => TReturn | Promise<TReturn>;
@@ -192,7 +192,9 @@ declare const ctx: TraceContext;
192
192
  * })
193
193
  * ```
194
194
  */
195
+ declare function traceImpl<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => PromiseLike<TReturn>): (...args: TArgs) => Promise<TReturn>;
195
196
  declare function traceImpl<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
197
+ declare function traceImpl<TArgs extends unknown[], TReturn>(name: string, fn: (...args: TArgs) => PromiseLike<TReturn>): (...args: TArgs) => Promise<TReturn>;
196
198
  declare function traceImpl<TArgs extends unknown[], TReturn>(name: string, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
197
199
  declare function traceImpl<TArgs extends unknown[], TReturn>(options: TracingOptions<TArgs, TReturn>, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
198
200
  declare function traceImpl(name: string): <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
@@ -258,7 +260,7 @@ declare const trace$1: typeof traceImpl & {
258
260
  * )(ctx => async (data) => { })
259
261
  * ```
260
262
  */
261
- declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn = unknown>(options?: TracingOptions<TCfgArgs, TCfgReturn>): <TArgs extends TCfgArgs, TReturn extends TCfgReturn>(fnFactory: (ctx: TraceContext) => (...args: TArgs) => TReturn | Promise<TReturn>) => WrappedFunction<TArgs, TReturn>;
263
+ declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn = unknown>(options?: TracingOptions<TCfgArgs, TCfgReturn>): <TArgs extends TCfgArgs, TReturn extends TCfgReturn>(fnFactory: (ctx: TraceContext) => (...args: TArgs) => TReturn | PromiseLike<TReturn>) => WrappedFunction<TArgs, TReturn>;
262
264
  /**
263
265
  * Approach 3: instrument() - Batch auto-instrumentation
264
266
  *
@@ -309,8 +311,13 @@ declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn
309
311
  * })
310
312
  * ```
311
313
  */
314
+ type InstrumentedFunction<TFunction extends AnyInstrumentable> = TFunction extends ((...args: infer TArgs) => infer TReturn) ? (...args: TArgs) => TReturn extends PromiseLike<infer TValue> ? Promise<TValue> : TReturn : never;
315
+ type InstrumentedFunctions<T extends Record<string, AnyInstrumentable>> = { [TKey in keyof T]: InstrumentedFunction<T[TKey]>; };
316
+ declare function instrument<TFunction extends AnyInstrumentable>(options: SingleInstrumentOptions<TFunction> & {
317
+ fn: TFunction & ((...args: Parameters<TFunction>) => PromiseLike<unknown>);
318
+ }): (...args: Parameters<TFunction>) => Promise<Awaited<ReturnType<TFunction>>>;
312
319
  declare function instrument<TFunction extends AnyInstrumentable>(options: SingleInstrumentOptions<TFunction>): TFunction;
313
- declare function instrument<T extends Record<string, AnyInstrumentable>>(options: InstrumentOptions<T>): T;
320
+ declare function instrument<T extends Record<string, AnyInstrumentable>>(options: InstrumentOptions<T>): InstrumentedFunctions<T>;
314
321
  /**
315
322
  * Options for span() function
316
323
  */
@@ -352,10 +359,10 @@ interface SpanOptions {
352
359
  * })
353
360
  * ```
354
361
  */
362
+ declare function span<T = unknown>(name: string, fn: (span: Span) => PromiseLike<T>): Promise<T>;
363
+ declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => PromiseLike<T>): Promise<T>;
355
364
  declare function span<T = unknown>(name: string, fn: (span: Span) => T): T;
356
- declare function span<T = unknown>(name: string, fn: (span: Span) => Promise<T>): Promise<T>;
357
365
  declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => T): T;
358
- declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => Promise<T>): Promise<T>;
359
366
  /**
360
367
  * Options for withNewContext() function
361
368
  */
@@ -1,14 +1,43 @@
1
1
  import { l as asString, m as isDevelopment } from "./values-BenyvWKz.js";
2
2
  import { getForceFlushableProvider } from "./tracer-provider.js";
3
3
  import { getConfig } from "./config.js";
4
- import { AUTOTEL_SAMPLING_RATE, AUTOTEL_SAMPLING_TAIL_EVALUATED, AUTOTEL_SAMPLING_TAIL_KEEP, AlwaysSampler } from "./sampling.js";
5
- import { D as getActiveContextWithBaggage, O as getContextStorage, T as createTraceContext, h as getEventQueue, k as hasExplicitSpanStatus, m as runInOperationContext, r as getSdk, t as getConfig$1 } from "./init-DDyaLzeg.js";
4
+ import { C as AUTOTEL_SAMPLING_TAIL_EVALUATED, E as AlwaysSampler, F as debugCaptureRequested, G as getContextStorage, H as createTraceContext, K as hasExplicitSpanStatus, R as isForceKept, S as AUTOTEL_SAMPLING_RATE, W as getActiveContextWithBaggage, m as runInOperationContext, q as getEventQueue, r as getSdk, t as getConfig$1, w as AUTOTEL_SAMPLING_TAIL_KEEP } from "./init-DzAdgcFM.js";
6
5
  import { evidenceAttribute } from "./evidence.js";
7
6
  import { setSpanName } from "./trace-helpers.js";
8
7
  import { SpanStatusCode, context, propagation, trace } from "@opentelemetry/api";
9
8
  import * as nodeFs from "node:fs";
10
9
  import * as nodeUrl from "node:url";
11
10
 
11
+ //#region src/is-thenable.ts
12
+ /**
13
+ * Convert anything `await` would wait on into a native Promise, or return
14
+ * `undefined` for a synchronous value.
15
+ *
16
+ * `instanceof Promise` is not enough. ORM query builders (drizzle, knex,
17
+ * Prisma, Sequelize) are lazy thenables that are not native Promises, and a
18
+ * promise created in another realm fails the check too. Treating those as
19
+ * synchronous ends the span before the work runs, which produces a short
20
+ * parent span with its real children orphaned outside it.
21
+ */
22
+ function promiseFromThenable(value) {
23
+ if (typeof value !== "object" && typeof value !== "function" || value === null) return;
24
+ let then;
25
+ try {
26
+ then = value.then;
27
+ } catch (error) {
28
+ return Promise.reject(error);
29
+ }
30
+ if (typeof then !== "function") return void 0;
31
+ return new Promise((resolve, reject) => {
32
+ try {
33
+ then.call(value, resolve, reject);
34
+ } catch (error) {
35
+ reject(error);
36
+ }
37
+ });
38
+ }
39
+
40
+ //#endregion
12
41
  //#region src/variable-name-inference.ts
13
42
  /**
14
43
  * Variable Name Inference Utility
@@ -335,7 +364,10 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
335
364
  const shouldSample = sampler.shouldSample(samplingContext);
336
365
  const sampleRate = sampler.sampleRate?.(samplingContext);
337
366
  const needsTailSampling = sampler.needsTailSampling?.() ?? false;
338
- if (!shouldSample && !needsTailSampling) return fnFactory(createDummyCtx()).call(this, ...args);
367
+ if (!shouldSample && !needsTailSampling) {
368
+ const unsampled = fnFactory(createDummyCtx()).call(this, ...args);
369
+ return promiseFromThenable(unsampled) ?? unsampled;
370
+ }
339
371
  const startTime = performance.now();
340
372
  const flushRootTelemetry = createRootTelemetryFlusher(options, options.startNewRoot || trace.getActiveSpan() === void 0);
341
373
  const spanOptions = {};
@@ -351,7 +383,7 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
351
383
  ...options.attributesFromArgs?.(args)
352
384
  };
353
385
  const handleTailSampling = (success, duration, error) => {
354
- if (needsTailSampling && sampler.shouldKeepTrace) {
386
+ if (needsTailSampling && sampler.shouldKeepTrace && !isForceKept(span) && !debugCaptureRequested()) {
355
387
  shouldKeepSpan = sampler.shouldKeepTrace(samplingContext, {
356
388
  success,
357
389
  duration,
@@ -406,7 +438,8 @@ function wrapWithTracingSync(fnFactory, options, variableName) {
406
438
  status: "started"
407
439
  });
408
440
  const result = context.with(trace.setSpan(getActiveContextWithBaggage(), span), () => fn.call(this, ...args));
409
- if (result instanceof Promise) return result.then(async (value) => {
441
+ const resultPromise = promiseFromThenable(result);
442
+ if (resultPromise) return resultPromise.then(async (value) => {
410
443
  const completed = onSuccess(value);
411
444
  await flushRootTelemetry();
412
445
  return completed;
@@ -656,7 +689,8 @@ function span(nameOrOptions, fn) {
656
689
  try {
657
690
  if (attributes) for (const [key, value] of Object.entries(attributes)) span.setAttribute(key, value);
658
691
  const result = fn(span);
659
- if (result instanceof Promise) return result.then((resolved) => {
692
+ const resultPromise = promiseFromThenable(result);
693
+ if (resultPromise) return resultPromise.then((resolved) => {
660
694
  span.setStatus({ code: SpanStatusCode.OK });
661
695
  span.end();
662
696
  return resolved;
@@ -1,5 +1,5 @@
1
1
  import { n as TraceContext } from "./trace-context-f89xPJbK.js";
2
- import { p as Sampler } from "./sampling-CM5S2Lp3.js";
2
+ import { m as Sampler } from "./sampling-DBng4Foa.js";
3
3
  import { Attributes, Span, SpanKind } from "@opentelemetry/api";
4
4
  //#region src/functional-wrapper.d.ts
5
5
  type WrappedFunction<TArgs extends unknown[], TReturn> = (...args: TArgs) => TReturn | Promise<TReturn>;
@@ -192,7 +192,9 @@ declare const ctx: TraceContext;
192
192
  * })
193
193
  * ```
194
194
  */
195
+ declare function traceImpl<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => PromiseLike<TReturn>): (...args: TArgs) => Promise<TReturn>;
195
196
  declare function traceImpl<TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
197
+ declare function traceImpl<TArgs extends unknown[], TReturn>(name: string, fn: (...args: TArgs) => PromiseLike<TReturn>): (...args: TArgs) => Promise<TReturn>;
196
198
  declare function traceImpl<TArgs extends unknown[], TReturn>(name: string, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
197
199
  declare function traceImpl<TArgs extends unknown[], TReturn>(options: TracingOptions<TArgs, TReturn>, fn: (...args: TArgs) => TReturn): (...args: TArgs) => TReturn;
198
200
  declare function traceImpl(name: string): <TArgs extends unknown[], TReturn>(fn: (...args: TArgs) => TReturn) => (...args: TArgs) => TReturn;
@@ -258,7 +260,7 @@ declare const trace$1: typeof traceImpl & {
258
260
  * )(ctx => async (data) => { })
259
261
  * ```
260
262
  */
261
- declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn = unknown>(options?: TracingOptions<TCfgArgs, TCfgReturn>): <TArgs extends TCfgArgs, TReturn extends TCfgReturn>(fnFactory: (ctx: TraceContext) => (...args: TArgs) => TReturn | Promise<TReturn>) => WrappedFunction<TArgs, TReturn>;
263
+ declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn = unknown>(options?: TracingOptions<TCfgArgs, TCfgReturn>): <TArgs extends TCfgArgs, TReturn extends TCfgReturn>(fnFactory: (ctx: TraceContext) => (...args: TArgs) => TReturn | PromiseLike<TReturn>) => WrappedFunction<TArgs, TReturn>;
262
264
  /**
263
265
  * Approach 3: instrument() - Batch auto-instrumentation
264
266
  *
@@ -309,8 +311,13 @@ declare function withTracing<TCfgArgs extends unknown[] = unknown[], TCfgReturn
309
311
  * })
310
312
  * ```
311
313
  */
314
+ type InstrumentedFunction<TFunction extends AnyInstrumentable> = TFunction extends ((...args: infer TArgs) => infer TReturn) ? (...args: TArgs) => TReturn extends PromiseLike<infer TValue> ? Promise<TValue> : TReturn : never;
315
+ type InstrumentedFunctions<T extends Record<string, AnyInstrumentable>> = { [TKey in keyof T]: InstrumentedFunction<T[TKey]>; };
316
+ declare function instrument<TFunction extends AnyInstrumentable>(options: SingleInstrumentOptions<TFunction> & {
317
+ fn: TFunction & ((...args: Parameters<TFunction>) => PromiseLike<unknown>);
318
+ }): (...args: Parameters<TFunction>) => Promise<Awaited<ReturnType<TFunction>>>;
312
319
  declare function instrument<TFunction extends AnyInstrumentable>(options: SingleInstrumentOptions<TFunction>): TFunction;
313
- declare function instrument<T extends Record<string, AnyInstrumentable>>(options: InstrumentOptions<T>): T;
320
+ declare function instrument<T extends Record<string, AnyInstrumentable>>(options: InstrumentOptions<T>): InstrumentedFunctions<T>;
314
321
  /**
315
322
  * Options for span() function
316
323
  */
@@ -352,10 +359,10 @@ interface SpanOptions {
352
359
  * })
353
360
  * ```
354
361
  */
362
+ declare function span<T = unknown>(name: string, fn: (span: Span) => PromiseLike<T>): Promise<T>;
363
+ declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => PromiseLike<T>): Promise<T>;
355
364
  declare function span<T = unknown>(name: string, fn: (span: Span) => T): T;
356
- declare function span<T = unknown>(name: string, fn: (span: Span) => Promise<T>): Promise<T>;
357
365
  declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => T): T;
358
- declare function span<T = unknown>(options: SpanOptions, fn: (span: Span) => Promise<T>): Promise<T>;
359
366
  /**
360
367
  * Options for withNewContext() function
361
368
  */
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_functional = require('./functional-BhhP4Er_.cjs');
2
+ const require_functional = require('./functional-C925G95W.cjs');
3
3
 
4
4
  exports.ctx = require_functional.ctx;
5
5
  exports.getActiveTraceContext = require_functional.getActiveTraceContext;
@@ -1,3 +1,3 @@
1
1
  import { n as TraceContext } from "./trace-context-C1Cn1q0y.cjs";
2
- import { a as getActiveTraceContext, c as trace, d as withTracing, f as InstrumentOptions, i as ctx, l as withBaggage, m as TracingOptions, n as WithBaggageOptions, o as instrument, p as SingleInstrumentOptions, r as WithNewContextOptions, s as span, t as SpanOptions, u as withNewContext } from "./functional-CJn2zY4o.cjs";
2
+ import { a as getActiveTraceContext, c as trace, d as withTracing, f as InstrumentOptions, i as ctx, l as withBaggage, m as TracingOptions, n as WithBaggageOptions, o as instrument, p as SingleInstrumentOptions, r as WithNewContextOptions, s as span, t as SpanOptions, u as withNewContext } from "./functional-CgWcRXGX.cjs";
3
3
  export { type InstrumentOptions, type SingleInstrumentOptions, SpanOptions, type TraceContext, type TracingOptions, WithBaggageOptions, WithNewContextOptions, ctx, getActiveTraceContext, instrument, span, trace, withBaggage, withNewContext, withTracing };
@@ -1,3 +1,3 @@
1
1
  import { n as TraceContext } from "./trace-context-f89xPJbK.js";
2
- import { a as getActiveTraceContext, c as trace, d as withTracing, f as InstrumentOptions, i as ctx, l as withBaggage, m as TracingOptions, n as WithBaggageOptions, o as instrument, p as SingleInstrumentOptions, r as WithNewContextOptions, s as span, t as SpanOptions, u as withNewContext } from "./functional-DXy1cHFF.js";
2
+ import { a as getActiveTraceContext, c as trace, d as withTracing, f as InstrumentOptions, i as ctx, l as withBaggage, m as TracingOptions, n as WithBaggageOptions, o as instrument, p as SingleInstrumentOptions, r as WithNewContextOptions, s as span, t as SpanOptions, u as withNewContext } from "./functional-RFFpQzAV.js";
3
3
  export { type InstrumentOptions, type SingleInstrumentOptions, SpanOptions, type TraceContext, type TracingOptions, WithBaggageOptions, WithNewContextOptions, ctx, getActiveTraceContext, instrument, span, trace, withBaggage, withNewContext, withTracing };
@@ -1,3 +1,3 @@
1
- import { a as trace, c as withTracing, i as span, n as getActiveTraceContext, o as withBaggage, r as instrument, s as withNewContext, t as ctx } from "./functional-Cub1ku-C.js";
1
+ import { a as trace, c as withTracing, i as span, n as getActiveTraceContext, o as withBaggage, r as instrument, s as withNewContext, t as ctx } from "./functional-Doi0hFm3.js";
2
2
 
3
3
  export { ctx, getActiveTraceContext, instrument, span, trace, withBaggage, withNewContext, withTracing };
package/dist/http.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_values = require('./values-DApyq53y.cjs');
3
3
  const require_config = require('./config.cjs');
4
- const require_init = require('./init-C5aHRqi2.cjs');
4
+ const require_init = require('./init-aTZKsAwy.cjs');
5
5
  let _opentelemetry_api = require("@opentelemetry/api");
6
6
 
7
7
  //#region src/http.ts
package/dist/http.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { _ as readProperty, h as isFunction, i as asNumber, l as asString } from "./values-BenyvWKz.js";
2
2
  import { getConfig } from "./config.js";
3
- import { D as getActiveContextWithBaggage } from "./init-DDyaLzeg.js";
3
+ import { W as getActiveContextWithBaggage } from "./init-DzAdgcFM.js";
4
4
  import { SpanStatusCode, context, propagation } from "@opentelemetry/api";
5
5
 
6
6
  //#region src/http.ts