@geekmidas/telescope 1.1.1 → 10.0.0-alpha.0

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.
Files changed (167) hide show
  1. package/README.md +14 -4
  2. package/dist/{hono-Bz9PQQzj.mjs → hono-Bw-ey6CT.mjs} +2 -2
  3. package/dist/{hono-Bz9PQQzj.mjs.map → hono-Bw-ey6CT.mjs.map} +1 -1
  4. package/dist/{hono-Z_JIICmt.cjs → hono-CPHX7FAm.cjs} +2 -2
  5. package/dist/{hono-Z_JIICmt.cjs.map → hono-CPHX7FAm.cjs.map} +1 -1
  6. package/dist/{http-Crsriv32.mjs → http-BIvr0YdI.mjs} +1 -1
  7. package/dist/{http-Crsriv32.mjs.map → http-BIvr0YdI.mjs.map} +1 -1
  8. package/dist/{http-JycFRfSe.cjs → http-BsqmhurZ.cjs} +1 -1
  9. package/dist/{http-JycFRfSe.cjs.map → http-BsqmhurZ.cjs.map} +1 -1
  10. package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
  11. package/dist/{http-D5kn3_Mt.d.mts.map → http-DULM1u2L.d.cts.map} +1 -1
  12. package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
  13. package/dist/{http-Dvca6fC3.d.cts.map → http-GB-Nlvwc.d.mts.map} +1 -1
  14. package/dist/instrumentation/hono.cjs +2 -2
  15. package/dist/instrumentation/hono.mjs +2 -2
  16. package/dist/instrumentation/http.cjs +1 -1
  17. package/dist/instrumentation/http.d.cts +1 -1
  18. package/dist/instrumentation/http.d.mts +1 -1
  19. package/dist/instrumentation/http.mjs +1 -1
  20. package/dist/instrumentation/index.cjs +5 -5
  21. package/dist/instrumentation/index.d.cts +3 -3
  22. package/dist/instrumentation/index.d.mts +3 -3
  23. package/dist/instrumentation/index.mjs +5 -5
  24. package/dist/instrumentation/middleware.cjs +2 -2
  25. package/dist/instrumentation/middleware.d.cts +1 -1
  26. package/dist/instrumentation/middleware.d.mts +1 -1
  27. package/dist/instrumentation/middleware.mjs +2 -2
  28. package/dist/instrumentation/otel.cjs +2 -2
  29. package/dist/instrumentation/otel.d.cts +1 -1
  30. package/dist/instrumentation/otel.d.mts +1 -1
  31. package/dist/instrumentation/otel.mjs +2 -2
  32. package/dist/instrumentation/setup.cjs +1 -1
  33. package/dist/instrumentation/setup.mjs +1 -1
  34. package/dist/logger/console.d.cts.map +1 -1
  35. package/dist/{middleware-D3v5SnSs.cjs → middleware-Bcq6XXGG.cjs} +3 -3
  36. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  37. package/dist/{middleware-Dy1ctr2N.mjs → middleware-D1XEHvyy.mjs} +3 -3
  38. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  39. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  40. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  41. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  42. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  43. package/dist/{otel-DPKNyJ0t.mjs → otel-B9bNoeZ2.mjs} +4 -4
  44. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  45. package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
  46. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  47. package/dist/{otel-DuiBeBPU.cjs → otel-BzjOtVxZ.cjs} +4 -4
  48. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  49. package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
  50. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  51. package/dist/otlp/hono.cjs +3 -3
  52. package/dist/otlp/hono.mjs +3 -3
  53. package/dist/otlp/index.cjs +3 -3
  54. package/dist/otlp/index.mjs +3 -3
  55. package/dist/otlp/receiver.cjs +3 -3
  56. package/dist/otlp/receiver.mjs +3 -3
  57. package/dist/otlp/transformer.cjs +2 -2
  58. package/dist/otlp/transformer.mjs +2 -2
  59. package/dist/otlp/types.cjs +1 -1
  60. package/dist/otlp/types.mjs +1 -1
  61. package/dist/{receiver-q4f7eirs.mjs → receiver-D46dfkYI.mjs} +2 -2
  62. package/dist/{receiver-q4f7eirs.mjs.map → receiver-D46dfkYI.mjs.map} +1 -1
  63. package/dist/{receiver-BW_4go_X.cjs → receiver-slCoAFat.cjs} +2 -2
  64. package/dist/{receiver-BW_4go_X.cjs.map → receiver-slCoAFat.cjs.map} +1 -1
  65. package/dist/{setup-BhCp2LUp.mjs → setup-DC9JMEYZ.mjs} +1 -1
  66. package/dist/{setup-BhCp2LUp.mjs.map → setup-DC9JMEYZ.mjs.map} +1 -1
  67. package/dist/{setup-_uT4L_x5.cjs → setup-DufxQpi9.cjs} +1 -1
  68. package/dist/{setup-_uT4L_x5.cjs.map → setup-DufxQpi9.cjs.map} +1 -1
  69. package/dist/storage/kysely.cjs +48 -38
  70. package/dist/storage/kysely.cjs.map +1 -1
  71. package/dist/storage/kysely.d.cts +29 -9
  72. package/dist/storage/kysely.d.cts.map +1 -1
  73. package/dist/storage/kysely.d.mts +29 -9
  74. package/dist/storage/kysely.d.mts.map +1 -1
  75. package/dist/storage/kysely.mjs +48 -38
  76. package/dist/storage/kysely.mjs.map +1 -1
  77. package/dist/tracing-BX8uY2nR.d.cts.map +1 -1
  78. package/dist/tracing-PnECEbEu.d.mts.map +1 -1
  79. package/dist/{transformer-CFrJQkUg.mjs → transformer-CFQ4WFk6.mjs} +2 -2
  80. package/dist/{transformer-CFrJQkUg.mjs.map → transformer-CFQ4WFk6.mjs.map} +1 -1
  81. package/dist/{transformer-DvDYyFRQ.cjs → transformer-Csl6fbgv.cjs} +2 -2
  82. package/dist/{transformer-DvDYyFRQ.cjs.map → transformer-Csl6fbgv.cjs.map} +1 -1
  83. package/dist/types-B1EIa_cQ.d.mts.map +1 -1
  84. package/dist/{types-BBeTDpHr.cjs → types-BMiHgsi4.cjs} +1 -1
  85. package/dist/{types-BBeTDpHr.cjs.map → types-BMiHgsi4.cjs.map} +1 -1
  86. package/dist/{types-CXYLhG_G.mjs → types-Cj59nqy7.mjs} +1 -1
  87. package/dist/{types-CXYLhG_G.mjs.map → types-Cj59nqy7.mjs.map} +1 -1
  88. package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
  89. package/package.json +6 -3
  90. package/CHANGELOG.md +0 -51
  91. package/dist/middleware-D3v5SnSs.cjs.map +0 -1
  92. package/dist/middleware-Dy1ctr2N.mjs.map +0 -1
  93. package/dist/otel-DPKNyJ0t.mjs.map +0 -1
  94. package/dist/otel-DuiBeBPU.cjs.map +0 -1
  95. package/src/Telescope.ts +0 -561
  96. package/src/__tests__/Telescope.spec.ts +0 -438
  97. package/src/__tests__/pino-transport.spec.ts +0 -115
  98. package/src/__tests__/redact.spec.ts +0 -336
  99. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  100. package/src/adapters/__tests__/middy.spec.ts +0 -741
  101. package/src/adapters/index.ts +0 -22
  102. package/src/adapters/lambda.ts +0 -432
  103. package/src/adapters/middy.ts +0 -402
  104. package/src/adapters/types.ts +0 -181
  105. package/src/core.ts +0 -51
  106. package/src/index.ts +0 -34
  107. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  108. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  109. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  110. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  111. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  112. package/src/instrumentation/core.ts +0 -228
  113. package/src/instrumentation/hono.ts +0 -270
  114. package/src/instrumentation/http.ts +0 -306
  115. package/src/instrumentation/index.ts +0 -90
  116. package/src/instrumentation/middleware.ts +0 -297
  117. package/src/instrumentation/otel.ts +0 -271
  118. package/src/instrumentation/setup.ts +0 -246
  119. package/src/instrumentation/tracing.ts +0 -145
  120. package/src/logger/__tests__/console.spec.ts +0 -366
  121. package/src/logger/__tests__/pino.spec.ts +0 -217
  122. package/src/logger/console.ts +0 -230
  123. package/src/logger/pino.ts +0 -201
  124. package/src/metrics/MetricsAggregator.ts +0 -555
  125. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  126. package/src/metrics/index.ts +0 -2
  127. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  128. package/src/metrics/storage/MetricsStorage.ts +0 -74
  129. package/src/metrics/storage/index.ts +0 -3
  130. package/src/metrics/storage/types.ts +0 -243
  131. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  132. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  133. package/src/otlp/hono.ts +0 -120
  134. package/src/otlp/index.ts +0 -22
  135. package/src/otlp/receiver.ts +0 -162
  136. package/src/otlp/transformer.ts +0 -367
  137. package/src/otlp/types.ts +0 -364
  138. package/src/redact.ts +0 -116
  139. package/src/server/__tests__/hono.spec.ts +0 -814
  140. package/src/server/hono.ts +0 -442
  141. package/src/storage/__tests__/kysely.spec.ts +0 -715
  142. package/src/storage/__tests__/memory.spec.ts +0 -694
  143. package/src/storage/kysely.ts +0 -599
  144. package/src/storage/memory.ts +0 -204
  145. package/src/types.ts +0 -447
  146. package/src/ui-assets.ts +0 -40
  147. package/tsconfig.json +0 -9
  148. package/ui/CHANGELOG.md +0 -7
  149. package/ui/index.html +0 -12
  150. package/ui/node_modules/.bin/tsc +0 -21
  151. package/ui/node_modules/.bin/tsserver +0 -21
  152. package/ui/node_modules/.bin/vite +0 -21
  153. package/ui/package.json +0 -24
  154. package/ui/src/App.tsx +0 -595
  155. package/ui/src/api.ts +0 -88
  156. package/ui/src/components/ExceptionDetail.tsx +0 -100
  157. package/ui/src/components/FilterBar.tsx +0 -162
  158. package/ui/src/components/LogDetail.tsx +0 -91
  159. package/ui/src/components/RequestDetail.tsx +0 -143
  160. package/ui/src/main.tsx +0 -10
  161. package/ui/src/styles.css +0 -11
  162. package/ui/src/types.ts +0 -63
  163. package/ui/src/vite-env.d.ts +0 -1
  164. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  165. package/ui/tsconfig.json +0 -20
  166. package/ui/tsconfig.tsbuildinfo +0 -1
  167. package/ui/vite.config.ts +0 -13
@@ -1,162 +0,0 @@
1
- import type { Telescope } from '../Telescope';
2
- import {
3
- type MetricDataPoint,
4
- transformLogs,
5
- transformMetrics,
6
- transformTraces,
7
- } from './transformer';
8
- import type {
9
- ExportLogsServiceRequest,
10
- ExportLogsServiceResponse,
11
- ExportMetricsServiceRequest,
12
- ExportMetricsServiceResponse,
13
- ExportTraceServiceRequest,
14
- ExportTraceServiceResponse,
15
- } from './types';
16
-
17
- /**
18
- * Callback for handling OTLP metrics
19
- */
20
- export type MetricsHandler = (
21
- points: MetricDataPoint[],
22
- ) => void | Promise<void>;
23
-
24
- /**
25
- * Options for OTLPReceiver
26
- */
27
- export interface OTLPReceiverOptions {
28
- /**
29
- * The Telescope instance to record data to
30
- */
31
- telescope: Telescope;
32
-
33
- /**
34
- * Optional callback for handling OTLP metrics.
35
- * OTLP metrics are more granular than Telescope's request metrics,
36
- * so a custom handler allows integration with metrics systems like Prometheus.
37
- */
38
- onMetrics?: MetricsHandler;
39
-
40
- /**
41
- * Whether to also log OTLP metrics to Telescope as log entries.
42
- * Useful for debugging OTLP integration. Default: false
43
- */
44
- logMetrics?: boolean;
45
- }
46
-
47
- /**
48
- * OTLP Receiver for ingesting OpenTelemetry data into Telescope.
49
- *
50
- * Supports the OTLP/JSON protocol for:
51
- * - Traces (POST /v1/traces) - HTTP server spans become RequestEntries
52
- * - Logs (POST /v1/logs) - Log records become LogEntries
53
- * - Metrics (POST /v1/metrics) - Metrics can be forwarded to custom handlers
54
- */
55
- export class OTLPReceiver {
56
- private telescope: Telescope;
57
- private onMetrics?: MetricsHandler;
58
- private logMetrics: boolean;
59
-
60
- constructor(options: OTLPReceiverOptions) {
61
- this.telescope = options.telescope;
62
- this.onMetrics = options.onMetrics;
63
- this.logMetrics = options.logMetrics ?? false;
64
- }
65
-
66
- /**
67
- * Handle incoming trace data
68
- * Transforms HTTP server spans to Telescope request entries
69
- */
70
- async receiveTraces(
71
- request: ExportTraceServiceRequest,
72
- ): Promise<ExportTraceServiceResponse> {
73
- const entries = transformTraces(request);
74
- let rejected = 0;
75
-
76
- for (const entry of entries) {
77
- try {
78
- await this.telescope.recordRequest(entry);
79
- } catch {
80
- rejected++;
81
- }
82
- }
83
-
84
- return rejected > 0
85
- ? { partialSuccess: { rejectedSpans: String(rejected) } }
86
- : {};
87
- }
88
-
89
- /**
90
- * Handle incoming log data
91
- * Transforms OTLP log records to Telescope log entries
92
- */
93
- async receiveLogs(
94
- request: ExportLogsServiceRequest,
95
- ): Promise<ExportLogsServiceResponse> {
96
- const entries = transformLogs(request);
97
- let rejected = 0;
98
-
99
- // Batch log entries for efficiency
100
- const batchEntries = entries.map((entry) => ({
101
- level: entry.level,
102
- message: entry.message,
103
- context: entry.context,
104
- requestId: entry.requestId,
105
- }));
106
-
107
- try {
108
- await this.telescope.log(batchEntries);
109
- } catch {
110
- rejected = entries.length;
111
- }
112
-
113
- return rejected > 0
114
- ? { partialSuccess: { rejectedLogRecords: String(rejected) } }
115
- : {};
116
- }
117
-
118
- /**
119
- * Handle incoming metrics data
120
- * Forwards to custom handler and optionally logs to Telescope
121
- */
122
- async receiveMetrics(
123
- request: ExportMetricsServiceRequest,
124
- ): Promise<ExportMetricsServiceResponse> {
125
- const points = transformMetrics(request);
126
- let rejected = 0;
127
-
128
- // Forward to custom metrics handler
129
- if (this.onMetrics) {
130
- try {
131
- await this.onMetrics(points);
132
- } catch {
133
- rejected = points.length;
134
- }
135
- }
136
-
137
- // Optionally log metrics to Telescope for debugging
138
- if (this.logMetrics && points.length > 0) {
139
- const logEntries = points.map((point) => ({
140
- level: 'debug' as const,
141
- message: `OTLP Metric: ${point.name}`,
142
- context: {
143
- name: point.name,
144
- value: point.value,
145
- type: point.type,
146
- unit: point.unit,
147
- attributes: point.attributes,
148
- },
149
- }));
150
-
151
- try {
152
- await this.telescope.log(logEntries);
153
- } catch {
154
- // Ignore logging errors
155
- }
156
- }
157
-
158
- return rejected > 0
159
- ? { partialSuccess: { rejectedDataPoints: String(rejected) } }
160
- : {};
161
- }
162
- }
@@ -1,367 +0,0 @@
1
- import type { LogEntry, RequestEntry } from '../types';
2
- import {
3
- type AnyValue,
4
- type ExportLogsServiceRequest,
5
- type ExportMetricsServiceRequest,
6
- type ExportTraceServiceRequest,
7
- type KeyValue,
8
- type LogRecord,
9
- SeverityNumber,
10
- type Span,
11
- SpanKind,
12
- SpanStatusCode,
13
- } from './types';
14
-
15
- /**
16
- * Extract a primitive value from an AnyValue
17
- */
18
- function extractValue(value?: AnyValue): unknown {
19
- if (!value) return undefined;
20
- if (value.stringValue !== undefined) return value.stringValue;
21
- if (value.boolValue !== undefined) return value.boolValue;
22
- if (value.intValue !== undefined) return parseInt(value.intValue, 10);
23
- if (value.doubleValue !== undefined) return value.doubleValue;
24
- if (value.bytesValue !== undefined) return value.bytesValue;
25
- if (value.arrayValue) return value.arrayValue.values.map(extractValue);
26
- if (value.kvlistValue) return attributesToObject(value.kvlistValue.values);
27
- return undefined;
28
- }
29
-
30
- /**
31
- * Convert KeyValue array to a plain object
32
- */
33
- function attributesToObject(attrs?: KeyValue[]): Record<string, unknown> {
34
- if (!attrs) return {};
35
- const result: Record<string, unknown> = {};
36
- for (const attr of attrs) {
37
- result[attr.key] = extractValue(attr.value);
38
- }
39
- return result;
40
- }
41
-
42
- /**
43
- * Convert nanoseconds string to Date
44
- */
45
- function nanoToDate(nanoStr: string): Date {
46
- const nano = BigInt(nanoStr);
47
- const ms = Number(nano / BigInt(1_000_000));
48
- return new Date(ms);
49
- }
50
-
51
- /**
52
- * Convert nanoseconds string to milliseconds number
53
- */
54
- function nanoToMs(nanoStr: string): number {
55
- const nano = BigInt(nanoStr);
56
- return Number(nano / BigInt(1_000_000));
57
- }
58
-
59
- /**
60
- * Map OTLP severity number to Telescope log level
61
- */
62
- function mapSeverity(
63
- severity?: SeverityNumber,
64
- ): 'debug' | 'info' | 'warn' | 'error' {
65
- if (severity === undefined) return 'info';
66
- if (severity <= SeverityNumber.SEVERITY_NUMBER_DEBUG4) return 'debug';
67
- if (severity <= SeverityNumber.SEVERITY_NUMBER_INFO4) return 'info';
68
- if (severity <= SeverityNumber.SEVERITY_NUMBER_WARN4) return 'warn';
69
- return 'error';
70
- }
71
-
72
- /**
73
- * Determine HTTP status from span attributes and status
74
- */
75
- function getHttpStatus(span: Span): number {
76
- const attrs = attributesToObject(span.attributes);
77
-
78
- // Look for HTTP status code in various attribute names
79
- const statusCode =
80
- attrs['http.status_code'] ??
81
- attrs['http.response.status_code'] ??
82
- attrs['http.response_status_code'];
83
-
84
- if (typeof statusCode === 'number') return statusCode;
85
- if (typeof statusCode === 'string') return parseInt(statusCode, 10) || 200;
86
-
87
- // Fall back to span status
88
- if (span.status?.code === SpanStatusCode.STATUS_CODE_ERROR) return 500;
89
- if (span.status?.code === SpanStatusCode.STATUS_CODE_OK) return 200;
90
-
91
- return 200;
92
- }
93
-
94
- /**
95
- * Check if a span represents an HTTP server request
96
- */
97
- function isHttpServerSpan(span: Span): boolean {
98
- if (span.kind !== SpanKind.SPAN_KIND_SERVER) return false;
99
-
100
- const attrs = attributesToObject(span.attributes);
101
- return !!(
102
- attrs['http.method'] ||
103
- attrs['http.request.method'] ||
104
- attrs['http.url'] ||
105
- attrs['http.target'] ||
106
- attrs['url.path']
107
- );
108
- }
109
-
110
- /**
111
- * Transform HTTP-related span attributes to RequestEntry format
112
- */
113
- function transformHttpSpan(
114
- span: Span,
115
- resourceAttrs: Record<string, unknown>,
116
- ): Omit<RequestEntry, 'id' | 'timestamp'> {
117
- const attrs = attributesToObject(span.attributes);
118
-
119
- // Extract HTTP method
120
- const method = String(
121
- attrs['http.method'] ?? attrs['http.request.method'] ?? 'GET',
122
- ).toUpperCase();
123
-
124
- // Extract path
125
- const path = String(
126
- attrs['http.target'] ?? attrs['url.path'] ?? attrs['http.route'] ?? '/',
127
- );
128
-
129
- // Extract full URL
130
- const url = String(
131
- attrs['http.url'] ?? attrs['url.full'] ?? `http://localhost${path}`,
132
- );
133
-
134
- // Extract headers (if available)
135
- const headers: Record<string, string> = {};
136
- const userAgent = attrs['http.user_agent'] ?? attrs['user_agent.original'];
137
- if (userAgent) headers['user-agent'] = String(userAgent);
138
-
139
- const contentType = attrs['http.request.header.content_type'];
140
- if (contentType) headers['content-type'] = String(contentType);
141
-
142
- // Calculate duration
143
- const startTime = nanoToMs(span.startTimeUnixNano);
144
- const endTime = nanoToMs(span.endTimeUnixNano);
145
- const duration = endTime - startTime;
146
-
147
- // Get status code
148
- const status = getHttpStatus(span);
149
-
150
- // Extract client IP
151
- const ip =
152
- attrs['net.peer.ip'] ?? attrs['client.address'] ?? attrs['http.client_ip'];
153
-
154
- return {
155
- method,
156
- path,
157
- url,
158
- headers,
159
- query: {},
160
- status,
161
- responseHeaders: {},
162
- duration,
163
- ip: ip ? String(ip) : undefined,
164
- tags: [
165
- `trace:${span.traceId}`,
166
- `span:${span.spanId}`,
167
- ...(resourceAttrs['service.name']
168
- ? [`service:${resourceAttrs['service.name']}`]
169
- : []),
170
- ],
171
- };
172
- }
173
-
174
- /**
175
- * Transform OTLP traces to Telescope RequestEntries
176
- * Only transforms HTTP server spans to request entries
177
- */
178
- export function transformTraces(
179
- request: ExportTraceServiceRequest,
180
- ): Array<Omit<RequestEntry, 'id' | 'timestamp'>> {
181
- const entries: Array<Omit<RequestEntry, 'id' | 'timestamp'>> = [];
182
-
183
- for (const resourceSpans of request.resourceSpans ?? []) {
184
- const resourceAttrs = attributesToObject(
185
- resourceSpans.resource?.attributes,
186
- );
187
-
188
- for (const scopeSpans of resourceSpans.scopeSpans ?? []) {
189
- for (const span of scopeSpans.spans ?? []) {
190
- // Only transform HTTP server spans
191
- if (isHttpServerSpan(span)) {
192
- entries.push(transformHttpSpan(span, resourceAttrs));
193
- }
194
- }
195
- }
196
- }
197
-
198
- return entries;
199
- }
200
-
201
- /**
202
- * Transform a single OTLP log record to Telescope LogEntry
203
- */
204
- function transformLogRecord(
205
- record: LogRecord,
206
- resourceAttrs: Record<string, unknown>,
207
- scopeName?: string,
208
- ): Omit<LogEntry, 'id' | 'timestamp'> {
209
- const attrs = attributesToObject(record.attributes);
210
-
211
- // Extract message from body
212
- let message = '';
213
- if (record.body) {
214
- const bodyValue = extractValue(record.body);
215
- message =
216
- typeof bodyValue === 'string' ? bodyValue : JSON.stringify(bodyValue);
217
- }
218
-
219
- // Build context from attributes
220
- const context: Record<string, unknown> = {
221
- ...attrs,
222
- ...resourceAttrs,
223
- };
224
-
225
- if (scopeName) {
226
- context['instrumentation.scope'] = scopeName;
227
- }
228
-
229
- // Add severity text if present
230
- if (record.severityText) {
231
- context['severity.text'] = record.severityText;
232
- }
233
-
234
- return {
235
- level: mapSeverity(record.severityNumber),
236
- message,
237
- context: Object.keys(context).length > 0 ? context : undefined,
238
- requestId: record.spanId ? `span:${record.spanId}` : undefined,
239
- };
240
- }
241
-
242
- /**
243
- * Transform OTLP logs to Telescope LogEntries
244
- */
245
- export function transformLogs(
246
- request: ExportLogsServiceRequest,
247
- ): Array<Omit<LogEntry, 'id' | 'timestamp'>> {
248
- const entries: Array<Omit<LogEntry, 'id' | 'timestamp'>> = [];
249
-
250
- for (const resourceLogs of request.resourceLogs ?? []) {
251
- const resourceAttrs = attributesToObject(resourceLogs.resource?.attributes);
252
-
253
- for (const scopeLogs of resourceLogs.scopeLogs ?? []) {
254
- const scopeName = scopeLogs.scope?.name;
255
-
256
- for (const record of scopeLogs.logRecords ?? []) {
257
- entries.push(transformLogRecord(record, resourceAttrs, scopeName));
258
- }
259
- }
260
- }
261
-
262
- return entries;
263
- }
264
-
265
- /**
266
- * Extracted metric data point for recording
267
- */
268
- export interface MetricDataPoint {
269
- name: string;
270
- description?: string;
271
- unit?: string;
272
- value: number;
273
- timestamp: Date;
274
- attributes: Record<string, unknown>;
275
- resourceAttributes: Record<string, unknown>;
276
- type: 'gauge' | 'sum' | 'histogram' | 'summary';
277
- }
278
-
279
- /**
280
- * Transform OTLP metrics to normalized data points
281
- * These can be used for custom metrics processing or forwarding
282
- */
283
- export function transformMetrics(
284
- request: ExportMetricsServiceRequest,
285
- ): MetricDataPoint[] {
286
- const points: MetricDataPoint[] = [];
287
-
288
- for (const resourceMetrics of request.resourceMetrics ?? []) {
289
- const resourceAttrs = attributesToObject(
290
- resourceMetrics.resource?.attributes,
291
- );
292
-
293
- for (const scopeMetrics of resourceMetrics.scopeMetrics ?? []) {
294
- for (const metric of scopeMetrics.metrics ?? []) {
295
- const baseMeta = {
296
- name: metric.name,
297
- description: metric.description,
298
- unit: metric.unit,
299
- resourceAttributes: resourceAttrs,
300
- };
301
-
302
- // Handle gauge
303
- if (metric.gauge) {
304
- for (const dp of metric.gauge.dataPoints) {
305
- points.push({
306
- ...baseMeta,
307
- value: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),
308
- timestamp: nanoToDate(dp.timeUnixNano),
309
- attributes: attributesToObject(dp.attributes),
310
- type: 'gauge',
311
- });
312
- }
313
- }
314
-
315
- // Handle sum (counter)
316
- if (metric.sum) {
317
- for (const dp of metric.sum.dataPoints) {
318
- points.push({
319
- ...baseMeta,
320
- value: dp.asDouble ?? (dp.asInt ? parseInt(dp.asInt, 10) : 0),
321
- timestamp: nanoToDate(dp.timeUnixNano),
322
- attributes: attributesToObject(dp.attributes),
323
- type: 'sum',
324
- });
325
- }
326
- }
327
-
328
- // Handle histogram (extract sum as the value)
329
- if (metric.histogram) {
330
- for (const dp of metric.histogram.dataPoints) {
331
- points.push({
332
- ...baseMeta,
333
- value: dp.sum ?? 0,
334
- timestamp: nanoToDate(dp.timeUnixNano),
335
- attributes: {
336
- ...attributesToObject(dp.attributes),
337
- count: parseInt(dp.count, 10),
338
- min: dp.min,
339
- max: dp.max,
340
- },
341
- type: 'histogram',
342
- });
343
- }
344
- }
345
-
346
- // Handle summary
347
- if (metric.summary) {
348
- for (const dp of metric.summary.dataPoints) {
349
- points.push({
350
- ...baseMeta,
351
- value: dp.sum ?? 0,
352
- timestamp: nanoToDate(dp.timeUnixNano),
353
- attributes: {
354
- ...attributesToObject(dp.attributes),
355
- count: parseInt(dp.count, 10),
356
- quantiles: dp.quantileValues,
357
- },
358
- type: 'summary',
359
- });
360
- }
361
- }
362
- }
363
- }
364
- }
365
-
366
- return points;
367
- }