@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.
- package/README.md +14 -4
- package/dist/{hono-Bz9PQQzj.mjs → hono-Bw-ey6CT.mjs} +2 -2
- package/dist/{hono-Bz9PQQzj.mjs.map → hono-Bw-ey6CT.mjs.map} +1 -1
- package/dist/{hono-Z_JIICmt.cjs → hono-CPHX7FAm.cjs} +2 -2
- package/dist/{hono-Z_JIICmt.cjs.map → hono-CPHX7FAm.cjs.map} +1 -1
- package/dist/{http-Crsriv32.mjs → http-BIvr0YdI.mjs} +1 -1
- package/dist/{http-Crsriv32.mjs.map → http-BIvr0YdI.mjs.map} +1 -1
- package/dist/{http-JycFRfSe.cjs → http-BsqmhurZ.cjs} +1 -1
- package/dist/{http-JycFRfSe.cjs.map → http-BsqmhurZ.cjs.map} +1 -1
- package/dist/{http-D5kn3_Mt.d.mts → http-DULM1u2L.d.cts} +3 -3
- package/dist/{http-D5kn3_Mt.d.mts.map → http-DULM1u2L.d.cts.map} +1 -1
- package/dist/{http-Dvca6fC3.d.cts → http-GB-Nlvwc.d.mts} +3 -3
- package/dist/{http-Dvca6fC3.d.cts.map → http-GB-Nlvwc.d.mts.map} +1 -1
- package/dist/instrumentation/hono.cjs +2 -2
- package/dist/instrumentation/hono.mjs +2 -2
- package/dist/instrumentation/http.cjs +1 -1
- package/dist/instrumentation/http.d.cts +1 -1
- package/dist/instrumentation/http.d.mts +1 -1
- package/dist/instrumentation/http.mjs +1 -1
- package/dist/instrumentation/index.cjs +5 -5
- package/dist/instrumentation/index.d.cts +3 -3
- package/dist/instrumentation/index.d.mts +3 -3
- package/dist/instrumentation/index.mjs +5 -5
- package/dist/instrumentation/middleware.cjs +2 -2
- package/dist/instrumentation/middleware.d.cts +1 -1
- package/dist/instrumentation/middleware.d.mts +1 -1
- package/dist/instrumentation/middleware.mjs +2 -2
- package/dist/instrumentation/otel.cjs +2 -2
- package/dist/instrumentation/otel.d.cts +1 -1
- package/dist/instrumentation/otel.d.mts +1 -1
- package/dist/instrumentation/otel.mjs +2 -2
- package/dist/instrumentation/setup.cjs +1 -1
- package/dist/instrumentation/setup.mjs +1 -1
- package/dist/logger/console.d.cts.map +1 -1
- package/dist/{middleware-D3v5SnSs.cjs → middleware-Bcq6XXGG.cjs} +3 -3
- package/dist/middleware-Bcq6XXGG.cjs.map +1 -0
- package/dist/{middleware-Dy1ctr2N.mjs → middleware-D1XEHvyy.mjs} +3 -3
- 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-DPKNyJ0t.mjs → otel-B9bNoeZ2.mjs} +4 -4
- package/dist/otel-B9bNoeZ2.mjs.map +1 -0
- package/dist/{otel-1bJPb2Z7.d.mts → otel-Bk89b1lX.d.cts} +3 -3
- package/dist/{otel-1bJPb2Z7.d.mts.map → otel-Bk89b1lX.d.cts.map} +1 -1
- package/dist/{otel-DuiBeBPU.cjs → otel-BzjOtVxZ.cjs} +4 -4
- package/dist/otel-BzjOtVxZ.cjs.map +1 -0
- package/dist/{otel-SBVoVEHr.d.cts → otel-lPMsM26e.d.mts} +3 -3
- package/dist/{otel-SBVoVEHr.d.cts.map → otel-lPMsM26e.d.mts.map} +1 -1
- package/dist/otlp/hono.cjs +3 -3
- package/dist/otlp/hono.mjs +3 -3
- package/dist/otlp/index.cjs +3 -3
- package/dist/otlp/index.mjs +3 -3
- package/dist/otlp/receiver.cjs +3 -3
- package/dist/otlp/receiver.mjs +3 -3
- package/dist/otlp/transformer.cjs +2 -2
- package/dist/otlp/transformer.mjs +2 -2
- package/dist/otlp/types.cjs +1 -1
- package/dist/otlp/types.mjs +1 -1
- package/dist/{receiver-q4f7eirs.mjs → receiver-D46dfkYI.mjs} +2 -2
- package/dist/{receiver-q4f7eirs.mjs.map → receiver-D46dfkYI.mjs.map} +1 -1
- package/dist/{receiver-BW_4go_X.cjs → receiver-slCoAFat.cjs} +2 -2
- package/dist/{receiver-BW_4go_X.cjs.map → receiver-slCoAFat.cjs.map} +1 -1
- package/dist/{setup-BhCp2LUp.mjs → setup-DC9JMEYZ.mjs} +1 -1
- package/dist/{setup-BhCp2LUp.mjs.map → setup-DC9JMEYZ.mjs.map} +1 -1
- package/dist/{setup-_uT4L_x5.cjs → setup-DufxQpi9.cjs} +1 -1
- package/dist/{setup-_uT4L_x5.cjs.map → setup-DufxQpi9.cjs.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-BX8uY2nR.d.cts.map +1 -1
- package/dist/tracing-PnECEbEu.d.mts.map +1 -1
- package/dist/{transformer-CFrJQkUg.mjs → transformer-CFQ4WFk6.mjs} +2 -2
- package/dist/{transformer-CFrJQkUg.mjs.map → transformer-CFQ4WFk6.mjs.map} +1 -1
- package/dist/{transformer-DvDYyFRQ.cjs → transformer-Csl6fbgv.cjs} +2 -2
- package/dist/{transformer-DvDYyFRQ.cjs.map → transformer-Csl6fbgv.cjs.map} +1 -1
- package/dist/types-B1EIa_cQ.d.mts.map +1 -1
- package/dist/{types-BBeTDpHr.cjs → types-BMiHgsi4.cjs} +1 -1
- package/dist/{types-BBeTDpHr.cjs.map → types-BMiHgsi4.cjs.map} +1 -1
- package/dist/{types-CXYLhG_G.mjs → types-Cj59nqy7.mjs} +1 -1
- package/dist/{types-CXYLhG_G.mjs.map → types-Cj59nqy7.mjs.map} +1 -1
- package/dist/types-l7Rlb5Mg.d.cts.map +1 -1
- package/package.json +6 -3
- package/CHANGELOG.md +0 -51
- package/dist/middleware-D3v5SnSs.cjs.map +0 -1
- package/dist/middleware-Dy1ctr2N.mjs.map +0 -1
- package/dist/otel-DPKNyJ0t.mjs.map +0 -1
- package/dist/otel-DuiBeBPU.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/storage/memory.ts
DELETED
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ExceptionEntry,
|
|
3
|
-
LogEntry,
|
|
4
|
-
QueryOptions,
|
|
5
|
-
RequestEntry,
|
|
6
|
-
TelescopeStats,
|
|
7
|
-
TelescopeStorage,
|
|
8
|
-
} from '../types';
|
|
9
|
-
|
|
10
|
-
export interface InMemoryStorageOptions {
|
|
11
|
-
/** Maximum number of entries to keep per type (default: 1000) */
|
|
12
|
-
maxEntries?: number;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* In-memory storage for Telescope data.
|
|
17
|
-
* Ideal for development and testing.
|
|
18
|
-
* Data is lost when the process restarts.
|
|
19
|
-
*/
|
|
20
|
-
export class InMemoryStorage implements TelescopeStorage {
|
|
21
|
-
private requests: RequestEntry[] = [];
|
|
22
|
-
private exceptions: ExceptionEntry[] = [];
|
|
23
|
-
private logs: LogEntry[] = [];
|
|
24
|
-
private maxEntries: number;
|
|
25
|
-
|
|
26
|
-
constructor(options?: InMemoryStorageOptions) {
|
|
27
|
-
this.maxEntries = options?.maxEntries ?? 1000;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Requests
|
|
31
|
-
|
|
32
|
-
async saveRequest(entry: RequestEntry): Promise<void> {
|
|
33
|
-
this.requests.unshift(entry);
|
|
34
|
-
this.enforceLimit('requests');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
async saveRequests(entries: RequestEntry[]): Promise<void> {
|
|
38
|
-
this.requests.unshift(...entries);
|
|
39
|
-
this.enforceLimit('requests');
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async getRequests(options?: QueryOptions): Promise<RequestEntry[]> {
|
|
43
|
-
let result = this.requests;
|
|
44
|
-
|
|
45
|
-
// Apply request-specific filters before generic filtering
|
|
46
|
-
if (options?.method) {
|
|
47
|
-
result = result.filter((r) => r.method === options.method);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (options?.status) {
|
|
51
|
-
const statusFilter = options.status;
|
|
52
|
-
result = result.filter((r) => {
|
|
53
|
-
// Handle status ranges like "2xx", "4xx", "5xx"
|
|
54
|
-
if (statusFilter.endsWith('xx')) {
|
|
55
|
-
const firstChar = statusFilter[0];
|
|
56
|
-
if (!firstChar) return false;
|
|
57
|
-
const category = parseInt(firstChar, 10);
|
|
58
|
-
return Math.floor(r.status / 100) === category;
|
|
59
|
-
}
|
|
60
|
-
// Handle exact status codes
|
|
61
|
-
return r.status === parseInt(statusFilter, 10);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return this.filterEntries(result, options);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async getRequest(id: string): Promise<RequestEntry | null> {
|
|
69
|
-
return this.requests.find((r) => r.id === id) ?? null;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// Exceptions
|
|
73
|
-
|
|
74
|
-
async saveException(entry: ExceptionEntry): Promise<void> {
|
|
75
|
-
this.exceptions.unshift(entry);
|
|
76
|
-
this.enforceLimit('exceptions');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async saveExceptions(entries: ExceptionEntry[]): Promise<void> {
|
|
80
|
-
this.exceptions.unshift(...entries);
|
|
81
|
-
this.enforceLimit('exceptions');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]> {
|
|
85
|
-
return this.filterEntries(this.exceptions, options);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async getException(id: string): Promise<ExceptionEntry | null> {
|
|
89
|
-
return this.exceptions.find((e) => e.id === id) ?? null;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Logs
|
|
93
|
-
|
|
94
|
-
async saveLog(entry: LogEntry): Promise<void> {
|
|
95
|
-
this.logs.unshift(entry);
|
|
96
|
-
this.enforceLimit('logs');
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async saveLogs(entries: LogEntry[]): Promise<void> {
|
|
100
|
-
this.logs.unshift(...entries);
|
|
101
|
-
this.enforceLimit('logs');
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async getLogs(options?: QueryOptions): Promise<LogEntry[]> {
|
|
105
|
-
let result = this.logs;
|
|
106
|
-
|
|
107
|
-
// Apply log-specific filters before generic filtering
|
|
108
|
-
if (options?.level) {
|
|
109
|
-
result = result.filter((l) => l.level === options.level);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return this.filterEntries(result, options);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Cleanup
|
|
116
|
-
|
|
117
|
-
async prune(olderThan: Date): Promise<number> {
|
|
118
|
-
const beforeCount =
|
|
119
|
-
this.requests.length + this.exceptions.length + this.logs.length;
|
|
120
|
-
|
|
121
|
-
this.requests = this.requests.filter((r) => r.timestamp >= olderThan);
|
|
122
|
-
this.exceptions = this.exceptions.filter((e) => e.timestamp >= olderThan);
|
|
123
|
-
this.logs = this.logs.filter((l) => l.timestamp >= olderThan);
|
|
124
|
-
|
|
125
|
-
const afterCount =
|
|
126
|
-
this.requests.length + this.exceptions.length + this.logs.length;
|
|
127
|
-
return beforeCount - afterCount;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Stats
|
|
131
|
-
|
|
132
|
-
async getStats(): Promise<TelescopeStats> {
|
|
133
|
-
const allTimestamps = [
|
|
134
|
-
...this.requests.map((r) => r.timestamp),
|
|
135
|
-
...this.exceptions.map((e) => e.timestamp),
|
|
136
|
-
...this.logs.map((l) => l.timestamp),
|
|
137
|
-
].sort((a, b) => a.getTime() - b.getTime());
|
|
138
|
-
|
|
139
|
-
return {
|
|
140
|
-
requests: this.requests.length,
|
|
141
|
-
exceptions: this.exceptions.length,
|
|
142
|
-
logs: this.logs.length,
|
|
143
|
-
oldestEntry: allTimestamps[0],
|
|
144
|
-
newestEntry: allTimestamps[allTimestamps.length - 1],
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Clear all data (useful for testing)
|
|
149
|
-
|
|
150
|
-
clear(): void {
|
|
151
|
-
this.requests = [];
|
|
152
|
-
this.exceptions = [];
|
|
153
|
-
this.logs = [];
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Private helpers
|
|
157
|
-
|
|
158
|
-
private enforceLimit(type: 'requests' | 'exceptions' | 'logs'): void {
|
|
159
|
-
const entries = this[type];
|
|
160
|
-
if (entries.length > this.maxEntries) {
|
|
161
|
-
if (type === 'requests') {
|
|
162
|
-
this.requests = this.requests.slice(0, this.maxEntries);
|
|
163
|
-
} else if (type === 'exceptions') {
|
|
164
|
-
this.exceptions = this.exceptions.slice(0, this.maxEntries);
|
|
165
|
-
} else {
|
|
166
|
-
this.logs = this.logs.slice(0, this.maxEntries);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
private filterEntries<T extends { timestamp: Date; tags?: string[] }>(
|
|
172
|
-
entries: T[],
|
|
173
|
-
options?: QueryOptions,
|
|
174
|
-
): T[] {
|
|
175
|
-
let result = entries;
|
|
176
|
-
|
|
177
|
-
if (options?.after) {
|
|
178
|
-
result = result.filter((e) => e.timestamp >= options.after!);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (options?.before) {
|
|
182
|
-
result = result.filter((e) => e.timestamp <= options.before!);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
if (options?.tags && options.tags.length > 0) {
|
|
186
|
-
result = result.filter(
|
|
187
|
-
(e) => e.tags && options.tags?.some((t) => e.tags?.includes(t)),
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (options?.search) {
|
|
192
|
-
const searchLower = options.search.toLowerCase();
|
|
193
|
-
result = result.filter((e) => {
|
|
194
|
-
const str = JSON.stringify(e).toLowerCase();
|
|
195
|
-
return str.includes(searchLower);
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const offset = options?.offset ?? 0;
|
|
200
|
-
const limit = options?.limit ?? 50;
|
|
201
|
-
|
|
202
|
-
return result.slice(offset, offset + limit);
|
|
203
|
-
}
|
|
204
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,447 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Stack frame from a parsed error stack trace
|
|
3
|
-
*/
|
|
4
|
-
export interface StackFrame {
|
|
5
|
-
file: string;
|
|
6
|
-
line: number;
|
|
7
|
-
column: number;
|
|
8
|
-
function: string;
|
|
9
|
-
/** Whether this frame is from application code (vs node_modules) */
|
|
10
|
-
isApp: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Source code context around an error
|
|
15
|
-
*/
|
|
16
|
-
export interface SourceContext {
|
|
17
|
-
file: string;
|
|
18
|
-
line: number;
|
|
19
|
-
column: number;
|
|
20
|
-
lines: Array<{ num: number; code: string; highlight: boolean }>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Recorded HTTP request entry
|
|
25
|
-
*/
|
|
26
|
-
export interface RequestEntry {
|
|
27
|
-
id: string;
|
|
28
|
-
method: string;
|
|
29
|
-
path: string;
|
|
30
|
-
url: string;
|
|
31
|
-
headers: Record<string, string>;
|
|
32
|
-
body?: unknown;
|
|
33
|
-
query?: Record<string, string>;
|
|
34
|
-
status: number;
|
|
35
|
-
responseHeaders: Record<string, string>;
|
|
36
|
-
responseBody?: unknown;
|
|
37
|
-
duration: number;
|
|
38
|
-
timestamp: Date;
|
|
39
|
-
ip?: string;
|
|
40
|
-
userId?: string;
|
|
41
|
-
tags?: string[];
|
|
42
|
-
/** Request body size in bytes */
|
|
43
|
-
requestSize?: number;
|
|
44
|
-
/** Response body size in bytes */
|
|
45
|
-
responseSize?: number;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Recorded exception entry
|
|
50
|
-
*/
|
|
51
|
-
export interface ExceptionEntry {
|
|
52
|
-
id: string;
|
|
53
|
-
name: string;
|
|
54
|
-
message: string;
|
|
55
|
-
stack: StackFrame[];
|
|
56
|
-
source?: SourceContext;
|
|
57
|
-
requestId?: string;
|
|
58
|
-
timestamp: Date;
|
|
59
|
-
handled: boolean;
|
|
60
|
-
tags?: string[];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Recorded log entry
|
|
65
|
-
*/
|
|
66
|
-
export interface LogEntry {
|
|
67
|
-
id: string;
|
|
68
|
-
level: 'debug' | 'info' | 'warn' | 'error';
|
|
69
|
-
message: string;
|
|
70
|
-
context?: Record<string, unknown>;
|
|
71
|
-
requestId?: string;
|
|
72
|
-
timestamp: Date;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Query options for retrieving entries
|
|
77
|
-
*/
|
|
78
|
-
export interface QueryOptions {
|
|
79
|
-
limit?: number;
|
|
80
|
-
offset?: number;
|
|
81
|
-
before?: Date;
|
|
82
|
-
after?: Date;
|
|
83
|
-
search?: string;
|
|
84
|
-
tags?: string[];
|
|
85
|
-
/** Filter requests by HTTP method */
|
|
86
|
-
method?: string;
|
|
87
|
-
/** Filter requests by status code (e.g., "2xx", "4xx", "500") */
|
|
88
|
-
status?: string;
|
|
89
|
-
/** Filter logs by level */
|
|
90
|
-
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Storage interface for Telescope data
|
|
95
|
-
* Implementations can use memory, database, or any other backend
|
|
96
|
-
*/
|
|
97
|
-
export interface TelescopeStorage {
|
|
98
|
-
// Requests
|
|
99
|
-
saveRequest(entry: RequestEntry): Promise<void>;
|
|
100
|
-
saveRequests?(entries: RequestEntry[]): Promise<void>;
|
|
101
|
-
getRequests(options?: QueryOptions): Promise<RequestEntry[]>;
|
|
102
|
-
getRequest(id: string): Promise<RequestEntry | null>;
|
|
103
|
-
|
|
104
|
-
// Exceptions
|
|
105
|
-
saveException(entry: ExceptionEntry): Promise<void>;
|
|
106
|
-
saveExceptions?(entries: ExceptionEntry[]): Promise<void>;
|
|
107
|
-
getExceptions(options?: QueryOptions): Promise<ExceptionEntry[]>;
|
|
108
|
-
getException(id: string): Promise<ExceptionEntry | null>;
|
|
109
|
-
|
|
110
|
-
// Logs
|
|
111
|
-
saveLog(entry: LogEntry): Promise<void>;
|
|
112
|
-
saveLogs?(entries: LogEntry[]): Promise<void>;
|
|
113
|
-
getLogs(options?: QueryOptions): Promise<LogEntry[]>;
|
|
114
|
-
|
|
115
|
-
// Cleanup
|
|
116
|
-
prune(olderThan: Date): Promise<number>;
|
|
117
|
-
|
|
118
|
-
// Stats
|
|
119
|
-
getStats(): Promise<TelescopeStats>;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Statistics about stored entries
|
|
124
|
-
*/
|
|
125
|
-
export interface TelescopeStats {
|
|
126
|
-
requests: number;
|
|
127
|
-
exceptions: number;
|
|
128
|
-
logs: number;
|
|
129
|
-
oldestEntry?: Date;
|
|
130
|
-
newestEntry?: Date;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* Redaction configuration for Telescope.
|
|
135
|
-
* Uses @pinojs/redact for immutable, selective redaction.
|
|
136
|
-
*/
|
|
137
|
-
export type TelescopeRedactOptions =
|
|
138
|
-
| boolean
|
|
139
|
-
| string[]
|
|
140
|
-
| {
|
|
141
|
-
/** Paths to redact using dot/bracket notation (e.g., 'headers.authorization', '*.password') */
|
|
142
|
-
paths: string[];
|
|
143
|
-
/** Replacement value (default: '[REDACTED]') */
|
|
144
|
-
censor?: string;
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Configuration options for Telescope
|
|
149
|
-
*/
|
|
150
|
-
export interface TelescopeOptions {
|
|
151
|
-
/** Storage backend for persisting data */
|
|
152
|
-
storage: TelescopeStorage;
|
|
153
|
-
/** Whether telescope is enabled (default: true) */
|
|
154
|
-
enabled?: boolean;
|
|
155
|
-
/** Dashboard path (default: '/__telescope') */
|
|
156
|
-
path?: string;
|
|
157
|
-
/** Whether to record request/response bodies (default: true) */
|
|
158
|
-
recordBody?: boolean;
|
|
159
|
-
/** Maximum body size to record in bytes (default: 64KB) */
|
|
160
|
-
maxBodySize?: number;
|
|
161
|
-
/** URL patterns to ignore (default: []) */
|
|
162
|
-
ignorePatterns?: string[];
|
|
163
|
-
/** Auto-prune entries older than this many hours (default: undefined - no auto-prune) */
|
|
164
|
-
pruneAfterHours?: number;
|
|
165
|
-
/**
|
|
166
|
-
* Redaction configuration for sensitive data.
|
|
167
|
-
* - `true`: Enable redaction with default sensitive paths
|
|
168
|
-
* - `string[]`: Custom paths to redact (merged with defaults)
|
|
169
|
-
* - `{ paths, censor }`: Full control over redaction
|
|
170
|
-
* - `false` or `undefined`: No redaction (default)
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
* // Enable with defaults
|
|
174
|
-
* redact: true
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* // Add custom paths (merged with defaults)
|
|
178
|
-
* redact: ['user.ssn', 'payment.cardNumber']
|
|
179
|
-
*
|
|
180
|
-
* @example
|
|
181
|
-
* // Full control
|
|
182
|
-
* redact: { paths: ['headers.authorization'], censor: '***' }
|
|
183
|
-
*/
|
|
184
|
-
redact?: TelescopeRedactOptions;
|
|
185
|
-
/**
|
|
186
|
-
* Custom request ID getter for correlation with request context.
|
|
187
|
-
* If provided and returns a string, uses that ID instead of generating one.
|
|
188
|
-
* Useful for integrating with ServiceContext.getRequestId() from @geekmidas/services.
|
|
189
|
-
*
|
|
190
|
-
* @example
|
|
191
|
-
* // Integration with request context
|
|
192
|
-
* import { serviceContext } from '@geekmidas/services';
|
|
193
|
-
*
|
|
194
|
-
* const telescope = new Telescope({
|
|
195
|
-
* storage: new InMemoryStorage(),
|
|
196
|
-
* getRequestId: () => serviceContext.hasContext()
|
|
197
|
-
* ? serviceContext.getRequestId()
|
|
198
|
-
* : undefined,
|
|
199
|
-
* });
|
|
200
|
-
*/
|
|
201
|
-
getRequestId?: () => string | undefined;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Normalized telescope options with defaults applied
|
|
206
|
-
*/
|
|
207
|
-
export interface NormalizedTelescopeOptions {
|
|
208
|
-
storage: TelescopeStorage;
|
|
209
|
-
enabled: boolean;
|
|
210
|
-
path: string;
|
|
211
|
-
recordBody: boolean;
|
|
212
|
-
maxBodySize: number;
|
|
213
|
-
ignorePatterns: string[];
|
|
214
|
-
pruneAfterHours?: number;
|
|
215
|
-
getRequestId?: () => string | undefined;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* WebSocket event types
|
|
220
|
-
*/
|
|
221
|
-
export type TelescopeEventType =
|
|
222
|
-
| 'request'
|
|
223
|
-
| 'exception'
|
|
224
|
-
| 'log'
|
|
225
|
-
| 'stats'
|
|
226
|
-
| 'metrics'
|
|
227
|
-
| 'connected';
|
|
228
|
-
|
|
229
|
-
/**
|
|
230
|
-
* Real-time metrics snapshot for WebSocket broadcast
|
|
231
|
-
*/
|
|
232
|
-
export interface MetricsSnapshot {
|
|
233
|
-
/** Timestamp of the snapshot */
|
|
234
|
-
timestamp: number;
|
|
235
|
-
/** Total requests in the time window */
|
|
236
|
-
totalRequests: number;
|
|
237
|
-
/** Requests per second */
|
|
238
|
-
requestsPerSecond: number;
|
|
239
|
-
/** Average duration in milliseconds */
|
|
240
|
-
avgDuration: number;
|
|
241
|
-
/** Error rate as percentage */
|
|
242
|
-
errorRate: number;
|
|
243
|
-
/** 50th percentile duration */
|
|
244
|
-
p50: number;
|
|
245
|
-
/** 95th percentile duration */
|
|
246
|
-
p95: number;
|
|
247
|
-
/** 99th percentile duration */
|
|
248
|
-
p99: number;
|
|
249
|
-
/** Status code distribution */
|
|
250
|
-
statusDistribution: StatusDistribution;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/**
|
|
254
|
-
* WebSocket event payload
|
|
255
|
-
*/
|
|
256
|
-
export interface TelescopeEvent<T = unknown> {
|
|
257
|
-
type: TelescopeEventType;
|
|
258
|
-
payload: T;
|
|
259
|
-
timestamp: number;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Context stored during request processing
|
|
264
|
-
*/
|
|
265
|
-
export interface RequestContext {
|
|
266
|
-
id: string;
|
|
267
|
-
startTime: number;
|
|
268
|
-
method: string;
|
|
269
|
-
path: string;
|
|
270
|
-
url: string;
|
|
271
|
-
headers: Record<string, string>;
|
|
272
|
-
query: Record<string, string>;
|
|
273
|
-
body?: unknown;
|
|
274
|
-
ip?: string;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// ============================================
|
|
278
|
-
// Metrics Types
|
|
279
|
-
// ============================================
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Time range for metrics queries
|
|
283
|
-
*/
|
|
284
|
-
export interface TimeRange {
|
|
285
|
-
/** Start of time range */
|
|
286
|
-
start: Date;
|
|
287
|
-
/** End of time range */
|
|
288
|
-
end: Date;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* A single point in a time series
|
|
293
|
-
*/
|
|
294
|
-
export interface TimeSeriesPoint {
|
|
295
|
-
/** Unix timestamp in milliseconds */
|
|
296
|
-
timestamp: number;
|
|
297
|
-
/** Number of requests in this bucket */
|
|
298
|
-
count: number;
|
|
299
|
-
/** Average duration in milliseconds */
|
|
300
|
-
avgDuration: number;
|
|
301
|
-
/** Number of errors (4xx + 5xx) */
|
|
302
|
-
errorCount: number;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Aggregated request metrics
|
|
307
|
-
*/
|
|
308
|
-
export interface RequestMetrics {
|
|
309
|
-
/** Total number of requests */
|
|
310
|
-
totalRequests: number;
|
|
311
|
-
/** Average duration in milliseconds */
|
|
312
|
-
avgDuration: number;
|
|
313
|
-
/** 50th percentile duration */
|
|
314
|
-
p50Duration: number;
|
|
315
|
-
/** 95th percentile duration */
|
|
316
|
-
p95Duration: number;
|
|
317
|
-
/** 99th percentile duration */
|
|
318
|
-
p99Duration: number;
|
|
319
|
-
/** Error rate as percentage (0-100) */
|
|
320
|
-
errorRate: number;
|
|
321
|
-
/** Success rate as percentage (0-100) */
|
|
322
|
-
successRate: number;
|
|
323
|
-
/** Requests per second (averaged over time range) */
|
|
324
|
-
requestsPerSecond: number;
|
|
325
|
-
/** Time series data for charts */
|
|
326
|
-
timeSeries: TimeSeriesPoint[];
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Metrics for a specific endpoint (method + path pattern)
|
|
331
|
-
*/
|
|
332
|
-
export interface EndpointMetrics {
|
|
333
|
-
/** HTTP method */
|
|
334
|
-
method: string;
|
|
335
|
-
/** Path pattern (e.g., /users/:id) */
|
|
336
|
-
path: string;
|
|
337
|
-
/** Total request count */
|
|
338
|
-
count: number;
|
|
339
|
-
/** Average duration in milliseconds */
|
|
340
|
-
avgDuration: number;
|
|
341
|
-
/** 95th percentile duration */
|
|
342
|
-
p95Duration: number;
|
|
343
|
-
/** Error rate as percentage */
|
|
344
|
-
errorRate: number;
|
|
345
|
-
/** Timestamp of last request */
|
|
346
|
-
lastSeen: number;
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* Status code distribution
|
|
351
|
-
*/
|
|
352
|
-
export interface StatusDistribution {
|
|
353
|
-
/** 2xx responses */
|
|
354
|
-
'2xx': number;
|
|
355
|
-
/** 3xx responses */
|
|
356
|
-
'3xx': number;
|
|
357
|
-
/** 4xx responses */
|
|
358
|
-
'4xx': number;
|
|
359
|
-
/** 5xx responses */
|
|
360
|
-
'5xx': number;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Options for querying metrics
|
|
365
|
-
*/
|
|
366
|
-
export interface MetricsQueryOptions {
|
|
367
|
-
/** Time range for the query */
|
|
368
|
-
range?: TimeRange;
|
|
369
|
-
/** Bucket size for time series in milliseconds (default: 60000 = 1 minute) */
|
|
370
|
-
bucketSize?: number;
|
|
371
|
-
/** Limit number of endpoints returned */
|
|
372
|
-
limit?: number;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
/**
|
|
376
|
-
* A metrics bucket for aggregation (stored in memory/db)
|
|
377
|
-
*/
|
|
378
|
-
export interface MetricsBucket {
|
|
379
|
-
/** Bucket timestamp (start of bucket) */
|
|
380
|
-
timestamp: number;
|
|
381
|
-
/** Bucket duration in milliseconds */
|
|
382
|
-
bucketSize: number;
|
|
383
|
-
/** Request count */
|
|
384
|
-
count: number;
|
|
385
|
-
/** Sum of durations (for calculating avg) */
|
|
386
|
-
durationSum: number;
|
|
387
|
-
/** Min duration */
|
|
388
|
-
durationMin: number;
|
|
389
|
-
/** Max duration */
|
|
390
|
-
durationMax: number;
|
|
391
|
-
/** Duration samples for percentile calculation */
|
|
392
|
-
durationSamples: number[];
|
|
393
|
-
/** Error count (4xx + 5xx) */
|
|
394
|
-
errorCount: number;
|
|
395
|
-
/** Status distribution */
|
|
396
|
-
statusDistribution: StatusDistribution;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* Endpoint-specific metrics bucket
|
|
401
|
-
*/
|
|
402
|
-
export interface EndpointBucket {
|
|
403
|
-
/** HTTP method */
|
|
404
|
-
method: string;
|
|
405
|
-
/** Path pattern */
|
|
406
|
-
path: string;
|
|
407
|
-
/** Request count */
|
|
408
|
-
count: number;
|
|
409
|
-
/** Sum of durations */
|
|
410
|
-
durationSum: number;
|
|
411
|
-
/** Duration samples for percentiles */
|
|
412
|
-
durationSamples: number[];
|
|
413
|
-
/** Error count */
|
|
414
|
-
errorCount: number;
|
|
415
|
-
/** Last seen timestamp */
|
|
416
|
-
lastSeen: number;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/**
|
|
420
|
-
* Detailed metrics for a specific endpoint
|
|
421
|
-
*/
|
|
422
|
-
export interface EndpointDetails {
|
|
423
|
-
/** HTTP method */
|
|
424
|
-
method: string;
|
|
425
|
-
/** Path pattern */
|
|
426
|
-
path: string;
|
|
427
|
-
/** Total request count */
|
|
428
|
-
count: number;
|
|
429
|
-
/** Average duration in milliseconds */
|
|
430
|
-
avgDuration: number;
|
|
431
|
-
/** 50th percentile duration */
|
|
432
|
-
p50Duration: number;
|
|
433
|
-
/** 95th percentile duration */
|
|
434
|
-
p95Duration: number;
|
|
435
|
-
/** 99th percentile duration */
|
|
436
|
-
p99Duration: number;
|
|
437
|
-
/** Error rate as percentage */
|
|
438
|
-
errorRate: number;
|
|
439
|
-
/** Success rate as percentage */
|
|
440
|
-
successRate: number;
|
|
441
|
-
/** Timestamp of last request */
|
|
442
|
-
lastSeen: number;
|
|
443
|
-
/** Status distribution */
|
|
444
|
-
statusDistribution: StatusDistribution;
|
|
445
|
-
/** Time series data for this endpoint */
|
|
446
|
-
timeSeries: TimeSeriesPoint[];
|
|
447
|
-
}
|