@typokit/otel 0.1.4

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.
@@ -0,0 +1,7 @@
1
+ export { StructuredLogger } from "./logger.js";
2
+ export { redactFields } from "./redact.js";
3
+ export { OtelLogSink, createOtelLogSink } from "./log-bridge.js";
4
+ export { Tracer, Span, ConsoleSpanExporter, OtlpSpanExporter, NoopSpanExporter, createRequestTracer, resolveTracingConfig, createExporter, generateTraceId, generateSpanId, } from "./tracing.js";
5
+ export { MetricsCollector, ConsoleMetricExporter, OtlpMetricExporter, NoopMetricExporter, resolveMetricsConfig, createMetricExporter, createMetricsCollector, } from "./metrics.js";
6
+ export type { LogLevel, LogEntry, LoggingConfig, LogSink, LogMetadata, SpanData, SpanStatus, SpanExporter, TracingConfig, TelemetryConfig, MetricsConfig, MetricLabels, MetricData, MetricExporter, HistogramDataPoint, GaugeDataPoint, CounterDataPoint, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EACL,MAAM,EACN,IAAI,EACJ,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,OAAO,EACP,WAAW,EACX,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ // @typokit/otel — Structured Logger & Observability
2
+ export { StructuredLogger } from "./logger.js";
3
+ export { redactFields } from "./redact.js";
4
+ export { OtelLogSink, createOtelLogSink } from "./log-bridge.js";
5
+ export { Tracer, Span, ConsoleSpanExporter, OtlpSpanExporter, NoopSpanExporter, createRequestTracer, resolveTracingConfig, createExporter, generateTraceId, generateSpanId, } from "./tracing.js";
6
+ export { MetricsCollector, ConsoleMetricExporter, OtlpMetricExporter, NoopMetricExporter, resolveMetricsConfig, createMetricExporter, createMetricsCollector, } from "./metrics.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EACL,MAAM,EACN,IAAI,EACJ,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { LogEntry, LogSink, TelemetryConfig } from "./types.js";
2
+ /**
3
+ * OTel log sink that pushes structured log entries to an OTLP-compatible
4
+ * collector via HTTP POST. Includes trace context (traceId, spanId) for
5
+ * correlation with distributed traces.
6
+ */
7
+ export declare class OtelLogSink implements LogSink {
8
+ private readonly endpoint;
9
+ private readonly serviceName;
10
+ constructor(options?: {
11
+ endpoint?: string;
12
+ serviceName?: string;
13
+ });
14
+ write(entry: LogEntry): void;
15
+ private buildAttributes;
16
+ }
17
+ /**
18
+ * Creates an OtelLogSink if tracing is configured and enabled.
19
+ * Returns undefined if tracing is not configured (opt-in behavior).
20
+ */
21
+ export declare function createOtelLogSink(telemetry?: TelemetryConfig): OtelLogSink | undefined;
22
+ //# sourceMappingURL=log-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-bridge.d.ts","sourceRoot":"","sources":["../src/log-bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAsBrE;;;;GAIG;AACH,qBAAa,WAAY,YAAW,OAAO;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAKjE,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAuD5B,OAAO,CAAC,eAAe;CAoCxB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,eAAe,GAC1B,WAAW,GAAG,SAAS,CAczB"}
@@ -0,0 +1,128 @@
1
+ import { resolveTracingConfig } from "./tracing.js";
2
+ // OTel severity numbers per spec (https://opentelemetry.io/docs/specs/otel/logs/data-model/#severity-fields)
3
+ const SEVERITY_NUMBER = {
4
+ trace: 1,
5
+ debug: 5,
6
+ info: 9,
7
+ warn: 13,
8
+ error: 17,
9
+ fatal: 21,
10
+ };
11
+ const SEVERITY_TEXT = {
12
+ trace: "TRACE",
13
+ debug: "DEBUG",
14
+ info: "INFO",
15
+ warn: "WARN",
16
+ error: "ERROR",
17
+ fatal: "FATAL",
18
+ };
19
+ /**
20
+ * OTel log sink that pushes structured log entries to an OTLP-compatible
21
+ * collector via HTTP POST. Includes trace context (traceId, spanId) for
22
+ * correlation with distributed traces.
23
+ */
24
+ export class OtelLogSink {
25
+ endpoint;
26
+ serviceName;
27
+ constructor(options) {
28
+ this.endpoint = options?.endpoint ?? "http://localhost:4318/v1/logs";
29
+ this.serviceName = options?.serviceName ?? "typokit";
30
+ }
31
+ write(entry) {
32
+ const fetchFn = globalThis.fetch;
33
+ if (!fetchFn)
34
+ return;
35
+ const timeUnixNano = new Date(entry.timestamp).getTime() * 1_000_000;
36
+ const attributes = this.buildAttributes(entry);
37
+ const logRecord = {
38
+ timeUnixNano,
39
+ severityNumber: SEVERITY_NUMBER[entry.level] ?? 9,
40
+ severityText: SEVERITY_TEXT[entry.level] ?? "INFO",
41
+ body: { stringValue: entry.message },
42
+ attributes,
43
+ };
44
+ // Include trace context for correlation
45
+ if (entry.traceId) {
46
+ logRecord["traceId"] = entry.traceId;
47
+ }
48
+ if (entry.data?.["spanId"]) {
49
+ logRecord["spanId"] = String(entry.data["spanId"]);
50
+ }
51
+ const payload = {
52
+ resourceLogs: [
53
+ {
54
+ resource: {
55
+ attributes: [
56
+ { key: "service.name", value: { stringValue: this.serviceName } },
57
+ ],
58
+ },
59
+ scopeLogs: [
60
+ {
61
+ scope: { name: "@typokit/otel" },
62
+ logRecords: [logRecord],
63
+ },
64
+ ],
65
+ },
66
+ ],
67
+ };
68
+ // Fire-and-forget POST to OTLP endpoint
69
+ fetchFn(this.endpoint, {
70
+ method: "POST",
71
+ headers: { "Content-Type": "application/json" },
72
+ body: JSON.stringify(payload),
73
+ }).catch(() => {
74
+ // Silently ignore export failures
75
+ });
76
+ }
77
+ buildAttributes(entry) {
78
+ const attrs = [];
79
+ if (entry.route) {
80
+ attrs.push({ key: "route", value: { stringValue: entry.route } });
81
+ }
82
+ if (entry.phase) {
83
+ attrs.push({ key: "phase", value: { stringValue: entry.phase } });
84
+ }
85
+ if (entry.requestId) {
86
+ attrs.push({ key: "requestId", value: { stringValue: entry.requestId } });
87
+ }
88
+ if (entry.serverAdapter) {
89
+ attrs.push({
90
+ key: "serverAdapter",
91
+ value: { stringValue: entry.serverAdapter },
92
+ });
93
+ }
94
+ // Include any extra data fields as attributes
95
+ if (entry.data) {
96
+ for (const [key, val] of Object.entries(entry.data)) {
97
+ if (key === "spanId")
98
+ continue; // Already used as top-level field
99
+ if (val !== undefined && val !== null) {
100
+ attrs.push({
101
+ key: `data.${key}`,
102
+ value: { stringValue: String(val) },
103
+ });
104
+ }
105
+ }
106
+ }
107
+ return attrs;
108
+ }
109
+ }
110
+ /**
111
+ * Creates an OtelLogSink if tracing is configured and enabled.
112
+ * Returns undefined if tracing is not configured (opt-in behavior).
113
+ */
114
+ export function createOtelLogSink(telemetry) {
115
+ if (!telemetry)
116
+ return undefined;
117
+ const tracingConfig = resolveTracingConfig(telemetry);
118
+ if (!tracingConfig.enabled)
119
+ return undefined;
120
+ const endpoint = tracingConfig.endpoint
121
+ ? tracingConfig.endpoint.replace(/\/v1\/traces\/?$/, "/v1/logs")
122
+ : "http://localhost:4318/v1/logs";
123
+ return new OtelLogSink({
124
+ endpoint,
125
+ serviceName: tracingConfig.serviceName,
126
+ });
127
+ }
128
+ //# sourceMappingURL=log-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log-bridge.js","sourceRoot":"","sources":["../src/log-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Logger } from "@typokit/types";
2
+ import type { LogEntry, LoggingConfig, LogMetadata, LogSink } from "./types.js";
3
+ /** Default sink: writes structured JSON to stdout */
4
+ export declare class StdoutSink implements LogSink {
5
+ write(entry: LogEntry): void;
6
+ }
7
+ /**
8
+ * StructuredLogger implements the Logger interface from @typokit/types.
9
+ * Automatically enriches log entries with request metadata and supports
10
+ * field redaction and configurable log levels.
11
+ */
12
+ export declare class StructuredLogger implements Logger {
13
+ private readonly minLevel;
14
+ private readonly redactPatterns;
15
+ private readonly metadata;
16
+ private readonly sinks;
17
+ constructor(config?: LoggingConfig, metadata?: LogMetadata, sinks?: LogSink[]);
18
+ trace(message: string, data?: Record<string, unknown>): void;
19
+ debug(message: string, data?: Record<string, unknown>): void;
20
+ info(message: string, data?: Record<string, unknown>): void;
21
+ warn(message: string, data?: Record<string, unknown>): void;
22
+ error(message: string, data?: Record<string, unknown>): void;
23
+ fatal(message: string, data?: Record<string, unknown>): void;
24
+ /** Create a child logger with additional/overridden metadata */
25
+ child(metadata: Partial<LogMetadata>): StructuredLogger;
26
+ private log;
27
+ }
28
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAEV,QAAQ,EACR,aAAa,EACb,WAAW,EACX,OAAO,EACR,MAAM,YAAY,CAAC;AAIpB,qDAAqD;AACrD,qBAAa,UAAW,YAAW,OAAO;IACxC,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;CAY7B;AAoBD;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,MAAM;IAC7C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAW;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;gBAGhC,MAAM,CAAC,EAAE,aAAa,EACtB,QAAQ,CAAC,EAAE,WAAW,EACtB,KAAK,CAAC,EAAE,OAAO,EAAE;IASnB,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI3D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAI5D,gEAAgE;IAChE,KAAK,CAAC,QAAQ,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,gBAAgB;IAWvD,OAAO,CAAC,GAAG;CAsCZ"}
package/dist/logger.js ADDED
@@ -0,0 +1,100 @@
1
+ import { LOG_LEVELS } from "./types.js";
2
+ import { redactFields } from "./redact.js";
3
+ /** Default sink: writes structured JSON to stdout */
4
+ export class StdoutSink {
5
+ write(entry) {
6
+ const output = JSON.stringify(entry);
7
+ // Use globalThis to avoid @types/node dependency
8
+ const proc = globalThis.process;
9
+ if (proc?.stdout?.write) {
10
+ proc.stdout.write(output + "\n");
11
+ }
12
+ }
13
+ }
14
+ const LEVEL_PRIORITY = {
15
+ trace: 0,
16
+ debug: 1,
17
+ info: 2,
18
+ warn: 3,
19
+ error: 4,
20
+ fatal: 5,
21
+ };
22
+ function isProduction() {
23
+ const proc = globalThis.process;
24
+ return proc?.env?.["NODE_ENV"] === "production";
25
+ }
26
+ /**
27
+ * StructuredLogger implements the Logger interface from @typokit/types.
28
+ * Automatically enriches log entries with request metadata and supports
29
+ * field redaction and configurable log levels.
30
+ */
31
+ export class StructuredLogger {
32
+ minLevel;
33
+ redactPatterns;
34
+ metadata;
35
+ sinks;
36
+ constructor(config, metadata, sinks) {
37
+ const defaultLevel = isProduction() ? "info" : "debug";
38
+ this.minLevel = LEVEL_PRIORITY[config?.level ?? defaultLevel];
39
+ this.redactPatterns = config?.redact ?? [];
40
+ this.metadata = metadata ?? {};
41
+ this.sinks = sinks ?? [new StdoutSink()];
42
+ }
43
+ trace(message, data) {
44
+ this.log("trace", message, data);
45
+ }
46
+ debug(message, data) {
47
+ this.log("debug", message, data);
48
+ }
49
+ info(message, data) {
50
+ this.log("info", message, data);
51
+ }
52
+ warn(message, data) {
53
+ this.log("warn", message, data);
54
+ }
55
+ error(message, data) {
56
+ this.log("error", message, data);
57
+ }
58
+ fatal(message, data) {
59
+ this.log("fatal", message, data);
60
+ }
61
+ /** Create a child logger with additional/overridden metadata */
62
+ child(metadata) {
63
+ return new StructuredLogger({
64
+ level: LOG_LEVELS[this.minLevel],
65
+ redact: this.redactPatterns,
66
+ }, { ...this.metadata, ...metadata }, this.sinks);
67
+ }
68
+ log(level, message, data) {
69
+ if (LEVEL_PRIORITY[level] < this.minLevel)
70
+ return;
71
+ const redactedData = data && this.redactPatterns.length > 0
72
+ ? redactFields(data, this.redactPatterns)
73
+ : data;
74
+ const entry = {
75
+ level,
76
+ message,
77
+ timestamp: new Date().toISOString(),
78
+ ...(redactedData !== undefined ? { data: redactedData } : {}),
79
+ ...(this.metadata.traceId !== undefined
80
+ ? { traceId: this.metadata.traceId }
81
+ : {}),
82
+ ...(this.metadata.route !== undefined
83
+ ? { route: this.metadata.route }
84
+ : {}),
85
+ ...(this.metadata.phase !== undefined
86
+ ? { phase: this.metadata.phase }
87
+ : {}),
88
+ ...(this.metadata.requestId !== undefined
89
+ ? { requestId: this.metadata.requestId }
90
+ : {}),
91
+ ...(this.metadata.serverAdapter !== undefined
92
+ ? { serverAdapter: this.metadata.serverAdapter }
93
+ : {}),
94
+ };
95
+ for (const sink of this.sinks) {
96
+ sink.write(entry);
97
+ }
98
+ }
99
+ }
100
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ import type { MetricsConfig, MetricLabels, MetricData, MetricExporter, HistogramDataPoint, CounterDataPoint, TelemetryConfig } from "./types.js";
2
+ /** Exports metrics to stdout as structured JSON (dev mode) */
3
+ export declare class ConsoleMetricExporter implements MetricExporter {
4
+ export(metrics: MetricData[]): void;
5
+ }
6
+ /** No-op exporter that silently discards metrics */
7
+ export declare class NoopMetricExporter implements MetricExporter {
8
+ export(_metrics: MetricData[]): void;
9
+ }
10
+ /** Exports metrics to an OTLP-compatible HTTP endpoint */
11
+ export declare class OtlpMetricExporter implements MetricExporter {
12
+ private readonly endpoint;
13
+ constructor(endpoint?: string);
14
+ export(metrics: MetricData[]): void;
15
+ }
16
+ /**
17
+ * MetricsCollector records and stores request metrics.
18
+ * It manages three metric instruments:
19
+ * - http.server.request.duration (histogram) — request latency in ms
20
+ * - http.server.active_requests (gauge) — currently in-flight requests
21
+ * - http.server.error_count (counter) — error responses (status >= 400)
22
+ */
23
+ export declare class MetricsCollector {
24
+ private readonly enabled;
25
+ private readonly exporter;
26
+ private readonly serviceName;
27
+ private readonly durations;
28
+ private readonly errors;
29
+ private activeRequests;
30
+ private readonly activeGaugeSnapshots;
31
+ constructor(options?: {
32
+ enabled?: boolean;
33
+ exporter?: MetricExporter;
34
+ serviceName?: string;
35
+ });
36
+ /** Record the start of a request (increments active_requests gauge) */
37
+ requestStart(): void;
38
+ /** Record the end of a request with its duration and labels */
39
+ requestEnd(labels: MetricLabels, durationMs: number): void;
40
+ /** Get current active request count */
41
+ getActiveRequests(): number;
42
+ /** Get the service name */
43
+ getServiceName(): string;
44
+ /** Get all recorded duration data points */
45
+ getDurations(): HistogramDataPoint[];
46
+ /** Get all recorded error counter data points */
47
+ getErrors(): CounterDataPoint[];
48
+ /** Flush all collected metrics to the exporter */
49
+ flush(): void;
50
+ /** Reset all collected metrics */
51
+ reset(): void;
52
+ }
53
+ /** Resolves a TelemetryConfig into a normalized MetricsConfig */
54
+ export declare function resolveMetricsConfig(telemetry?: TelemetryConfig): MetricsConfig;
55
+ /** Creates the appropriate MetricExporter from config */
56
+ export declare function createMetricExporter(config: MetricsConfig): MetricExporter;
57
+ /**
58
+ * Creates a MetricsCollector configured from TelemetryConfig.
59
+ * This is the main entry point for request-level metrics.
60
+ */
61
+ export declare function createMetricsCollector(telemetry?: TelemetryConfig, exporterOverride?: MetricExporter): MetricsCollector;
62
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,UAAU,EACV,cAAc,EACd,kBAAkB,EAElB,gBAAgB,EAChB,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,8DAA8D;AAC9D,qBAAa,qBAAsB,YAAW,cAAc;IAC1D,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI;CAapC;AAED,oDAAoD;AACpD,qBAAa,kBAAmB,YAAW,cAAc;IACvD,MAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;CAGrC;AAED,0DAA0D;AAC1D,qBAAa,kBAAmB,YAAW,cAAc;IACvD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,CAAC,EAAE,MAAM;IAI7B,MAAM,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI;CA4EpC;AAuBD;;;;;;GAMG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA4B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAwB;gBAEjD,OAAO,CAAC,EAAE;QACpB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,cAAc,CAAC;QAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB;IAMD,uEAAuE;IACvE,YAAY,IAAI,IAAI;IAKpB,+DAA+D;IAC/D,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA+B1D,uCAAuC;IACvC,iBAAiB,IAAI,MAAM;IAI3B,2BAA2B;IAC3B,cAAc,IAAI,MAAM;IAIxB,4CAA4C;IAC5C,YAAY,IAAI,kBAAkB,EAAE;IAIpC,iDAAiD;IACjD,SAAS,IAAI,gBAAgB,EAAE;IAI/B,kDAAkD;IAClD,KAAK,IAAI,IAAI;IAkCb,kCAAkC;IAClC,KAAK,IAAI,IAAI;CAMd;AAID,iEAAiE;AACjE,wBAAgB,oBAAoB,CAClC,SAAS,CAAC,EAAE,eAAe,GAC1B,aAAa,CA6Bf;AAED,yDAAyD;AACzD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAQ1E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,CAAC,EAAE,eAAe,EAC3B,gBAAgB,CAAC,EAAE,cAAc,GAChC,gBAAgB,CASlB"}
@@ -0,0 +1,260 @@
1
+ // ─── Metric Exporters ────────────────────────────────────────
2
+ /** Exports metrics to stdout as structured JSON (dev mode) */
3
+ export class ConsoleMetricExporter {
4
+ export(metrics) {
5
+ const proc = globalThis.process;
6
+ for (const metric of metrics) {
7
+ const output = JSON.stringify({ ...metric, exportKind: "metric" });
8
+ if (proc?.stdout?.write) {
9
+ proc.stdout.write(output + "\n");
10
+ }
11
+ }
12
+ }
13
+ }
14
+ /** No-op exporter that silently discards metrics */
15
+ export class NoopMetricExporter {
16
+ export(_metrics) {
17
+ // intentionally empty
18
+ }
19
+ }
20
+ /** Exports metrics to an OTLP-compatible HTTP endpoint */
21
+ export class OtlpMetricExporter {
22
+ endpoint;
23
+ constructor(endpoint) {
24
+ this.endpoint = endpoint ?? "http://localhost:4318/v1/metrics";
25
+ }
26
+ export(metrics) {
27
+ const fetchFn = globalThis.fetch;
28
+ if (fetchFn) {
29
+ const payload = {
30
+ resourceMetrics: [
31
+ {
32
+ resource: { attributes: [] },
33
+ scopeMetrics: [
34
+ {
35
+ scope: { name: "@typokit/otel" },
36
+ metrics: metrics.map((m) => ({
37
+ name: m.name,
38
+ ...(m.type === "histogram"
39
+ ? {
40
+ histogram: {
41
+ dataPoints: m.dataPoints.map((dp) => ({
42
+ attributes: labelsToAttributes(dp.labels),
43
+ startTimeUnixNano: new Date(dp.timestamp).getTime() * 1_000_000,
44
+ timeUnixNano: new Date(dp.timestamp).getTime() * 1_000_000,
45
+ sum: dp.value,
46
+ count: 1,
47
+ })),
48
+ },
49
+ }
50
+ : m.type === "gauge"
51
+ ? {
52
+ gauge: {
53
+ dataPoints: m.dataPoints.map((dp) => ({
54
+ attributes: labelsToAttributes(dp.labels),
55
+ timeUnixNano: new Date(dp.timestamp).getTime() * 1_000_000,
56
+ asInt: dp.value,
57
+ })),
58
+ },
59
+ }
60
+ : {
61
+ sum: {
62
+ dataPoints: m.dataPoints.map((dp) => ({
63
+ attributes: labelsToAttributes(dp.labels),
64
+ startTimeUnixNano: new Date(dp.timestamp).getTime() * 1_000_000,
65
+ timeUnixNano: new Date(dp.timestamp).getTime() * 1_000_000,
66
+ asInt: dp.value,
67
+ })),
68
+ isMonotonic: true,
69
+ },
70
+ }),
71
+ })),
72
+ },
73
+ ],
74
+ },
75
+ ],
76
+ };
77
+ fetchFn(this.endpoint, {
78
+ method: "POST",
79
+ headers: { "Content-Type": "application/json" },
80
+ body: JSON.stringify(payload),
81
+ }).catch(() => {
82
+ // Silently ignore export failures
83
+ });
84
+ }
85
+ }
86
+ }
87
+ function labelsToAttributes(labels) {
88
+ const attrs = [];
89
+ if (labels.route !== undefined) {
90
+ attrs.push({ key: "http.route", value: { stringValue: labels.route } });
91
+ }
92
+ if (labels.method !== undefined) {
93
+ attrs.push({ key: "http.method", value: { stringValue: labels.method } });
94
+ }
95
+ if (labels.status !== undefined) {
96
+ attrs.push({ key: "http.status_code", value: { intValue: labels.status } });
97
+ }
98
+ return attrs;
99
+ }
100
+ // ─── Metrics Collector ───────────────────────────────────────
101
+ /**
102
+ * MetricsCollector records and stores request metrics.
103
+ * It manages three metric instruments:
104
+ * - http.server.request.duration (histogram) — request latency in ms
105
+ * - http.server.active_requests (gauge) — currently in-flight requests
106
+ * - http.server.error_count (counter) — error responses (status >= 400)
107
+ */
108
+ export class MetricsCollector {
109
+ enabled;
110
+ exporter;
111
+ serviceName;
112
+ durations = [];
113
+ errors = [];
114
+ activeRequests = 0;
115
+ activeGaugeSnapshots = [];
116
+ constructor(options) {
117
+ this.enabled = options?.enabled ?? true;
118
+ this.exporter = options?.exporter ?? new NoopMetricExporter();
119
+ this.serviceName = options?.serviceName ?? "typokit";
120
+ }
121
+ /** Record the start of a request (increments active_requests gauge) */
122
+ requestStart() {
123
+ if (!this.enabled)
124
+ return;
125
+ this.activeRequests++;
126
+ }
127
+ /** Record the end of a request with its duration and labels */
128
+ requestEnd(labels, durationMs) {
129
+ if (!this.enabled)
130
+ return;
131
+ this.activeRequests = Math.max(0, this.activeRequests - 1);
132
+ const timestamp = new Date().toISOString();
133
+ // Record duration histogram data point
134
+ this.durations.push({
135
+ labels,
136
+ value: durationMs,
137
+ timestamp,
138
+ });
139
+ // Record active requests gauge snapshot
140
+ this.activeGaugeSnapshots.push({
141
+ labels: {},
142
+ value: this.activeRequests,
143
+ timestamp,
144
+ });
145
+ // Record error counter if status >= 400
146
+ if (labels.status >= 400) {
147
+ this.errors.push({
148
+ labels,
149
+ value: 1,
150
+ timestamp,
151
+ });
152
+ }
153
+ }
154
+ /** Get current active request count */
155
+ getActiveRequests() {
156
+ return this.activeRequests;
157
+ }
158
+ /** Get the service name */
159
+ getServiceName() {
160
+ return this.serviceName;
161
+ }
162
+ /** Get all recorded duration data points */
163
+ getDurations() {
164
+ return [...this.durations];
165
+ }
166
+ /** Get all recorded error counter data points */
167
+ getErrors() {
168
+ return [...this.errors];
169
+ }
170
+ /** Flush all collected metrics to the exporter */
171
+ flush() {
172
+ if (!this.enabled)
173
+ return;
174
+ const metrics = [];
175
+ if (this.durations.length > 0) {
176
+ metrics.push({
177
+ name: "http.server.request.duration",
178
+ type: "histogram",
179
+ dataPoints: [...this.durations],
180
+ });
181
+ }
182
+ if (this.activeGaugeSnapshots.length > 0) {
183
+ metrics.push({
184
+ name: "http.server.active_requests",
185
+ type: "gauge",
186
+ dataPoints: [...this.activeGaugeSnapshots],
187
+ });
188
+ }
189
+ if (this.errors.length > 0) {
190
+ metrics.push({
191
+ name: "http.server.error_count",
192
+ type: "counter",
193
+ dataPoints: [...this.errors],
194
+ });
195
+ }
196
+ if (metrics.length > 0) {
197
+ this.exporter.export(metrics);
198
+ }
199
+ }
200
+ /** Reset all collected metrics */
201
+ reset() {
202
+ this.durations.length = 0;
203
+ this.errors.length = 0;
204
+ this.activeGaugeSnapshots.length = 0;
205
+ this.activeRequests = 0;
206
+ }
207
+ }
208
+ // ─── Config Resolution ───────────────────────────────────────
209
+ /** Resolves a TelemetryConfig into a normalized MetricsConfig */
210
+ export function resolveMetricsConfig(telemetry) {
211
+ if (!telemetry) {
212
+ return { enabled: true, exporter: "console" };
213
+ }
214
+ if (typeof telemetry.metrics === "boolean") {
215
+ return {
216
+ enabled: telemetry.metrics,
217
+ exporter: telemetry.exporter ?? "console",
218
+ endpoint: telemetry.endpoint,
219
+ serviceName: telemetry.serviceName,
220
+ };
221
+ }
222
+ if (typeof telemetry.metrics === "object") {
223
+ return {
224
+ enabled: telemetry.metrics.enabled ?? true,
225
+ exporter: telemetry.metrics.exporter ?? telemetry.exporter ?? "console",
226
+ endpoint: telemetry.metrics.endpoint ?? telemetry.endpoint,
227
+ serviceName: telemetry.metrics.serviceName ?? telemetry.serviceName,
228
+ };
229
+ }
230
+ return {
231
+ enabled: true,
232
+ exporter: telemetry.exporter ?? "console",
233
+ endpoint: telemetry.endpoint,
234
+ serviceName: telemetry.serviceName,
235
+ };
236
+ }
237
+ /** Creates the appropriate MetricExporter from config */
238
+ export function createMetricExporter(config) {
239
+ if (!config.enabled) {
240
+ return new NoopMetricExporter();
241
+ }
242
+ if (config.exporter === "otlp") {
243
+ return new OtlpMetricExporter(config.endpoint);
244
+ }
245
+ return new ConsoleMetricExporter();
246
+ }
247
+ /**
248
+ * Creates a MetricsCollector configured from TelemetryConfig.
249
+ * This is the main entry point for request-level metrics.
250
+ */
251
+ export function createMetricsCollector(telemetry, exporterOverride) {
252
+ const config = resolveMetricsConfig(telemetry);
253
+ const exporter = exporterOverride ?? createMetricExporter(config);
254
+ return new MetricsCollector({
255
+ exporter,
256
+ serviceName: config.serviceName,
257
+ enabled: config.enabled,
258
+ });
259
+ }
260
+ //# sourceMappingURL=metrics.js.map