autotel 7.7.1 → 7.9.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 (111) hide show
  1. package/dist/analysis.cjs +0 -1
  2. package/dist/{attribute-redacting-processor-CvBE0z1p.d.ts → attribute-redacting-processor-rkV_WL-k.d.ts} +2 -2
  3. package/dist/attribute-redacting-processor.cjs +1 -1
  4. package/dist/attribute-redacting-processor.d.ts +1 -1
  5. package/dist/{attributes-De9Fx0b4.js → attributes-CuGx6cOI.js} +21 -11
  6. package/dist/{attributes-DkptT2Ck.cjs → attributes-Ii3jDPsW.cjs} +23 -13
  7. package/dist/attributes.cjs +1 -1
  8. package/dist/attributes.d.ts +1 -1
  9. package/dist/attributes.js +1 -1
  10. package/dist/auto.cjs +2 -2
  11. package/dist/auto.js +1 -1
  12. package/dist/business-baggage.cjs +1 -1
  13. package/dist/{canonical-log-line-processor-Bvgb1lE4.cjs → canonical-log-line-processor-BU03jJeA.cjs} +1 -1
  14. package/dist/{canonical-log-line-processor-Yq4cXcD5.d.ts → canonical-log-line-processor-Bwrt_L4c.d.ts} +1 -1
  15. package/dist/{correlated-events-9RRdfyWR.cjs → correlated-events-DE_4A3oD.cjs} +1 -1
  16. package/dist/correlation-id.cjs +1 -1
  17. package/dist/correlation-id.js +1 -1
  18. package/dist/db.cjs +1 -1
  19. package/dist/decorators.cjs +2 -2
  20. package/dist/decorators.d.cts +1 -1
  21. package/dist/decorators.d.ts +1 -1
  22. package/dist/decorators.js +1 -1
  23. package/dist/diagnostics.cjs +3 -3
  24. package/dist/diagnostics.js +1 -1
  25. package/dist/drain-pipeline.cjs +0 -1
  26. package/dist/enrichers.cjs +0 -1
  27. package/dist/event-testing.cjs +0 -1
  28. package/dist/event.cjs +1 -1
  29. package/dist/event.js +1 -1
  30. package/dist/evidence.cjs +0 -1
  31. package/dist/exception-fingerprint.cjs +1 -1
  32. package/dist/{filtering-span-processor-BpDagWNa.d.ts → filtering-span-processor-vkewzbqB.d.ts} +2 -2
  33. package/dist/filtering-span-processor.cjs +0 -1
  34. package/dist/filtering-span-processor.d.ts +1 -1
  35. package/dist/{functional-S9IJNlBn.js → functional-6QPJDqUW.js} +27 -29
  36. package/dist/{functional-C4mjgtJb.d.cts → functional-DPZTpGh6.d.cts} +2 -2
  37. package/dist/{functional-UIJ0CaTV.cjs → functional-DxHvvWc_.cjs} +19 -21
  38. package/dist/{functional-DN_ztd9C.d.ts → functional-SeRUabkE.d.ts} +2 -2
  39. package/dist/functional.cjs +1 -1
  40. package/dist/functional.d.cts +1 -1
  41. package/dist/functional.d.ts +1 -1
  42. package/dist/functional.js +1 -1
  43. package/dist/http.cjs +2 -2
  44. package/dist/http.js +1 -1
  45. package/dist/{index-o_6YjZhV.d.ts → index-B9aRLp6c.d.ts} +1 -1
  46. package/dist/index.cjs +10 -10
  47. package/dist/index.d.cts +3 -3
  48. package/dist/index.d.ts +10 -10
  49. package/dist/index.js +3 -3
  50. package/dist/{init-Dyq6WtsO.js → init-C-qfxo_u.js} +262 -36
  51. package/dist/{init-WwjD-kQu.d.cts → init-COfMwKbc.d.cts} +38 -10
  52. package/dist/{init-CKSMbJUG.d.ts → init-CnoRlJqS.d.ts} +43 -15
  53. package/dist/{init-BYXDCfRL.cjs → init-W_klPrYk.cjs} +277 -39
  54. package/dist/instrumentation.cjs +9 -8
  55. package/dist/instrumentation.js +8 -7
  56. package/dist/{logger-CSdZkxbh.cjs → logger-DLjHQAus.cjs} +1 -1
  57. package/dist/logger.cjs +1 -1
  58. package/dist/messaging-adapters.cjs +1 -1
  59. package/dist/messaging-testing.cjs +0 -1
  60. package/dist/messaging.cjs +8 -7
  61. package/dist/messaging.js +5 -4
  62. package/dist/metric-testing.cjs +0 -1
  63. package/dist/{node-require-B_IVapV3.cjs → node-require-BPsB09eC.cjs} +2 -2
  64. package/dist/parse-error.cjs +1 -1
  65. package/dist/{policy-C4QcZnqv.d.ts → policy-DNw_0qUq.d.ts} +1 -1
  66. package/dist/policy.cjs +0 -0
  67. package/dist/policy.d.ts +1 -1
  68. package/dist/processors.cjs +1 -1
  69. package/dist/processors.d.ts +1 -1
  70. package/dist/register.cjs +1 -1
  71. package/dist/{registry-DIoklBz5.cjs → registry-B3ZJmUtU.cjs} +0 -1
  72. package/dist/{rolldown-runtime-C_NdSu1c.cjs → rolldown-runtime-C24Yb2bl.cjs} +1 -2
  73. package/dist/{sampling-DBng4Foa.d.ts → sampling-CZi7OM9u.d.ts} +13 -13
  74. package/dist/{sampling-Er217Mge.d.cts → sampling-DENUjT_8.d.cts} +13 -13
  75. package/dist/sampling.cjs +1 -1
  76. package/dist/sampling.d.cts +1 -1
  77. package/dist/sampling.d.ts +1 -1
  78. package/dist/sampling.js +1 -1
  79. package/dist/security-schema.cjs +0 -1
  80. package/dist/semantic-conventions.cjs +1 -1
  81. package/dist/semantic-helpers.cjs +3 -3
  82. package/dist/semantic-helpers.js +1 -1
  83. package/dist/{span-name-normalizer-CN1-8C76.d.ts → span-name-normalizer-DHcg1bSP.d.ts} +2 -2
  84. package/dist/span-name-normalizer.cjs +0 -1
  85. package/dist/span-name-normalizer.d.ts +1 -1
  86. package/dist/{stable-hash-C9F6xjzx.cjs → stable-hash-sLi1o4jj.cjs} +2 -2
  87. package/dist/{structured-error-BAXhglRE.cjs → structured-error-DynjWTTu.cjs} +1 -1
  88. package/dist/tail-sampling-processor.cjs +1 -1
  89. package/dist/tail-sampling-processor.d.ts +2 -2
  90. package/dist/tail-sampling-processor.js +1 -1
  91. package/dist/test-span-collector.cjs +1 -1
  92. package/dist/testing.cjs +3 -3
  93. package/dist/testing.d.ts +1 -1
  94. package/dist/testing.js +1 -1
  95. package/dist/{trace-factory-validation-Dc8epn87.cjs → trace-factory-validation-CHU1WcjK.cjs} +0 -1
  96. package/dist/trace-helpers.cjs +2 -2
  97. package/dist/tracer-provider.cjs +1 -1
  98. package/dist/validate.cjs +3 -3
  99. package/dist/validation-attributes.cjs +0 -1
  100. package/dist/{values-tm4bi0FF.cjs → values-AxGpgYBA.cjs} +0 -1
  101. package/dist/webhook.cjs +16 -13
  102. package/dist/webhook.js +14 -11
  103. package/dist/workflow-distributed.cjs +4 -6
  104. package/dist/workflow-distributed.js +2 -4
  105. package/dist/workflow.cjs +7 -6
  106. package/dist/workflow.js +3 -2
  107. package/dist/yaml-config.cjs +1 -1
  108. package/dist/yaml-config.d.cts +2 -2
  109. package/dist/yaml-config.d.ts +2 -2
  110. package/dist/yaml-config.js +1 -1
  111. package/package.json +2 -1
@@ -10,21 +10,170 @@ import { AttributeRedactingProcessor, REDACTOR_PRESETS, normalizeAttributeRedact
10
10
  import { t as PrettyConsoleExporter } from "./pretty-console-exporter-DqKl_q9z.js";
11
11
  import { t as CanonicalLogLineProcessor } from "./canonical-log-line-processor-BQ6NeZAk.js";
12
12
  import { resetMetrics } from "./metric.js";
13
- import { NodeSDK } from "@opentelemetry/sdk-node";
14
- import { AlwaysOffSampler, AlwaysOnSampler, BatchSpanProcessor, ConsoleSpanExporter, ParentBasedSampler, SamplingDecision, SimpleSpanProcessor, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
15
- import { resourceFromAttributes } from "@opentelemetry/resources";
13
+ import { DiagConsoleLogger, DiagLogLevel, TraceFlags, context, createContextKey, diag, metrics, propagation, trace } from "@opentelemetry/api";
14
+ import { logs } from "@opentelemetry/api-logs";
15
+ import { AsyncLocalStorageContextManager } from "@opentelemetry/context-async-hooks";
16
+ import { CompositePropagator, W3CBaggagePropagator, W3CTraceContextPropagator } from "@opentelemetry/core";
17
+ import { registerInstrumentations } from "@opentelemetry/instrumentation";
18
+ import { detectResources, envDetector, hostDetector, processDetector, resourceFromAttributes } from "@opentelemetry/resources";
19
+ import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
20
+ import { BatchLogRecordProcessor, LoggerProvider } from "@opentelemetry/sdk-logs";
21
+ import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
22
+ import { AlwaysOffSampler, AlwaysOnSampler, BasicTracerProvider, BatchSpanProcessor, ConsoleSpanExporter, ParentBasedSampler, SamplingDecision, SimpleSpanProcessor, TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
16
23
  import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
17
- import { TraceFlags, context, propagation, trace } from "@opentelemetry/api";
18
24
  import * as nodeAsyncHooks from "node:async_hooks";
19
- import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
20
- import { BatchLogRecordProcessor } from "@opentelemetry/sdk-logs";
21
25
  import * as nodeFs from "node:fs";
22
26
  import path from "node:path";
23
27
  import { constants } from "node:os";
24
28
  import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
25
29
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
26
- import { OTLPLogExporter } from "@opentelemetry/exporter-logs-otlp-http";
27
30
 
31
+ //#region src/sdk.ts
32
+ /**
33
+ * The SDK behind `init()`: builds and registers the tracer, meter and logger
34
+ * providers from components autotel has already resolved.
35
+ *
36
+ * This replaces `@opentelemetry/sdk-node`'s `NodeSDK`. That class did the same
37
+ * registration, but it statically imports every exporter the `OTEL_*_EXPORTER`
38
+ * variables could name — OTLP over gRPC (`@grpc/grpc-js`, `protobufjs`),
39
+ * Prometheus, the YAML file-config loader — so any bundle that contained
40
+ * `init()` shipped ~1 MB of exporters it never used. autotel resolves its own
41
+ * exporters up front, so all it ever needed from `NodeSDK` was `start()`.
42
+ *
43
+ * Kept from `NodeSDK`, because code and tests rely on them:
44
+ * - `OTEL_SDK_DISABLED=true` makes `start()` a no-op.
45
+ * - `OTEL_LOG_LEVEL` installs the console diag logger.
46
+ * - Resource: `envDetector`, `processDetector` and `hostDetector` are merged
47
+ * in, then `serviceName` is applied last so the resolved autotel value
48
+ * wins (`OTEL_NODE_RESOURCE_DETECTORS=none` turns detection off).
49
+ * - Context manager: `AsyncLocalStorageContextManager`.
50
+ * - Propagator: W3C trace context + baggage, or `OTEL_PROPAGATORS`.
51
+ * - Providers are only registered when they have something to do; an empty
52
+ * `spanProcessors` list still registers a tracer provider, so context keeps
53
+ * propagating even when nothing is exported.
54
+ *
55
+ * Not kept: building an exporter from `OTEL_TRACES_EXPORTER` /
56
+ * `OTEL_LOGS_EXPORTER` / `OTEL_METRICS_EXPORTER`. autotel always passes its own
57
+ * processors, so the traces and metrics variables never reached `NodeSDK`
58
+ * anyway; `OTEL_LOGS_EXPORTER=none` still switches logs off, and `otlp` gets
59
+ * the OTLP/HTTP log exporter. gRPC and Prometheus are no longer reachable from
60
+ * the environment — pass an exporter through `init()` instead.
61
+ */
62
+ const DIAG_LEVELS = {
63
+ ALL: DiagLogLevel.ALL,
64
+ VERBOSE: DiagLogLevel.VERBOSE,
65
+ DEBUG: DiagLogLevel.DEBUG,
66
+ INFO: DiagLogLevel.INFO,
67
+ WARN: DiagLogLevel.WARN,
68
+ ERROR: DiagLogLevel.ERROR,
69
+ NONE: DiagLogLevel.NONE
70
+ };
71
+ function envFlag(name) {
72
+ return (process.env[name] ?? "").trim().toLowerCase() === "true";
73
+ }
74
+ function propagatorFromEnv() {
75
+ const raw = process.env.OTEL_PROPAGATORS?.trim();
76
+ if (!raw) return void 0;
77
+ const names = raw.split(",").map((n) => n.trim().toLowerCase()).filter(Boolean);
78
+ if (names.includes("none")) return new CompositePropagator({ propagators: [] });
79
+ const propagators = [];
80
+ for (const name of names) if (name === "tracecontext") propagators.push(new W3CTraceContextPropagator());
81
+ else if (name === "baggage") propagators.push(new W3CBaggagePropagator());
82
+ else diag.warn(`[autotel] OTEL_PROPAGATORS names "${name}", which needs a propagator package autotel does not bundle; pass one via init({ propagator }).`);
83
+ return propagators.length > 0 ? new CompositePropagator({ propagators }) : void 0;
84
+ }
85
+ function defaultPropagator() {
86
+ return new CompositePropagator({ propagators: [new W3CTraceContextPropagator(), new W3CBaggagePropagator()] });
87
+ }
88
+ var AutotelSdk = class {
89
+ options;
90
+ disabled;
91
+ tracerProvider;
92
+ meterProvider;
93
+ loggerProvider;
94
+ constructor(options = {}) {
95
+ this.options = options;
96
+ this.disabled = envFlag("OTEL_SDK_DISABLED");
97
+ const level = process.env.OTEL_LOG_LEVEL?.trim().toUpperCase();
98
+ if (level && DIAG_LEVELS[level] !== void 0) diag.setLogger(new DiagConsoleLogger(), { logLevel: DIAG_LEVELS[level] });
99
+ }
100
+ start() {
101
+ if (this.disabled) return;
102
+ const o = this.options;
103
+ const instrumentations = (o.instrumentations ?? []).flat();
104
+ registerInstrumentations({ instrumentations });
105
+ context.setGlobalContextManager(new AsyncLocalStorageContextManager().enable());
106
+ if (o.textMapPropagator !== null) propagation.setGlobalPropagator(o.textMapPropagator ?? propagatorFromEnv() ?? defaultPropagator());
107
+ const resource = this.resolveResource();
108
+ if (o.metricReaders && o.metricReaders.length > 0) {
109
+ this.meterProvider = new MeterProvider({
110
+ resource,
111
+ readers: o.metricReaders
112
+ });
113
+ metrics.setGlobalMeterProvider(this.meterProvider);
114
+ for (const instrumentation of instrumentations) instrumentation.setMeterProvider(this.meterProvider);
115
+ }
116
+ this.tracerProvider = new BasicTracerProvider({
117
+ resource,
118
+ spanProcessors: o.spanProcessors ?? [],
119
+ ...o.sampler && { sampler: o.sampler }
120
+ });
121
+ trace.setGlobalTracerProvider(this.tracerProvider);
122
+ const logProcessors = this.resolveLogProcessors();
123
+ if (logProcessors) {
124
+ this.loggerProvider = new LoggerProvider({
125
+ resource,
126
+ processors: logProcessors
127
+ });
128
+ logs.setGlobalLoggerProvider(this.loggerProvider);
129
+ }
130
+ }
131
+ getTracerProvider() {
132
+ return this.tracerProvider;
133
+ }
134
+ async shutdown() {
135
+ await Promise.allSettled([
136
+ this.tracerProvider?.forceFlush(),
137
+ this.loggerProvider?.forceFlush(),
138
+ this.meterProvider?.forceFlush()
139
+ ]);
140
+ await Promise.all([
141
+ this.tracerProvider?.shutdown(),
142
+ this.loggerProvider?.shutdown(),
143
+ this.meterProvider?.shutdown()
144
+ ]);
145
+ }
146
+ resolveResource() {
147
+ const o = this.options;
148
+ let resource = o.resource ?? resourceFromAttributes({});
149
+ const detectorsEnv = process.env.OTEL_NODE_RESOURCE_DETECTORS?.trim();
150
+ if (o.autoDetectResources ?? detectorsEnv?.toLowerCase() !== "none") {
151
+ const detectors = o.resourceDetectors ?? [
152
+ envDetector,
153
+ processDetector,
154
+ hostDetector
155
+ ];
156
+ resource = resource.merge(detectResources({ detectors }));
157
+ }
158
+ if (o.serviceName !== void 0) resource = resource.merge(resourceFromAttributes({ [ATTR_SERVICE_NAME]: o.serviceName }));
159
+ return resource;
160
+ }
161
+ /**
162
+ * `init()` passes a list when it configured logs itself and `undefined` to
163
+ * defer to `OTEL_LOGS_EXPORTER`. Only `otlp` (over HTTP) and `none`/unset
164
+ * are honoured there; any other value is named in a warning.
165
+ */
166
+ resolveLogProcessors() {
167
+ const configured = this.options.logRecordProcessors;
168
+ if (configured) return configured;
169
+ const fromEnv = process.env.OTEL_LOGS_EXPORTER?.trim().toLowerCase();
170
+ if (!fromEnv || fromEnv === "none") return void 0;
171
+ if (fromEnv === "otlp") return [new BatchLogRecordProcessor({ exporter: new OTLPLogExporter() })];
172
+ diag.warn(`[autotel] OTEL_LOGS_EXPORTER=${fromEnv} is not supported without sdk-node; pass a log exporter via init() instead.`);
173
+ }
174
+ };
175
+
176
+ //#endregion
28
177
  //#region src/rate-limiter.ts
29
178
  /**
30
179
  * Token bucket rate limiter
@@ -510,28 +659,30 @@ var EventQueue = class {
510
659
  */
511
660
  async sendWithRetry(events, retriesLeft, subscribersByEventIndex) {
512
661
  const failedDeliveries = await this.sendToSubscribers(events, subscribersByEventIndex);
513
- if (failedDeliveries.length > 0) if (retriesLeft > 0) {
514
- const failedEventIndicesOrdered = [...new Set(failedDeliveries.map((f) => f.eventIndex))].toSorted((a, b) => a - b);
515
- const eventsToRetry = failedEventIndicesOrdered.map((i) => events[i]);
516
- const failedSubscribersByRetryIndex = /* @__PURE__ */ new Map();
517
- for (const [j, origIndex] of failedEventIndicesOrdered.entries()) {
518
- const set = /* @__PURE__ */ new Set();
519
- for (const { eventIndex, subscriberName } of failedDeliveries) if (eventIndex === origIndex) set.add(subscriberName);
520
- failedSubscribersByRetryIndex.set(j, set);
521
- }
522
- const delay = Math.pow(2, this.config.maxRetries - retriesLeft) * 1e3;
523
- await new Promise((resolve) => setTimeout(resolve, delay));
524
- return this.sendWithRetry(eventsToRetry, retriesLeft - 1, failedSubscribersByRetryIndex);
525
- } else {
526
- for (const { eventIndex, subscriberName, error } of failedDeliveries) {
527
- const event = events[eventIndex];
528
- if (event) this.recordFailed(event, subscriberName, error);
662
+ if (failedDeliveries.length > 0) {
663
+ if (retriesLeft > 0) {
664
+ const failedEventIndicesOrdered = [...new Set(failedDeliveries.map((f) => f.eventIndex))].toSorted((a, b) => a - b);
665
+ const eventsToRetry = failedEventIndicesOrdered.map((i) => events[i]);
666
+ const failedSubscribersByRetryIndex = /* @__PURE__ */ new Map();
667
+ for (const [j, origIndex] of failedEventIndicesOrdered.entries()) {
668
+ const set = /* @__PURE__ */ new Set();
669
+ for (const { eventIndex, subscriberName } of failedDeliveries) if (eventIndex === origIndex) set.add(subscriberName);
670
+ failedSubscribersByRetryIndex.set(j, set);
671
+ }
672
+ const delay = Math.pow(2, this.config.maxRetries - retriesLeft) * 1e3;
673
+ await new Promise((resolve) => setTimeout(resolve, delay));
674
+ return this.sendWithRetry(eventsToRetry, retriesLeft - 1, failedSubscribersByRetryIndex);
675
+ } else {
676
+ for (const { eventIndex, subscriberName, error } of failedDeliveries) {
677
+ const event = events[eventIndex];
678
+ if (event) this.recordFailed(event, subscriberName, error);
679
+ }
680
+ const failedSubscriberNames = [...new Set(failedDeliveries.map((f) => f.subscriberName))];
681
+ getLogger().error({
682
+ failedSubscribers: failedSubscriberNames,
683
+ retriesAttempted: this.config.maxRetries
684
+ }, "[autotel] Failed to send events after retries");
529
685
  }
530
- const failedSubscriberNames = [...new Set(failedDeliveries.map((f) => f.subscriberName))];
531
- getLogger().error({
532
- failedSubscribers: failedSubscriberNames,
533
- retriesAttempted: this.config.maxRetries
534
- }, "[autotel] Failed to send events after retries");
535
686
  }
536
687
  }
537
688
  /**
@@ -888,7 +1039,8 @@ function getOrCreateQueue() {
888
1039
  function track(event, data, options) {
889
1040
  const queue = getOrCreateQueue();
890
1041
  if (!queue) return;
891
- const validated = validateEvent(event, data, getValidationConfig() || void 0);
1042
+ const validationConfig = getValidationConfig();
1043
+ const validated = validateEvent(event, data, validationConfig || void 0);
892
1044
  const span = trace.getActiveSpan();
893
1045
  const enrichedData = span ? {
894
1046
  ...validated.attributes,
@@ -1945,6 +2097,76 @@ var BaggageSpanProcessor = class {
1945
2097
  async forceFlush() {}
1946
2098
  };
1947
2099
 
2100
+ //#endregion
2101
+ //#region src/request-attributes.ts
2102
+ /**
2103
+ * Attributes set through `requestCtx` describe the whole request, so every
2104
+ * span started inside that request carries them too - not only the request
2105
+ * span. This stays in-process: nothing rides baggage, so a `user.email` set in
2106
+ * auth middleware never leaves in a `baggage` header on an outgoing call.
2107
+ */
2108
+ /**
2109
+ * The key `@opentelemetry/core` publishes RPC metadata under. `createContextKey`
2110
+ * is `Symbol.for`, so this reads exactly what `instrumentation-http` (and every
2111
+ * framework instrumentation that renames the route) wrote, without taking a
2112
+ * dependency on core.
2113
+ */
2114
+ const RPC_METADATA_KEY = createContextKey("OpenTelemetry SDK Context Key RPC_METADATA");
2115
+ /** The server span of the request `ctx` belongs to, if it belongs to one. */
2116
+ function getRequestSpanIn(ctx = context.active()) {
2117
+ const requestSpan = readProperty(ctx.getValue(RPC_METADATA_KEY), "span");
2118
+ return isFunction(readProperty(requestSpan, "spanContext")) ? requestSpan : void 0;
2119
+ }
2120
+ const scopes = /* @__PURE__ */ new WeakMap();
2121
+ function scopeFor(span) {
2122
+ let scope = scopes.get(span);
2123
+ if (!scope) {
2124
+ scope = { attributes: {} };
2125
+ scopes.set(span, scope);
2126
+ }
2127
+ return scope;
2128
+ }
2129
+ /**
2130
+ * The request span's attributes, or else every ancestor `requestCtx` wrote to,
2131
+ * merged so the nearer one wins a key: a job span tagging `job.id` under a
2132
+ * consumer that tagged `tenant` must not hide the tenant from its children.
2133
+ */
2134
+ function sourceOf(parentContext) {
2135
+ const requestSpan = getRequestSpanIn(parentContext);
2136
+ if (requestSpan) return scopes.get(requestSpan)?.attributes;
2137
+ const nearestFirst = [];
2138
+ const parent = trace.getSpan(parentContext);
2139
+ for (let scope = parent && scopes.get(parent); scope; scope = scope.parent) nearestFirst.push(scope.attributes);
2140
+ return nearestFirst.length > 0 ? Object.assign({}, ...nearestFirst.toReversed()) : void 0;
2141
+ }
2142
+ /** Remember attributes set through `requestCtx`, for the spans started under it. */
2143
+ function rememberRequestAttributes(span, attrs) {
2144
+ Object.assign(scopeFor(span).attributes, attrs);
2145
+ }
2146
+ /**
2147
+ * Copies `requestCtx` attributes onto each span started inside the request -
2148
+ * or, outside one, under the span `requestCtx` fell back to. Only what was set
2149
+ * before the span started is copied, and a key the span already carries keeps
2150
+ * its own value.
2151
+ */
2152
+ var RequestAttributesSpanProcessor = class {
2153
+ onStart(span, parentContext) {
2154
+ const parent = trace.getSpan(parentContext);
2155
+ if (parent) scopeFor(span).parent = scopeFor(parent);
2156
+ const attrs = sourceOf(parentContext);
2157
+ if (!attrs) return;
2158
+ const own = span.attributes;
2159
+ for (const [key, value] of Object.entries(attrs)) if (value !== void 0 && !(key in own)) span.setAttribute(key, value);
2160
+ }
2161
+ onEnd() {}
2162
+ forceFlush() {
2163
+ return Promise.resolve();
2164
+ }
2165
+ shutdown() {
2166
+ return Promise.resolve();
2167
+ }
2168
+ };
2169
+
1948
2170
  //#endregion
1949
2171
  //#region src/redact-values.ts
1950
2172
  /** Standalone string redaction for use outside the span processor pipeline. */
@@ -2990,7 +3212,8 @@ var Event = class {
2990
3212
  * ```
2991
3213
  */
2992
3214
  trackEvent(eventName, attributes) {
2993
- const validated = validateEvent(eventName, attributes, getValidationConfig() || void 0);
3215
+ const validationConfig = getValidationConfig();
3216
+ const validated = validateEvent(eventName, attributes, validationConfig || void 0);
2994
3217
  const enrichedAttributes = this.enrichWithTelemetryContext(validated.attributes);
2995
3218
  this.logger?.info({
2996
3219
  event: validated.eventName,
@@ -4052,7 +4275,8 @@ function init(cfg) {
4052
4275
  if (devtoolsConfig.enabled && mergedConfig.logs === void 0) mergedConfig.logs = true;
4053
4276
  const silent = mergedConfig.silent ?? false;
4054
4277
  const minLevel = mergedConfig.minLevel ?? "info";
4055
- logger = wrapLogger(mergedConfig.logger || silentLogger, silent, minLevel);
4278
+ const baseLogger = mergedConfig.logger || silentLogger;
4279
+ logger = wrapLogger(baseLogger, silent, minLevel);
4056
4280
  if (initialized) logger.warn({}, "[autotel] init() called again - last config wins. This may cause unexpected behavior.");
4057
4281
  config = mergedConfig;
4058
4282
  validationConfig = mergedConfig.validation || null;
@@ -4144,6 +4368,7 @@ function init(cfg) {
4144
4368
  mergedConfig.spanFilter = userSpanFilter ? (span) => userSpanFilter(span) && policySpanFilter(span) : policySpanFilter;
4145
4369
  }
4146
4370
  if (mergedConfig.spanFilter && spanProcessors.length > 0) spanProcessors = spanProcessors.map((processor) => new FilteringSpanProcessor(processor, { filter: mergedConfig.spanFilter }));
4371
+ if (spanProcessors.length > 0) spanProcessors.unshift(new RequestAttributesSpanProcessor());
4147
4372
  if (mergedConfig.spanEnrichers && mergedConfig.spanEnrichers.length > 0) spanProcessors.unshift(...mergedConfig.spanEnrichers);
4148
4373
  const metricReaders = [];
4149
4374
  if (configuredMetricReaders && configuredMetricReaders.length > 0) metricReaders.push(...configuredMetricReaders);
@@ -4165,10 +4390,11 @@ function init(cfg) {
4165
4390
  if (logsEnabled) {
4166
4391
  for (const destination of otlpDestinations) {
4167
4392
  if (!destinationSupportsSignal(destination, "logs")) continue;
4168
- let processor = new BatchLogRecordProcessor({ exporter: createLogExporter(destination.protocol, {
4393
+ const logExporter = createLogExporter(destination.protocol, {
4169
4394
  url: formatEndpointUrl(destination.endpoint, "logs", destination.protocol),
4170
4395
  headers: destination.headers
4171
- }) });
4396
+ });
4397
+ let processor = new BatchLogRecordProcessor({ exporter: logExporter });
4172
4398
  if (_stringRedactor) processor = new RedactingLogRecordProcessor(processor, _stringRedactor);
4173
4399
  if (!logRecordProcessors) logRecordProcessors = [];
4174
4400
  logRecordProcessors.push(processor);
@@ -4210,8 +4436,8 @@ function init(cfg) {
4210
4436
  if (metricReaders.length > 0) sdkOptions.metricReaders = metricReaders;
4211
4437
  if (logRecordProcessors && logRecordProcessors.length > 0) sdkOptions.logRecordProcessors = logRecordProcessors;
4212
4438
  else if (!process.env.OTEL_LOGS_EXPORTER) sdkOptions.logRecordProcessors = [];
4213
- sdk = mergedConfig.sdkFactory ? mergedConfig.sdkFactory(sdkOptions) : new NodeSDK(sdkOptions);
4214
- if (!sdk) throw new Error("[autotel] sdkFactory must return a NodeSDK instance");
4439
+ sdk = mergedConfig.sdkFactory ? mergedConfig.sdkFactory(sdkOptions) : new AutotelSdk(sdkOptions);
4440
+ if (!sdk) throw new Error("[autotel] sdkFactory must return an SDK instance");
4215
4441
  sdk.start();
4216
4442
  if (mergedConfig.openllmetry?.enabled) {
4217
4443
  const traceloop = _optionalRequire("@traceloop/node-server-sdk");
@@ -4307,4 +4533,4 @@ function getSdk() {
4307
4533
  }
4308
4534
 
4309
4535
  //#endregion
4310
- export { getCorrelationStorage as $, FeatureFlagSampler as A, markForceKept as B, AUTOTEL_SAMPLING_RATE as C, AlwaysSampler as D, AdaptiveSampler as E, createLinkFromHeaders as F, getActiveContextWithBaggage as G, samplingPresets as H, debugCaptureRequested as I, getEventQueue as J, getContextStorage as K, extractLinksFromBatch as L, NeverSampler as M, RandomSampler as N, CompositeSampler as O, UserIdSampler as P, getCorrelationId as Q, hashUnitInterval as R, AUTOTEL_DEBUG_BAGGAGE_KEY as S, AUTOTEL_SAMPLING_TAIL_KEEP as T, createTraceContext as U, resolveSamplingPreset as V, defineBaggageSchema as W, CORRELATION_ID_BAGGAGE_KEY as X, track as Y, generateCorrelationId as Z, loadYamlConfig as _, init as a, BaggageSpanProcessor as b, lockLogger as c, Event as d, getOrCreateCorrelationId as et, getEvents as f, hasYamlConfig as g, runInOperationContext as h, getSdk as i, KeyTargetRateSampler as j, DeterministicSampler as k, flush as l, getOperationContext as m, getConfiguredSampler as n, setCorrelationId as nt, isInitialized as o, resetEvents as p, hasExplicitSpanStatus as q, getLogger as r, setCorrelationIdInBaggage as rt, isLoggerLocked as s, getConfig as t, runWithCorrelationId as tt, shutdown as u, loadYamlConfigFromFile as v, AUTOTEL_SAMPLING_TAIL_EVALUATED as w, TailSamplingSpanProcessor as x, createStringRedactor as y, isForceKept as z };
4536
+ 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, getContextStorage 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, hasExplicitSpanStatus 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, getActiveContextWithBaggage 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 };
@@ -1,17 +1,43 @@
1
1
  import { a as AttributeRedactorPreset, r as AttributeRedactorConfig } from "./attribute-redacting-processor-CvBE0z1p.cjs";
2
2
  import { s as Logger } from "./logger-S1Fgl0g3.cjs";
3
- import { g as SamplingPreset, m as Sampler } from "./sampling-Er217Mge.cjs";
3
+ import { g as SamplingPreset, m as Sampler$1 } from "./sampling-DENUjT_8.cjs";
4
4
  import { o as EventSubscriber } from "./event-subscriber-DMACQA-1.cjs";
5
5
  import { r as SpanFilterPredicate } from "./filtering-span-processor-BpDagWNa.cjs";
6
6
  import { r as Policy } from "./policy-C4QcZnqv.cjs";
7
7
  import { r as SpanNameNormalizerConfig } from "./span-name-normalizer-CN1-8C76.cjs";
8
8
  import { t as CanonicalLogLineOptions } from "./canonical-log-line-processor-C0Z_N4oL.cjs";
9
- import { ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
10
- import { Attributes } from "@opentelemetry/api";
11
- import { Resource } from "@opentelemetry/resources";
12
- import { NodeSDK, NodeSDKConfiguration } from "@opentelemetry/sdk-node";
13
- import { MetricReader } from "@opentelemetry/sdk-metrics";
9
+ import { BasicTracerProvider, ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
10
+ import { Attributes, Sampler, TextMapPropagator } from "@opentelemetry/api";
11
+ import { Resource, ResourceDetector } from "@opentelemetry/resources";
12
+ import { Instrumentation } from "@opentelemetry/instrumentation";
14
13
  import { LogRecordProcessor } from "@opentelemetry/sdk-logs";
14
+ import { IMetricReader, MetricReader } from "@opentelemetry/sdk-metrics";
15
+ //#region src/sdk.d.ts
16
+ /**
17
+ * What `init()` hands the SDK. Field names match `NodeSDKConfiguration` so a
18
+ * `sdkFactory` written against the old shape still receives what it expects.
19
+ */
20
+ interface AutotelSdkOptions {
21
+ resource?: Resource;
22
+ serviceName?: string;
23
+ sampler?: Sampler;
24
+ instrumentations?: (Instrumentation | Instrumentation[])[];
25
+ spanProcessors?: SpanProcessor[];
26
+ metricReaders?: IMetricReader[];
27
+ logRecordProcessors?: LogRecordProcessor[];
28
+ /** `null` leaves whatever propagator is already registered alone. */
29
+ textMapPropagator?: TextMapPropagator | null;
30
+ /** Off by default only via `OTEL_NODE_RESOURCE_DETECTORS=none`. */
31
+ autoDetectResources?: boolean;
32
+ resourceDetectors?: ResourceDetector[];
33
+ }
34
+ /** The surface autotel needs from an SDK handle; `NodeSDK` satisfies it too. */
35
+ interface AutotelSdkLike {
36
+ start(): void;
37
+ shutdown(): Promise<void>;
38
+ getTracerProvider?(): BasicTracerProvider | undefined;
39
+ }
40
+ //#endregion
15
41
  //#region src/validation.d.ts
16
42
  interface ValidationConfig {
17
43
  /** Max event name length (default: 100) */
@@ -432,7 +458,7 @@ interface AutotelConfig {
432
458
  * })
433
459
  * ```
434
460
  */
435
- instrumentations?: NodeSDKConfiguration['instrumentations'];
461
+ instrumentations?: AutotelSdkOptions['instrumentations'];
436
462
  /**
437
463
  * Simple names for auto-instrumentation.
438
464
  * Uses @opentelemetry/auto-instrumentations-node (peer dependency).
@@ -756,9 +782,11 @@ interface AutotelConfig {
756
782
  */
757
783
  protocol?: AutotelProtocol;
758
784
  /**
759
- * Optional factory to build a customised NodeSDK instance from our defaults.
785
+ * Optional factory to build a customised SDK from our defaults. The options
786
+ * use `NodeSDKConfiguration`'s field names, so `new NodeSDK(defaults)` from
787
+ * `@opentelemetry/sdk-node` is a valid return value.
760
788
  */
761
- sdkFactory?: (defaults: Partial<NodeSDKConfiguration>) => NodeSDK;
789
+ sdkFactory?: (defaults: AutotelSdkOptions) => AutotelSdkLike;
762
790
  /**
763
791
  * Infrastructure metrics configuration
764
792
  * - true: always enabled (default)
@@ -794,7 +822,7 @@ interface AutotelConfig {
794
822
  */
795
823
  logs?: boolean | 'auto';
796
824
  /** Sampling strategy - takes precedence over `sampling` preset */
797
- sampler?: Sampler;
825
+ sampler?: Sampler$1;
798
826
  /**
799
827
  * Sampling preset shorthand — resolves to a pre-configured sampler.
800
828
  * If both `sampler` and `sampling` are provided, `sampler` takes precedence.
@@ -1,17 +1,43 @@
1
- import { a as AttributeRedactorPreset, r as AttributeRedactorConfig } from "./attribute-redacting-processor-CvBE0z1p.js";
1
+ import { a as AttributeRedactorPreset, r as AttributeRedactorConfig } from "./attribute-redacting-processor-rkV_WL-k.js";
2
2
  import { s as Logger } from "./logger-S1Fgl0g3.js";
3
- import { g as SamplingPreset, m as Sampler } from "./sampling-DBng4Foa.js";
3
+ import { g as SamplingPreset, m as Sampler$1 } from "./sampling-CZi7OM9u.js";
4
4
  import { o as EventSubscriber } from "./event-subscriber-DMACQA-1.js";
5
- import { r as SpanFilterPredicate } from "./filtering-span-processor-BpDagWNa.js";
6
- import { r as Policy } from "./policy-C4QcZnqv.js";
7
- import { r as SpanNameNormalizerConfig } from "./span-name-normalizer-CN1-8C76.js";
8
- import { t as CanonicalLogLineOptions } from "./canonical-log-line-processor-Yq4cXcD5.js";
9
- import { NodeSDK, NodeSDKConfiguration } from "@opentelemetry/sdk-node";
10
- import { ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
11
- import { Resource } from "@opentelemetry/resources";
12
- import { Attributes } from "@opentelemetry/api";
13
- import { MetricReader } from "@opentelemetry/sdk-metrics";
5
+ import { r as SpanFilterPredicate } from "./filtering-span-processor-vkewzbqB.js";
6
+ import { r as Policy } from "./policy-DNw_0qUq.js";
7
+ import { r as SpanNameNormalizerConfig } from "./span-name-normalizer-DHcg1bSP.js";
8
+ import { t as CanonicalLogLineOptions } from "./canonical-log-line-processor-Bwrt_L4c.js";
9
+ import { Attributes, Sampler, TextMapPropagator } from "@opentelemetry/api";
10
+ import { Instrumentation } from "@opentelemetry/instrumentation";
11
+ import { Resource, ResourceDetector } from "@opentelemetry/resources";
14
12
  import { LogRecordProcessor } from "@opentelemetry/sdk-logs";
13
+ import { IMetricReader, MetricReader } from "@opentelemetry/sdk-metrics";
14
+ import { BasicTracerProvider, ReadableSpan, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
15
+ //#region src/sdk.d.ts
16
+ /**
17
+ * What `init()` hands the SDK. Field names match `NodeSDKConfiguration` so a
18
+ * `sdkFactory` written against the old shape still receives what it expects.
19
+ */
20
+ interface AutotelSdkOptions {
21
+ resource?: Resource;
22
+ serviceName?: string;
23
+ sampler?: Sampler;
24
+ instrumentations?: (Instrumentation | Instrumentation[])[];
25
+ spanProcessors?: SpanProcessor[];
26
+ metricReaders?: IMetricReader[];
27
+ logRecordProcessors?: LogRecordProcessor[];
28
+ /** `null` leaves whatever propagator is already registered alone. */
29
+ textMapPropagator?: TextMapPropagator | null;
30
+ /** Off by default only via `OTEL_NODE_RESOURCE_DETECTORS=none`. */
31
+ autoDetectResources?: boolean;
32
+ resourceDetectors?: ResourceDetector[];
33
+ }
34
+ /** The surface autotel needs from an SDK handle; `NodeSDK` satisfies it too. */
35
+ interface AutotelSdkLike {
36
+ start(): void;
37
+ shutdown(): Promise<void>;
38
+ getTracerProvider?(): BasicTracerProvider | undefined;
39
+ }
40
+ //#endregion
15
41
  //#region src/validation.d.ts
16
42
  interface ValidationConfig {
17
43
  /** Max event name length (default: 100) */
@@ -432,7 +458,7 @@ interface AutotelConfig {
432
458
  * })
433
459
  * ```
434
460
  */
435
- instrumentations?: NodeSDKConfiguration['instrumentations'];
461
+ instrumentations?: AutotelSdkOptions['instrumentations'];
436
462
  /**
437
463
  * Simple names for auto-instrumentation.
438
464
  * Uses @opentelemetry/auto-instrumentations-node (peer dependency).
@@ -756,9 +782,11 @@ interface AutotelConfig {
756
782
  */
757
783
  protocol?: AutotelProtocol;
758
784
  /**
759
- * Optional factory to build a customised NodeSDK instance from our defaults.
785
+ * Optional factory to build a customised SDK from our defaults. The options
786
+ * use `NodeSDKConfiguration`'s field names, so `new NodeSDK(defaults)` from
787
+ * `@opentelemetry/sdk-node` is a valid return value.
760
788
  */
761
- sdkFactory?: (defaults: Partial<NodeSDKConfiguration>) => NodeSDK;
789
+ sdkFactory?: (defaults: AutotelSdkOptions) => AutotelSdkLike;
762
790
  /**
763
791
  * Infrastructure metrics configuration
764
792
  * - true: always enabled (default)
@@ -794,7 +822,7 @@ interface AutotelConfig {
794
822
  */
795
823
  logs?: boolean | 'auto';
796
824
  /** Sampling strategy - takes precedence over `sampling` preset */
797
- sampler?: Sampler;
825
+ sampler?: Sampler$1;
798
826
  /**
799
827
  * Sampling preset shorthand — resolves to a pre-configured sampler.
800
828
  * If both `sampler` and `sampling` are provided, `sampler` takes precedence.