@telemetry-dev/otel 0.1.0 → 0.1.1
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/dist/index.d.mts +14 -10
- package/dist/index.mjs +12 -11
- package/package.json +1 -1
- package/src/attrs.ts +9 -1
- package/src/config.ts +3 -4
- package/src/context.ts +2 -2
- package/src/debug.ts +7 -4
- package/src/metrics.ts +5 -5
- package/src/otel.ts +2 -2
- package/src/processor.ts +1 -1
- package/src/transport.ts +7 -6
package/dist/index.d.mts
CHANGED
|
@@ -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:
|
|
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";
|
|
@@ -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(): NodeJS.ProcessEnv;
|
|
31
31
|
//#endregion
|
|
32
32
|
//#region src/context.d.ts
|
|
33
33
|
declare const als: AsyncLocalStorage<Context> | undefined;
|
|
@@ -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,
|
|
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:
|
|
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:
|
|
117
|
+
onError?: (error: Error) => void;
|
|
118
118
|
/** Advanced/test seam: replaces the OTLP fetch exporter. */
|
|
119
119
|
spanExporter?: SpanExporter;
|
|
120
120
|
}
|
|
@@ -137,7 +137,7 @@ declare function createTelemetrySpanExporter(options?: {
|
|
|
137
137
|
apiKey?: string;
|
|
138
138
|
baseUrl?: string;
|
|
139
139
|
fetch?: typeof fetch;
|
|
140
|
-
onError?: (error:
|
|
140
|
+
onError?: (error: Error) => void;
|
|
141
141
|
}): SpanExporter;
|
|
142
142
|
//#endregion
|
|
143
143
|
//#region src/processor.d.ts
|
|
@@ -147,7 +147,7 @@ interface StampingProcessorOptions {
|
|
|
147
147
|
batch: Required<BatchOptions>;
|
|
148
148
|
spanFilter?: (span: ReadableSpan) => boolean;
|
|
149
149
|
recordMetrics?: (span: ReadableSpan) => void;
|
|
150
|
-
onError?: (error:
|
|
150
|
+
onError?: (error: Error) => void;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
153
|
* The vendor span processor: stamps propagated correlation attributes onto every span at start,
|
|
@@ -166,7 +166,7 @@ declare class StampingSpanProcessor implements SpanProcessor {
|
|
|
166
166
|
//#region src/transport.d.ts
|
|
167
167
|
interface Transport {
|
|
168
168
|
fetchImpl: typeof fetch;
|
|
169
|
-
onError?: (error:
|
|
169
|
+
onError?: (error: Error) => void;
|
|
170
170
|
}
|
|
171
171
|
interface OtlpTarget {
|
|
172
172
|
url: string;
|
|
@@ -190,6 +190,10 @@ declare function maybeGzip(body: Uint8Array): Promise<{
|
|
|
190
190
|
declare function createTraceExporter(target: OtlpTarget, transport: Transport): SpanExporter;
|
|
191
191
|
declare function createLogExporter(target: OtlpTarget, transport: Transport): LogRecordExporter;
|
|
192
192
|
declare function createMetricExporter(target: OtlpTarget, transport: Transport): PushMetricExporter;
|
|
193
|
-
declare function otlpHeaders(apiKey: string):
|
|
193
|
+
declare function otlpHeaders(apiKey: string, sdkName?: string): {
|
|
194
|
+
"content-type": string;
|
|
195
|
+
authorization: string;
|
|
196
|
+
"x-telemetry-dev-sdk": string;
|
|
197
|
+
};
|
|
194
198
|
//#endregion
|
|
195
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 };
|
package/dist/index.mjs
CHANGED
|
@@ -34,7 +34,7 @@ const DEFAULT_BATCH = {
|
|
|
34
34
|
exportTimeoutMillis: 3e4
|
|
35
35
|
};
|
|
36
36
|
function resolveEnv() {
|
|
37
|
-
if (
|
|
37
|
+
if (globalThis.process !== void 0 && process.env) return process.env;
|
|
38
38
|
return {};
|
|
39
39
|
}
|
|
40
40
|
//#endregion
|
|
@@ -61,11 +61,11 @@ const diag = {
|
|
|
61
61
|
error: (...args) => emit("error", args)
|
|
62
62
|
};
|
|
63
63
|
/** Fail-open guard: SDK internals report through onError + diagnostics, never into user code. */
|
|
64
|
-
function reportError(onError,
|
|
64
|
+
function reportError(onError, cause) {
|
|
65
65
|
try {
|
|
66
|
-
onError?.(
|
|
66
|
+
onError?.(cause instanceof Error ? cause : new Error(String(cause)));
|
|
67
67
|
} catch {}
|
|
68
|
-
diag.error(
|
|
68
|
+
diag.error(cause);
|
|
69
69
|
}
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region src/context.ts
|
|
@@ -204,7 +204,7 @@ const TOKEN_OPERATIONS = new Set([
|
|
|
204
204
|
const DORMANT_INTERVAL_MS = 2 ** 31 - 1;
|
|
205
205
|
const BATCHED_METRIC_INTERVAL_MS = 6e4;
|
|
206
206
|
function stringAttr(value) {
|
|
207
|
-
return
|
|
207
|
+
return value?.constructor === String ? `${value}` : void 0;
|
|
208
208
|
}
|
|
209
209
|
function createMetricsPipeline({ resource, exporter, exportIntervalMillis }) {
|
|
210
210
|
const reader = new PeriodicExportingMetricReader({
|
|
@@ -226,7 +226,7 @@ function createMetricsPipeline({ resource, exporter, exportIntervalMillis }) {
|
|
|
226
226
|
});
|
|
227
227
|
const record = (span) => {
|
|
228
228
|
const operation = span.attributes["gen_ai.operation.name"];
|
|
229
|
-
if (
|
|
229
|
+
if (operation?.constructor !== String || !DURATION_OPERATIONS.has(`${operation}`)) return;
|
|
230
230
|
const attrs = omitUndefined({
|
|
231
231
|
"gen_ai.operation.name": operation,
|
|
232
232
|
"gen_ai.provider.name": stringAttr(span.attributes["gen_ai.provider.name"]),
|
|
@@ -241,12 +241,12 @@ function createMetricsPipeline({ resource, exporter, exportIntervalMillis }) {
|
|
|
241
241
|
} : attrs);
|
|
242
242
|
if (!TOKEN_OPERATIONS.has(operation)) return;
|
|
243
243
|
const inputTokens = span.attributes["gen_ai.usage.input_tokens"];
|
|
244
|
-
if (
|
|
244
|
+
if (inputTokens?.constructor === Number) tokenHistogram.record(inputTokens, {
|
|
245
245
|
...attrs,
|
|
246
246
|
"gen_ai.token.type": "input"
|
|
247
247
|
});
|
|
248
248
|
const outputTokens = span.attributes["gen_ai.usage.output_tokens"];
|
|
249
|
-
if (
|
|
249
|
+
if (outputTokens?.constructor === Number) tokenHistogram.record(outputTokens, {
|
|
250
250
|
...attrs,
|
|
251
251
|
"gen_ai.token.type": "output"
|
|
252
252
|
});
|
|
@@ -335,7 +335,7 @@ const postOtlp = async ({ fetchImpl, url, headers, body }) => {
|
|
|
335
335
|
};
|
|
336
336
|
const GZIP_THRESHOLD_BYTES = 1024;
|
|
337
337
|
async function maybeGzip(body) {
|
|
338
|
-
if (body.byteLength <= GZIP_THRESHOLD_BYTES ||
|
|
338
|
+
if (body.byteLength <= GZIP_THRESHOLD_BYTES || globalThis.CompressionStream === void 0) return { body };
|
|
339
339
|
try {
|
|
340
340
|
const stream = new Blob([body]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
341
341
|
return {
|
|
@@ -455,10 +455,11 @@ function createMetricExporter(target, transport) {
|
|
|
455
455
|
shutdown: () => Promise.resolve()
|
|
456
456
|
};
|
|
457
457
|
}
|
|
458
|
-
function otlpHeaders(apiKey) {
|
|
458
|
+
function otlpHeaders(apiKey, sdkName = "@telemetry-dev/otel") {
|
|
459
459
|
return {
|
|
460
460
|
"content-type": "application/x-protobuf",
|
|
461
|
-
authorization: `Bearer ${apiKey}
|
|
461
|
+
authorization: `Bearer ${apiKey}`,
|
|
462
|
+
"x-telemetry-dev-sdk": sdkName
|
|
462
463
|
};
|
|
463
464
|
}
|
|
464
465
|
//#endregion
|
package/package.json
CHANGED
package/src/attrs.ts
CHANGED
|
@@ -19,7 +19,15 @@ export function omitUndefined(attributes: Attributes): Attributes {
|
|
|
19
19
|
|
|
20
20
|
// Stringify structured content (messages / tool args) for the gen_ai.* string attributes the
|
|
21
21
|
// ingest parses back into JSON. Returns undefined so omitUndefined drops absent content.
|
|
22
|
-
export
|
|
22
|
+
export type JsonValue =
|
|
23
|
+
| string
|
|
24
|
+
| number
|
|
25
|
+
| boolean
|
|
26
|
+
| null
|
|
27
|
+
| JsonValue[]
|
|
28
|
+
| { [key: string]: JsonValue };
|
|
29
|
+
|
|
30
|
+
export function jsonAttr<T>(value: T): string | undefined {
|
|
23
31
|
if (value === undefined) return undefined;
|
|
24
32
|
if (typeof value === "string") return value;
|
|
25
33
|
try {
|
package/src/config.ts
CHANGED
|
@@ -22,8 +22,7 @@ export const DEFAULT_BATCH: Required<BatchOptions> = {
|
|
|
22
22
|
exportTimeoutMillis: 30000,
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export function resolveEnv()
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
return emptyEnv;
|
|
25
|
+
export function resolveEnv() {
|
|
26
|
+
if (globalThis.process !== undefined && process.env) return process.env;
|
|
27
|
+
return {};
|
|
29
28
|
}
|
package/src/context.ts
CHANGED
|
@@ -53,13 +53,13 @@ export function withContext<T>(ctx: Context, fn: () => T): T {
|
|
|
53
53
|
|
|
54
54
|
export const PROPAGATED_KEY = createContextKey("telemetry.dev propagated attributes");
|
|
55
55
|
|
|
56
|
-
export interface PropagatedAttributes {
|
|
56
|
+
export interface PropagatedAttributes<MetadataValue = unknown> {
|
|
57
57
|
/** Stamped as user.id on every span and log record in scope. */
|
|
58
58
|
userId?: string;
|
|
59
59
|
/** Stamped as gen_ai.conversation.id on every span and log record in scope. */
|
|
60
60
|
sessionId?: string;
|
|
61
61
|
/** Stamped as td.metadata.<key> on every span and log record in scope. */
|
|
62
|
-
metadata?: Record<string,
|
|
62
|
+
metadata?: Record<string, MetadataValue>;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const RESERVED_METADATA_KEYS = new Set(["userId", "sessionId", "user_id", "session_id"]);
|
package/src/debug.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { LogLevel, SdkLogLevel } from "./config.ts";
|
|
2
2
|
|
|
3
|
-
const ORDER
|
|
3
|
+
const ORDER = { debug: 0, info: 1, warn: 2, error: 3, silent: 4 } satisfies Record<
|
|
4
|
+
SdkLogLevel,
|
|
5
|
+
number
|
|
6
|
+
>;
|
|
4
7
|
|
|
5
8
|
let currentLevel: SdkLogLevel = "warn";
|
|
6
9
|
|
|
@@ -22,11 +25,11 @@ export const diag = {
|
|
|
22
25
|
};
|
|
23
26
|
|
|
24
27
|
/** Fail-open guard: SDK internals report through onError + diagnostics, never into user code. */
|
|
25
|
-
export function reportError(onError: ((error:
|
|
28
|
+
export function reportError(onError: ((error: Error) => void) | undefined, cause: unknown): void {
|
|
26
29
|
try {
|
|
27
|
-
onError?.(
|
|
30
|
+
onError?.(cause instanceof Error ? cause : new Error(String(cause)));
|
|
28
31
|
} catch {
|
|
29
32
|
// onError itself must never propagate
|
|
30
33
|
}
|
|
31
|
-
diag.error(
|
|
34
|
+
diag.error(cause);
|
|
32
35
|
}
|
package/src/metrics.ts
CHANGED
|
@@ -31,8 +31,8 @@ export interface MetricsPipeline {
|
|
|
31
31
|
shutdown(): Promise<void>;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
function stringAttr(value:
|
|
35
|
-
return
|
|
34
|
+
function stringAttr(value: Attributes[string]): string | undefined {
|
|
35
|
+
return value?.constructor === String ? `${value}` : undefined;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export function createMetricsPipeline({
|
|
@@ -59,7 +59,7 @@ export function createMetricsPipeline({
|
|
|
59
59
|
|
|
60
60
|
const record = (span: ReadableSpan): void => {
|
|
61
61
|
const operation = span.attributes["gen_ai.operation.name"];
|
|
62
|
-
if (
|
|
62
|
+
if (operation?.constructor !== String || !DURATION_OPERATIONS.has(`${operation}`)) return;
|
|
63
63
|
const attrs: Attributes = omitUndefined({
|
|
64
64
|
"gen_ai.operation.name": operation,
|
|
65
65
|
"gen_ai.provider.name": stringAttr(span.attributes["gen_ai.provider.name"]),
|
|
@@ -74,11 +74,11 @@ export function createMetricsPipeline({
|
|
|
74
74
|
);
|
|
75
75
|
if (!TOKEN_OPERATIONS.has(operation)) return;
|
|
76
76
|
const inputTokens = span.attributes["gen_ai.usage.input_tokens"];
|
|
77
|
-
if (
|
|
77
|
+
if (inputTokens?.constructor === Number) {
|
|
78
78
|
tokenHistogram.record(inputTokens, { ...attrs, "gen_ai.token.type": "input" });
|
|
79
79
|
}
|
|
80
80
|
const outputTokens = span.attributes["gen_ai.usage.output_tokens"];
|
|
81
|
-
if (
|
|
81
|
+
if (outputTokens?.constructor === Number) {
|
|
82
82
|
tokenHistogram.record(outputTokens, { ...attrs, "gen_ai.token.type": "output" });
|
|
83
83
|
}
|
|
84
84
|
};
|
package/src/otel.ts
CHANGED
|
@@ -47,7 +47,7 @@ export interface TelemetrySpanProcessorOptions {
|
|
|
47
47
|
/** deployment.environment.name on the metrics resource. Falls back to `TELEMETRY_DEV_ENVIRONMENT`. */
|
|
48
48
|
environment?: string;
|
|
49
49
|
fetch?: typeof fetch;
|
|
50
|
-
onError?: (error:
|
|
50
|
+
onError?: (error: Error) => void;
|
|
51
51
|
/** Advanced/test seam: replaces the OTLP fetch exporter. */
|
|
52
52
|
spanExporter?: SpanExporter;
|
|
53
53
|
}
|
|
@@ -142,7 +142,7 @@ export function createTelemetrySpanExporter(
|
|
|
142
142
|
apiKey?: string;
|
|
143
143
|
baseUrl?: string;
|
|
144
144
|
fetch?: typeof fetch;
|
|
145
|
-
onError?: (error:
|
|
145
|
+
onError?: (error: Error) => void;
|
|
146
146
|
} = {},
|
|
147
147
|
): SpanExporter {
|
|
148
148
|
const env = resolveEnv();
|
package/src/processor.ts
CHANGED
|
@@ -18,7 +18,7 @@ export interface StampingProcessorOptions {
|
|
|
18
18
|
batch: Required<BatchOptions>;
|
|
19
19
|
spanFilter?: (span: ReadableSpan) => boolean;
|
|
20
20
|
recordMetrics?: (span: ReadableSpan) => void;
|
|
21
|
-
onError?: (error:
|
|
21
|
+
onError?: (error: Error) => void;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
package/src/transport.ts
CHANGED
|
@@ -16,7 +16,7 @@ import { reportError } from "./debug.ts";
|
|
|
16
16
|
|
|
17
17
|
export interface Transport {
|
|
18
18
|
fetchImpl: typeof fetch;
|
|
19
|
-
onError?: (error:
|
|
19
|
+
onError?: (error: Error) => void;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export interface OtlpTarget {
|
|
@@ -74,7 +74,7 @@ const GZIP_THRESHOLD_BYTES = 1024;
|
|
|
74
74
|
export async function maybeGzip(
|
|
75
75
|
body: Uint8Array,
|
|
76
76
|
): Promise<{ body: Uint8Array; contentEncoding?: "gzip" }> {
|
|
77
|
-
if (body.byteLength <= GZIP_THRESHOLD_BYTES ||
|
|
77
|
+
if (body.byteLength <= GZIP_THRESHOLD_BYTES || globalThis.CompressionStream === undefined) {
|
|
78
78
|
return { body };
|
|
79
79
|
}
|
|
80
80
|
try {
|
|
@@ -147,7 +147,7 @@ export function createTraceExporter(target: OtlpTarget, transport: Transport): S
|
|
|
147
147
|
export(spans, resultCallback) {
|
|
148
148
|
send(spans).then(
|
|
149
149
|
() => resultCallback({ code: ExportResultCode.SUCCESS }),
|
|
150
|
-
(error:
|
|
150
|
+
(error: Error) => {
|
|
151
151
|
reportError(transport.onError, error);
|
|
152
152
|
resultCallback({
|
|
153
153
|
code: ExportResultCode.FAILED,
|
|
@@ -172,7 +172,7 @@ export function createLogExporter(target: OtlpTarget, transport: Transport): Log
|
|
|
172
172
|
export(logs, resultCallback) {
|
|
173
173
|
send(logs).then(
|
|
174
174
|
() => resultCallback({ code: ExportResultCode.SUCCESS }),
|
|
175
|
-
(error:
|
|
175
|
+
(error: Error) => {
|
|
176
176
|
reportError(transport.onError, error);
|
|
177
177
|
resultCallback({
|
|
178
178
|
code: ExportResultCode.FAILED,
|
|
@@ -225,7 +225,7 @@ export function createMetricExporter(target: OtlpTarget, transport: Transport):
|
|
|
225
225
|
}
|
|
226
226
|
resultCallback({ code: 0 });
|
|
227
227
|
})
|
|
228
|
-
.catch((error:
|
|
228
|
+
.catch((error: Error) => {
|
|
229
229
|
reportError(onError, error);
|
|
230
230
|
resultCallback({ code: 1, error: error instanceof Error ? error : undefined });
|
|
231
231
|
});
|
|
@@ -236,9 +236,10 @@ export function createMetricExporter(target: OtlpTarget, transport: Transport):
|
|
|
236
236
|
};
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
export function otlpHeaders(apiKey: string
|
|
239
|
+
export function otlpHeaders(apiKey: string, sdkName = "@telemetry-dev/otel") {
|
|
240
240
|
return {
|
|
241
241
|
"content-type": "application/x-protobuf",
|
|
242
242
|
authorization: `Bearer ${apiKey}`,
|
|
243
|
+
"x-telemetry-dev-sdk": sdkName,
|
|
243
244
|
};
|
|
244
245
|
}
|