@telemetry-dev/otel 0.1.0 → 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
 
@@ -9,7 +9,7 @@ import { LogRecordExporter } from "@opentelemetry/sdk-logs";
9
9
  declare const SCOPE_NAME = "@telemetry-dev/sdk";
10
10
  declare const SCOPE_VERSION = "0.0.0";
11
11
  declare function omitUndefined(attributes: Attributes): Attributes;
12
- declare function jsonAttr(value: unknown): string | undefined;
12
+ declare function jsonAttr<T>(value: T): string | undefined;
13
13
  //#endregion
14
14
  //#region src/config.d.ts
15
15
  type LogLevel = "debug" | "info" | "warn" | "error";
@@ -39,13 +39,13 @@ declare function activeContext(): Context;
39
39
  /** Run `fn` with `ctx` active in both our ALS and the global OTel context manager. */
40
40
  declare function withContext<T>(ctx: Context, fn: () => T): T;
41
41
  declare const PROPAGATED_KEY: symbol;
42
- interface PropagatedAttributes {
42
+ interface PropagatedAttributes<MetadataValue = unknown> {
43
43
  /** Stamped as user.id on every span and log record in scope. */
44
44
  userId?: string;
45
45
  /** Stamped as gen_ai.conversation.id on every span and log record in scope. */
46
46
  sessionId?: string;
47
47
  /** Stamped as td.metadata.<key> on every span and log record in scope. */
48
- metadata?: Record<string, unknown>;
48
+ metadata?: Record<string, MetadataValue>;
49
49
  }
50
50
  declare function buildPropagatedAttributes(attrs: PropagatedAttributes): Attributes;
51
51
  declare function propagatedFromContext(ctx: Context): Attributes | undefined;
@@ -74,7 +74,7 @@ declare const diag: {
74
74
  error: (...args: unknown[]) => void;
75
75
  };
76
76
  /** Fail-open guard: SDK internals report through onError + diagnostics, never into user code. */
77
- declare function reportError(onError: ((error: unknown) => void) | undefined, error: unknown): void;
77
+ declare function reportError(onError: ((error: Error) => void) | undefined, cause: unknown): void;
78
78
  //#endregion
79
79
  //#region src/metrics.d.ts
80
80
  declare const DURATION_BUCKETS: number[];
@@ -114,7 +114,7 @@ interface TelemetrySpanProcessorOptions {
114
114
  /** deployment.environment.name on the metrics resource. Falls back to `TELEMETRY_DEV_ENVIRONMENT`. */
115
115
  environment?: string;
116
116
  fetch?: typeof fetch;
117
- onError?: (error: unknown) => void;
117
+ onError?: (error: Error) => void;
118
118
  /** Advanced/test seam: replaces the OTLP fetch exporter. */
119
119
  spanExporter?: SpanExporter;
120
120
  }
@@ -137,7 +137,8 @@ declare function createTelemetrySpanExporter(options?: {
137
137
  apiKey?: string;
138
138
  baseUrl?: string;
139
139
  fetch?: typeof fetch;
140
- onError?: (error: unknown) => void;
140
+ onError?: (error: Error) => void;
141
+ exportTimeoutMillis?: number;
141
142
  }): SpanExporter;
142
143
  //#endregion
143
144
  //#region src/processor.d.ts
@@ -147,7 +148,7 @@ interface StampingProcessorOptions {
147
148
  batch: Required<BatchOptions>;
148
149
  spanFilter?: (span: ReadableSpan) => boolean;
149
150
  recordMetrics?: (span: ReadableSpan) => void;
150
- onError?: (error: unknown) => void;
151
+ onError?: (error: Error) => void;
151
152
  }
152
153
  /**
153
154
  * The vendor span processor: stamps propagated correlation attributes onto every span at start,
@@ -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
- onError?: (error: unknown) => void;
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;
@@ -190,6 +227,10 @@ declare function maybeGzip(body: Uint8Array): Promise<{
190
227
  declare function createTraceExporter(target: OtlpTarget, transport: Transport): SpanExporter;
191
228
  declare function createLogExporter(target: OtlpTarget, transport: Transport): LogRecordExporter;
192
229
  declare function createMetricExporter(target: OtlpTarget, transport: Transport): PushMetricExporter;
193
- declare function otlpHeaders(apiKey: string): Record<string, string>;
230
+ declare function otlpHeaders(apiKey: string, sdkName?: string): {
231
+ "content-type": string;
232
+ authorization: string;
233
+ "x-telemetry-dev-sdk": string;
234
+ };
194
235
  //#endregion
195
- 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 };