@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.
- package/README.md +14 -4
- package/dist/{http-D5kn3_Mt.d.mts → http-BiNtg85L.d.mts} +3 -3
- package/dist/{http-D5kn3_Mt.d.mts.map → http-BiNtg85L.d.mts.map} +1 -1
- package/dist/instrumentation/http.d.mts +1 -1
- package/dist/instrumentation/index.cjs +2 -2
- package/dist/instrumentation/index.d.cts +2 -2
- package/dist/instrumentation/index.d.mts +3 -3
- package/dist/instrumentation/index.mjs +2 -2
- package/dist/instrumentation/middleware.cjs +1 -1
- package/dist/instrumentation/middleware.d.cts +1 -1
- package/dist/instrumentation/middleware.d.mts +1 -1
- package/dist/instrumentation/middleware.mjs +1 -1
- package/dist/instrumentation/otel.cjs +1 -1
- package/dist/instrumentation/otel.d.cts +1 -1
- package/dist/instrumentation/otel.d.mts +1 -1
- package/dist/instrumentation/otel.mjs +1 -1
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/logger/pino.d.mts +2 -2
- package/dist/{middleware-DqPQpcup.cjs → middleware-Bcq6XXGG.cjs} +2 -2
- package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
- package/dist/{middleware-4-GrQlOT.mjs → middleware-D1XEHvyy.mjs} +2 -2
- package/dist/middleware-D1XEHvyy.mjs.map +1 -0
- package/dist/{middleware-CA84nsNN.d.cts → middleware-PeyS-9Ny.d.cts} +2 -2
- package/dist/{middleware-CA84nsNN.d.cts.map → middleware-PeyS-9Ny.d.cts.map} +1 -1
- package/dist/{middleware-DAceVpfw.d.mts → middleware-oHvo_ZgU.d.mts} +2 -2
- package/dist/{middleware-DAceVpfw.d.mts.map → middleware-oHvo_ZgU.d.mts.map} +1 -1
- package/dist/{otel-40udNP5g.mjs → otel-B9bNoeZ2.mjs} +3 -3
- package/dist/otel-B9bNoeZ2.mjs.map +1 -0
- package/dist/{otel-SBVoVEHr.d.cts → otel-Bk89b1lX.d.cts} +3 -3
- package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
- package/dist/{otel-COrpz_GZ.cjs → otel-BzjOtVxZ.cjs} +3 -3
- package/dist/otel-BzjOtVxZ.cjs.map +1 -0
- package/dist/{otel-1bJPb2Z7.d.mts → otel-lPMsM26e.d.mts} +3 -3
- package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
- package/dist/storage/kysely.cjs +48 -38
- package/dist/storage/kysely.cjs.map +1 -1
- package/dist/storage/kysely.d.cts +29 -9
- package/dist/storage/kysely.d.cts.map +1 -1
- package/dist/storage/kysely.d.mts +29 -9
- package/dist/storage/kysely.d.mts.map +1 -1
- package/dist/storage/kysely.mjs +48 -38
- package/dist/storage/kysely.mjs.map +1 -1
- package/dist/tracing-PnECEbEu.d.mts.map +1 -1
- package/package.json +6 -3
- package/CHANGELOG.md +0 -72
- package/dist/middleware-4-GrQlOT.mjs.map +0 -1
- package/dist/middleware-DqPQpcup.cjs.map +0 -1
- package/dist/otel-40udNP5g.mjs.map +0 -1
- package/dist/otel-COrpz_GZ.cjs.map +0 -1
- package/src/Telescope.ts +0 -561
- package/src/__tests__/Telescope.spec.ts +0 -438
- package/src/__tests__/pino-transport.spec.ts +0 -115
- package/src/__tests__/redact.spec.ts +0 -336
- package/src/adapters/__tests__/lambda.spec.ts +0 -318
- package/src/adapters/__tests__/middy.spec.ts +0 -741
- package/src/adapters/index.ts +0 -22
- package/src/adapters/lambda.ts +0 -432
- package/src/adapters/middy.ts +0 -402
- package/src/adapters/types.ts +0 -181
- package/src/core.ts +0 -51
- package/src/index.ts +0 -34
- package/src/instrumentation/__tests__/core.spec.ts +0 -248
- package/src/instrumentation/__tests__/hono.spec.ts +0 -348
- package/src/instrumentation/__tests__/middleware.spec.ts +0 -528
- package/src/instrumentation/__tests__/otel.spec.ts +0 -291
- package/src/instrumentation/__tests__/tracing.spec.ts +0 -208
- package/src/instrumentation/core.ts +0 -228
- package/src/instrumentation/hono.ts +0 -270
- package/src/instrumentation/http.ts +0 -306
- package/src/instrumentation/index.ts +0 -90
- package/src/instrumentation/middleware.ts +0 -297
- package/src/instrumentation/otel.ts +0 -271
- package/src/instrumentation/setup.ts +0 -246
- package/src/instrumentation/tracing.ts +0 -145
- package/src/logger/__tests__/console.spec.ts +0 -366
- package/src/logger/__tests__/pino.spec.ts +0 -217
- package/src/logger/console.ts +0 -230
- package/src/logger/pino.ts +0 -201
- package/src/metrics/MetricsAggregator.ts +0 -555
- package/src/metrics/__tests__/MetricsAggregator.spec.ts +0 -298
- package/src/metrics/index.ts +0 -2
- package/src/metrics/storage/InMemoryMetricsStorage.ts +0 -380
- package/src/metrics/storage/MetricsStorage.ts +0 -74
- package/src/metrics/storage/index.ts +0 -3
- package/src/metrics/storage/types.ts +0 -243
- package/src/otlp/__tests__/receiver.spec.ts +0 -367
- package/src/otlp/__tests__/transformer.spec.ts +0 -455
- package/src/otlp/hono.ts +0 -120
- package/src/otlp/index.ts +0 -22
- package/src/otlp/receiver.ts +0 -162
- package/src/otlp/transformer.ts +0 -367
- package/src/otlp/types.ts +0 -364
- package/src/redact.ts +0 -116
- package/src/server/__tests__/hono.spec.ts +0 -814
- package/src/server/hono.ts +0 -442
- package/src/storage/__tests__/kysely.spec.ts +0 -715
- package/src/storage/__tests__/memory.spec.ts +0 -694
- package/src/storage/kysely.ts +0 -599
- package/src/storage/memory.ts +0 -204
- package/src/types.ts +0 -447
- package/src/ui-assets.ts +0 -40
- package/tsconfig.json +0 -9
- package/ui/CHANGELOG.md +0 -7
- package/ui/index.html +0 -12
- package/ui/node_modules/.bin/tsc +0 -21
- package/ui/node_modules/.bin/tsserver +0 -21
- package/ui/node_modules/.bin/vite +0 -21
- package/ui/package.json +0 -24
- package/ui/src/App.tsx +0 -595
- package/ui/src/api.ts +0 -88
- package/ui/src/components/ExceptionDetail.tsx +0 -100
- package/ui/src/components/FilterBar.tsx +0 -162
- package/ui/src/components/LogDetail.tsx +0 -91
- package/ui/src/components/RequestDetail.tsx +0 -143
- package/ui/src/main.tsx +0 -10
- package/ui/src/styles.css +0 -11
- package/ui/src/types.ts +0 -63
- package/ui/src/vite-env.d.ts +0 -1
- package/ui/src/vite-plugin-gkm-config.ts +0 -54
- package/ui/tsconfig.json +0 -20
- package/ui/tsconfig.tsbuildinfo +0 -1
- package/ui/vite.config.ts +0 -13
package/src/otlp/receiver.ts
DELETED
|
@@ -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
|
-
}
|
package/src/otlp/transformer.ts
DELETED
|
@@ -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
|
-
}
|