@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 +37 -1
- package/dist/index.d.mts +42 -5
- package/dist/index.mjs +455 -84
- package/package.json +1 -1
- package/src/config.ts +1 -1
- package/src/index.ts +9 -0
- package/src/otel.ts +7 -1
- package/src/session.ts +260 -0
- package/src/transport.ts +256 -87
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
|
|
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():
|
|
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 };
|