@geekmidas/telescope 9.0.2 → 10.0.0-alpha.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.
Files changed (122) hide show
  1. package/README.md +14 -4
  2. package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
  3. package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
  4. package/dist/instrumentation/http.d.mts +1 -1
  5. package/dist/instrumentation/index.cjs +2 -2
  6. package/dist/instrumentation/index.d.cts +2 -2
  7. package/dist/instrumentation/index.d.mts +3 -3
  8. package/dist/instrumentation/index.mjs +2 -2
  9. package/dist/instrumentation/middleware.cjs +1 -1
  10. package/dist/instrumentation/middleware.d.cts +1 -1
  11. package/dist/instrumentation/middleware.d.mts +1 -1
  12. package/dist/instrumentation/middleware.mjs +1 -1
  13. package/dist/instrumentation/otel.cjs +1 -1
  14. package/dist/instrumentation/otel.d.cts +1 -1
  15. package/dist/instrumentation/otel.d.mts +1 -1
  16. package/dist/instrumentation/otel.mjs +1 -1
  17. package/dist/logger/console.d.cts.map +1 -1
  18. package/dist/logger/pino.d.mts +2 -2
  19. package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
  20. package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
  21. package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
  22. package/dist/middleware-D1XEHvyy.mjs.map +1 -0
  23. package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
  24. package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
  25. package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
  26. package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
  27. package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
  28. package/dist/otel-B9bNoeZ2.mjs.map +1 -0
  29. package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
  30. package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
  31. package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
  32. package/dist/otel-BzjOtVxZ.cjs.map +1 -0
  33. package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
  34. package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
  35. package/dist/storage/kysely.cjs +48 -38
  36. package/dist/storage/kysely.cjs.map +1 -1
  37. package/dist/storage/kysely.d.cts +29 -9
  38. package/dist/storage/kysely.d.cts.map +1 -1
  39. package/dist/storage/kysely.d.mts +29 -9
  40. package/dist/storage/kysely.d.mts.map +1 -1
  41. package/dist/storage/kysely.mjs +48 -38
  42. package/dist/storage/kysely.mjs.map +1 -1
  43. package/dist/tracing-PnECEbEu.d.mts.map +1 -1
  44. package/package.json +6 -3
  45. package/CHANGELOG.md +0 -72
  46. package/dist/middleware-4-GrQlOT.mjs.map +0 -1
  47. package/dist/middleware-DqPQpcup.cjs.map +0 -1
  48. package/dist/otel-40udNP5g.mjs.map +0 -1
  49. package/dist/otel-COrpz_GZ.cjs.map +0 -1
  50. package/src/Telescope.ts +0 -561
  51. package/src/__tests__/Telescope.spec.ts +0 -438
  52. package/src/__tests__/pino-transport.spec.ts +0 -115
  53. package/src/__tests__/redact.spec.ts +0 -336
  54. package/src/adapters/__tests__/lambda.spec.ts +0 -318
  55. package/src/adapters/__tests__/middy.spec.ts +0 -741
  56. package/src/adapters/index.ts +0 -22
  57. package/src/adapters/lambda.ts +0 -432
  58. package/src/adapters/middy.ts +0 -402
  59. package/src/adapters/types.ts +0 -181
  60. package/src/core.ts +0 -51
  61. package/src/index.ts +0 -34
  62. package/src/instrumentation/__tests__/core.spec.ts +0 -248
  63. package/src/instrumentation/__tests__/hono.spec.ts +0 -348
  64. package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
  65. package/src/instrumentation/__tests__/otel.spec.ts +0 -291
  66. package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
  67. package/src/instrumentation/core.ts +0 -228
  68. package/src/instrumentation/hono.ts +0 -270
  69. package/src/instrumentation/http.ts +0 -306
  70. package/src/instrumentation/index.ts +0 -90
  71. package/src/instrumentation/middleware.ts +0 -297
  72. package/src/instrumentation/otel.ts +0 -271
  73. package/src/instrumentation/setup.ts +0 -246
  74. package/src/instrumentation/tracing.ts +0 -145
  75. package/src/logger/__tests__/console.spec.ts +0 -366
  76. package/src/logger/__tests__/pino.spec.ts +0 -217
  77. package/src/logger/console.ts +0 -230
  78. package/src/logger/pino.ts +0 -201
  79. package/src/metrics/MetricsAggregator.ts +0 -555
  80. package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
  81. package/src/metrics/index.ts +0 -2
  82. package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
  83. package/src/metrics/storage/MetricsStorage.ts +0 -74
  84. package/src/metrics/storage/index.ts +0 -3
  85. package/src/metrics/storage/types.ts +0 -243
  86. package/src/otlp/__tests__/receiver.spec.ts +0 -367
  87. package/src/otlp/__tests__/transformer.spec.ts +0 -455
  88. package/src/otlp/hono.ts +0 -120
  89. package/src/otlp/index.ts +0 -22
  90. package/src/otlp/receiver.ts +0 -162
  91. package/src/otlp/transformer.ts +0 -367
  92. package/src/otlp/types.ts +0 -364
  93. package/src/redact.ts +0 -116
  94. package/src/server/__tests__/hono.spec.ts +0 -814
  95. package/src/server/hono.ts +0 -442
  96. package/src/storage/__tests__/kysely.spec.ts +0 -715
  97. package/src/storage/__tests__/memory.spec.ts +0 -694
  98. package/src/storage/kysely.ts +0 -599
  99. package/src/storage/memory.ts +0 -204
  100. package/src/types.ts +0 -447
  101. package/src/ui-assets.ts +0 -40
  102. package/tsconfig.json +0 -9
  103. package/ui/CHANGELOG.md +0 -7
  104. package/ui/index.html +0 -12
  105. package/ui/node_modules/.bin/tsc +0 -21
  106. package/ui/node_modules/.bin/tsserver +0 -21
  107. package/ui/node_modules/.bin/vite +0 -21
  108. package/ui/package.json +0 -24
  109. package/ui/src/App.tsx +0 -595
  110. package/ui/src/api.ts +0 -88
  111. package/ui/src/components/ExceptionDetail.tsx +0 -100
  112. package/ui/src/components/FilterBar.tsx +0 -162
  113. package/ui/src/components/LogDetail.tsx +0 -91
  114. package/ui/src/components/RequestDetail.tsx +0 -143
  115. package/ui/src/main.tsx +0 -10
  116. package/ui/src/styles.css +0 -11
  117. package/ui/src/types.ts +0 -63
  118. package/ui/src/vite-env.d.ts +0 -1
  119. package/ui/src/vite-plugin-gkm-config.ts +0 -54
  120. package/ui/tsconfig.json +0 -20
  121. package/ui/tsconfig.tsbuildinfo +0 -1
  122. 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
- }