@telemetry-dev/otel 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,8 +80,44 @@ import { createTelemetrySpanExporter } from "@telemetry-dev/otel";
80
80
  const processor = new BatchSpanProcessor(createTelemetrySpanExporter());
81
81
  ```
82
82
 
83
- The exporter reads `apiKey`, `baseUrl`, `fetch`, and `onError` from the same option names and environment variables as `TelemetrySpanProcessor`.
83
+ The exporter accepts `apiKey`, `baseUrl`, `fetch`, `onError`, and `exportTimeoutMillis`. The timeout caps each export request and defaults to 30,000 ms. The API key and base URL use the same environment variable fallbacks as `TelemetrySpanProcessor`.
84
84
 
85
85
  ## Correlation attributes
86
86
 
87
87
  `propagateAttributes({ userId, sessionId, metadata }, fn)` works standalone with BYO providers. The function stores correlation attributes in the same OTel context key that `TelemetrySpanProcessor` reads on span start, so spans created inside `fn` receive `user.id`, `gen_ai.conversation.id`, and `td.metadata.*` attributes without installing `@telemetry-dev/sdk`.
88
+
89
+ `TelemetrySpanProcessor` on your provider adds `gen_ai.conversation.id`, but it cannot change trace IDs. Use `withSessionParent(context.active(), sessionId, apiKey)` for each root span. A nonempty API key and session ID put each session root in the same trace. A deterministic session parent (`SHA-256(apiKey ‖ 0x00 ‖ sessionId)`) is the parent, but the SDK does not send it. If one value is empty, the function keeps the input context.
90
+
91
+ **Install `sessionSampler(yourSampler)` on the provider before you use `withSessionParent` or `sessionRootTracerProvider`.** The OTel API does not expose a provider's sampler. A context helper alone cannot keep the root policy. Pass the existing programmatic sampler to the wrapper. Without an argument, `sessionSampler()` reads `OTEL_TRACES_SAMPLER` and `OTEL_TRACES_SAMPLER_ARG`. It does not inspect an existing provider.
92
+
93
+ The wrapper uses the original parent context and the deterministic session trace ID for the sampling decision. Real active and explicit parents keep their sampling decisions. The framework-root wrapper reparents recognized turns inside workflow spans, but keeps the workflow parent's sampling policy and trace state. Context values and baggage stay intact.
94
+
95
+ `sessionSpanContext` only calculates IDs. Its flags are not a sampling decision. Do not use it directly as a parent.
96
+
97
+ ```ts
98
+ import { context } from "@opentelemetry/api";
99
+ import {
100
+ BasicTracerProvider,
101
+ ParentBasedSampler,
102
+ TraceIdRatioBasedSampler,
103
+ } from "@opentelemetry/sdk-trace-base";
104
+ import { sessionSampler, TelemetrySpanProcessor, withSessionParent } from "@telemetry-dev/otel";
105
+
106
+ const sampler = new ParentBasedSampler({ root: new TraceIdRatioBasedSampler(0.1) });
107
+ const provider = new BasicTracerProvider({
108
+ sampler: sessionSampler(sampler),
109
+ spanProcessors: [new TelemetrySpanProcessor()],
110
+ });
111
+ const span = provider
112
+ .getTracer("my-app")
113
+ .startSpan(
114
+ "turn",
115
+ {},
116
+ withSessionParent(context.active(), sessionId, process.env.TELEMETRY_DEV_API_KEY),
117
+ );
118
+ span.end();
119
+ ```
120
+
121
+ The environment modes are `always_on`, `always_off`, `traceidratio`, `parentbased_always_on` (default), `parentbased_always_off`, and `parentbased_traceidratio`.
122
+ Ratio modes accept a finite argument in `[0, 1]`. Missing, invalid, or out-of-range arguments use `1` and cause an OTel diagnostic. Unknown modes use `parentbased_always_on`.
123
+ The TypeScript and Python SDKs share deterministic session IDs. Their built-in ratio samplers can select different sessions because the OTel algorithms differ.
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { Attributes, Context, ContextManager } from "@opentelemetry/api";
1
+ import { Attributes, Context, ContextManager, SpanContext, TracerProvider } from "@opentelemetry/api";
2
2
  import { PushMetricExporter } from "@opentelemetry/sdk-metrics";
3
3
  import { Resource } from "@opentelemetry/resources";
4
- import { ReadableSpan, Span, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
4
+ import { ReadableSpan, Sampler, Span, SpanExporter, SpanProcessor } from "@opentelemetry/sdk-trace-base";
5
5
  import { AsyncLocalStorage } from "node:async_hooks";
6
6
  import { LogRecordExporter } from "@opentelemetry/sdk-logs";
7
7
 
@@ -27,7 +27,7 @@ interface BatchOptions {
27
27
  }
28
28
  declare const DEFAULT_BASE_URL = "https://ingest.telemetry.dev";
29
29
  declare const DEFAULT_BATCH: Required<BatchOptions>;
30
- declare function resolveEnv(): NodeJS.ProcessEnv;
30
+ declare function resolveEnv(): Record<string, string | undefined>;
31
31
  //#endregion
32
32
  //#region src/context.d.ts
33
33
  declare const als: AsyncLocalStorage<Context> | undefined;
@@ -138,6 +138,7 @@ declare function createTelemetrySpanExporter(options?: {
138
138
  baseUrl?: string;
139
139
  fetch?: typeof fetch;
140
140
  onError?: (error: Error) => void;
141
+ exportTimeoutMillis?: number;
141
142
  }): SpanExporter;
142
143
  //#endregion
143
144
  //#region src/processor.d.ts
@@ -163,10 +164,44 @@ declare class StampingSpanProcessor implements SpanProcessor {
163
164
  shutdown(): Promise<void>;
164
165
  }
165
166
  //#endregion
167
+ //#region src/session.d.ts
168
+ /**
169
+ * Install on the provider used with withSessionParent or sessionRootTracerProvider.
170
+ * Pass the provider's configured sampler explicitly; OTel cannot read it back from a provider.
171
+ * Without an argument, uses OTEL_TRACES_SAMPLER / OTEL_TRACES_SAMPLER_ARG defaults.
172
+ */
173
+ declare function sessionSampler(inner?: Sampler): Sampler;
174
+ /**
175
+ * Deterministic remote parent for a session: every root span of the session joins one trace
176
+ * (`traceId = SHA-256(apiKey ‖ 0x00 ‖ sessionId)[0:16]`, parent `spanId = digest[16:24]`).
177
+ * The API key is part of the input so two projects with the same session id never share a trace
178
+ * id. No span is ever emitted for the parent. Its flags are not a sampling decision:
179
+ * use withSessionParent and install sessionSampler on the provider. Python mirrors these IDs.
180
+ */
181
+ declare function sessionSpanContext(apiKey: string | undefined, sessionId: string): SpanContext;
182
+ /** Returns the session id when a span must start a new turn in the session trace. */
183
+ type SessionRootOf = (name: string, attributes: Attributes) => string | undefined;
184
+ /**
185
+ * Wraps a provider so that spans `sessionRootOf` recognizes are parented under the session
186
+ * parent even when a parent is active. Frameworks that run each turn inside their own
187
+ * engine span (eve's "workflow" scope) otherwise give every turn its own trace.
188
+ * The inner provider MUST use sessionSampler(configuredSampler) to retain sampling policy.
189
+ */
190
+ declare function sessionRootTracerProvider(inner: TracerProvider, apiKey: string | undefined, sessionRootOf: SessionRootOf, onError?: (error: Error) => void): TracerProvider;
191
+ /**
192
+ * Parent a would-be root under the session; nested spans keep their real parent.
193
+ * Requires sessionSampler(configuredSampler) on the provider that starts the span.
194
+ */
195
+ declare function withSessionParent(ctx: Context, sessionId: string | undefined, apiKey: string | undefined): Context;
196
+ declare function sessionIdOf(ctx: Context, attributes?: Attributes): string | undefined;
197
+ /** FIPS 180-4 SHA-256 in plain JS: the package must stay synchronous and runtime-neutral. */
198
+ declare function sha256(bytes: Uint8Array): Uint8Array;
199
+ //#endregion
166
200
  //#region src/transport.d.ts
167
201
  interface Transport {
168
202
  fetchImpl: typeof fetch;
169
203
  onError?: (error: Error) => void;
204
+ exportTimeoutMillis?: number;
170
205
  }
171
206
  interface OtlpTarget {
172
207
  url: string;
@@ -176,12 +211,14 @@ declare const postOtlp: ({
176
211
  fetchImpl,
177
212
  url,
178
213
  headers,
179
- body
214
+ body,
215
+ signal
180
216
  }: {
181
217
  fetchImpl: typeof fetch;
182
218
  url: string;
183
219
  headers: Record<string, string>;
184
220
  body: Uint8Array;
221
+ signal?: AbortSignal;
185
222
  }) => Promise<Response>;
186
223
  declare function maybeGzip(body: Uint8Array): Promise<{
187
224
  body: Uint8Array;
@@ -196,4 +233,4 @@ declare function otlpHeaders(apiKey: string, sdkName?: string): {
196
233
  "x-telemetry-dev-sdk": string;
197
234
  };
198
235
  //#endregion
199
- export { AlsContextManager, BATCHED_METRIC_INTERVAL_MS, type BatchOptions, DEFAULT_BASE_URL, DEFAULT_BATCH, DORMANT_INTERVAL_MS, DURATION_BUCKETS, type ExportMode, type LogLevel, type MetricsPipeline, type OtlpTarget, PROPAGATED_KEY, type PropagatedAttributes, SCOPE_NAME, SCOPE_VERSION, type SdkLogLevel, type StampingProcessorOptions, StampingSpanProcessor, TOKEN_BUCKETS, TelemetrySpanProcessor, type TelemetrySpanProcessorOptions, type Transport, activeContext, als, buildPropagatedAttributes, createLogExporter, createMetricExporter, createMetricsPipeline, createTelemetrySpanExporter, createTraceExporter, diag, jsonAttr, maybeGzip, omitUndefined, otlpHeaders, postOtlp, propagateAttributes, propagatedFromContext, reportError, resolveEnv, setLogLevel, withContext };
236
+ export { AlsContextManager, BATCHED_METRIC_INTERVAL_MS, type BatchOptions, DEFAULT_BASE_URL, DEFAULT_BATCH, DORMANT_INTERVAL_MS, DURATION_BUCKETS, type ExportMode, type LogLevel, type MetricsPipeline, type OtlpTarget, PROPAGATED_KEY, type PropagatedAttributes, SCOPE_NAME, SCOPE_VERSION, type SdkLogLevel, type SessionRootOf, type StampingProcessorOptions, StampingSpanProcessor, TOKEN_BUCKETS, TelemetrySpanProcessor, type TelemetrySpanProcessorOptions, type Transport, activeContext, als, buildPropagatedAttributes, createLogExporter, createMetricExporter, createMetricsPipeline, createTelemetrySpanExporter, createTraceExporter, diag, jsonAttr, maybeGzip, omitUndefined, otlpHeaders, postOtlp, propagateAttributes, propagatedFromContext, reportError, resolveEnv, sessionIdOf, sessionRootTracerProvider, sessionSampler, sessionSpanContext, setLogLevel, sha256, withContext, withSessionParent };