@adonis-agora/telescope 0.13.0 → 0.15.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/CHANGELOG.md +77 -0
- package/dist/providers/telescope_provider.d.ts.map +1 -1
- package/dist/providers/telescope_provider.js +7 -2
- package/dist/providers/telescope_provider.js.map +1 -1
- package/dist/providers/telescope_ui_provider.d.ts.map +1 -1
- package/dist/providers/telescope_ui_provider.js +19 -3
- package/dist/providers/telescope_ui_provider.js.map +1 -1
- package/dist/providers/telescope_watchers_provider.d.ts +25 -0
- package/dist/providers/telescope_watchers_provider.d.ts.map +1 -1
- package/dist/providers/telescope_watchers_provider.js +67 -5
- package/dist/providers/telescope_watchers_provider.js.map +1 -1
- package/dist/src/ai/index.d.ts +1 -1
- package/dist/src/ai/index.js +1 -1
- package/dist/src/alerts/index.d.ts +1 -1
- package/dist/src/alerts/index.js +1 -1
- package/dist/src/extension/registry.d.ts +14 -1
- package/dist/src/extension/registry.d.ts.map +1 -1
- package/dist/src/extension/registry.js +38 -0
- package/dist/src/extension/registry.js.map +1 -1
- package/dist/src/extension/types.d.ts +22 -0
- package/dist/src/extension/types.d.ts.map +1 -1
- package/dist/src/extension/types.js.map +1 -1
- package/dist/src/index.d.ts +6 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/index.d.ts +1 -1
- package/dist/src/mcp/index.js +1 -1
- package/dist/src/metrics/metrics_service.d.ts +36 -2
- package/dist/src/metrics/metrics_service.d.ts.map +1 -1
- package/dist/src/metrics/metrics_service.js +61 -6
- package/dist/src/metrics/metrics_service.js.map +1 -1
- package/dist/src/metrics/screens.d.ts +41 -0
- package/dist/src/metrics/screens.d.ts.map +1 -0
- package/dist/src/metrics/screens.js +70 -0
- package/dist/src/metrics/screens.js.map +1 -0
- package/dist/src/metrics/timeseries.d.ts +13 -0
- package/dist/src/metrics/timeseries.d.ts.map +1 -1
- package/dist/src/metrics/timeseries.js +38 -0
- package/dist/src/metrics/timeseries.js.map +1 -1
- package/dist/src/profiling/index.d.ts +1 -1
- package/dist/src/profiling/index.js +1 -1
- package/dist/src/registry.d.ts +30 -0
- package/dist/src/registry.d.ts.map +1 -1
- package/dist/src/registry.js +21 -0
- package/dist/src/registry.js.map +1 -1
- package/dist/src/request_watcher.d.ts +39 -0
- package/dist/src/request_watcher.d.ts.map +1 -1
- package/dist/src/request_watcher.js +45 -0
- package/dist/src/request_watcher.js.map +1 -1
- package/dist/src/store.d.ts +78 -0
- package/dist/src/store.d.ts.map +1 -1
- package/dist/src/stores/lucid.d.ts +37 -1
- package/dist/src/stores/lucid.d.ts.map +1 -1
- package/dist/src/stores/lucid.js +83 -0
- package/dist/src/stores/lucid.js.map +1 -1
- package/dist/src/stores/memory.d.ts +11 -1
- package/dist/src/stores/memory.d.ts.map +1 -1
- package/dist/src/stores/memory.js +61 -0
- package/dist/src/stores/memory.js.map +1 -1
- package/dist/src/telescope_middleware.d.ts +8 -0
- package/dist/src/telescope_middleware.d.ts.map +1 -1
- package/dist/src/telescope_middleware.js +19 -0
- package/dist/src/telescope_middleware.js.map +1 -1
- package/dist/src/ui/api.d.ts +16 -1
- package/dist/src/ui/api.d.ts.map +1 -1
- package/dist/src/ui/api.js +53 -5
- package/dist/src/ui/api.js.map +1 -1
- package/dist/src/ui/define_config.d.ts +12 -0
- package/dist/src/ui/define_config.d.ts.map +1 -1
- package/dist/src/ui/define_config.js +1 -0
- package/dist/src/ui/define_config.js.map +1 -1
- package/dist/src/ui/index.d.ts +1 -1
- package/dist/src/ui/index.js +1 -1
- package/dist/src/watchers/define_config.d.ts +28 -0
- package/dist/src/watchers/define_config.d.ts.map +1 -1
- package/dist/src/watchers/define_config.js +10 -0
- package/dist/src/watchers/define_config.js.map +1 -1
- package/dist/src/watchers/index.d.ts +4 -4
- package/dist/src/watchers/index.d.ts.map +1 -1
- package/dist/src/watchers/index.js +2 -3
- package/dist/src/watchers/index.js.map +1 -1
- package/dist/src/watchers/logs_watcher.d.ts +0 -19
- package/dist/src/watchers/logs_watcher.d.ts.map +1 -1
- package/dist/src/watchers/logs_watcher.js +22 -0
- package/dist/src/watchers/logs_watcher.js.map +1 -1
- package/dist/src/watchers/redis_watcher.d.ts +78 -1
- package/dist/src/watchers/redis_watcher.d.ts.map +1 -1
- package/dist/src/watchers/redis_watcher.js +124 -1
- package/dist/src/watchers/redis_watcher.js.map +1 -1
- package/package.json +1 -1
package/dist/src/registry.d.ts
CHANGED
|
@@ -28,6 +28,28 @@ export interface TelescopeRuntime {
|
|
|
28
28
|
* {@link RequestEnrichment}.
|
|
29
29
|
*/
|
|
30
30
|
requestEnrichment: RequestEnrichment | null;
|
|
31
|
+
/**
|
|
32
|
+
* The dashboard's own URL prefix (e.g. `/telescope`), published by the UI provider.
|
|
33
|
+
*
|
|
34
|
+
* The request middleware skips it. Without that, the console competes with the
|
|
35
|
+
* application on the application's own list: telescope's aggregation endpoints are
|
|
36
|
+
* among the slowest the process serves — that is literally their job — so opening
|
|
37
|
+
* the Overview or Pulse recorded two more slow requests into the app's "slowest
|
|
38
|
+
* routes" ranking and its p99.
|
|
39
|
+
*
|
|
40
|
+
* `null` when the UI is not mounted, or when the host opted back in.
|
|
41
|
+
*/
|
|
42
|
+
selfPath: string | null;
|
|
43
|
+
/**
|
|
44
|
+
* The watcher names actually running, published by both watcher providers.
|
|
45
|
+
*
|
|
46
|
+
* The console needs this to tell "nothing happened" apart from "nothing is being
|
|
47
|
+
* measured". A panel that renders "No N+1 loops detected 🎉" when the `query`
|
|
48
|
+
* watcher is off is not reporting health — it is reporting its own blindness, in
|
|
49
|
+
* the voice of good news. That is worse than showing nothing, because the reader
|
|
50
|
+
* walks away reassured.
|
|
51
|
+
*/
|
|
52
|
+
enabledWatchers: Set<string>;
|
|
31
53
|
/** The booted extension registry (entry types / dashboards / data providers), or `null`. */
|
|
32
54
|
registry: ExtensionRegistry | null;
|
|
33
55
|
/**
|
|
@@ -69,8 +91,16 @@ export interface TelescopeRuntime {
|
|
|
69
91
|
export declare function getTelescopeRuntime(): TelescopeRuntime;
|
|
70
92
|
/** Install the active store + flags (called by the provider at boot). */
|
|
71
93
|
export declare function setTelescopeRuntime(store: TelescopeStore, requestWatcherEnabled: boolean, requestCapture?: RequestCaptureOptions | null, requestEnrichment?: RequestEnrichment | null): void;
|
|
94
|
+
/** Add watcher names to the set the console reads to distinguish "quiet" from "off". */
|
|
95
|
+
export declare function registerEnabledWatchers(names: Iterable<string>): void;
|
|
96
|
+
/** The watcher names currently running. */
|
|
97
|
+
export declare function getEnabledWatchers(): string[];
|
|
98
|
+
/** Publish (or clear) the dashboard's own path so the request middleware can skip it. */
|
|
99
|
+
export declare function setTelescopeSelfPath(path: string | null): void;
|
|
72
100
|
/** Publish the booted extension registry so the UI can serve its dashboards + providers. */
|
|
73
101
|
export declare function setTelescopeExtensionRegistry(registry: ExtensionRegistry | null): void;
|
|
102
|
+
/** The booted extension registry, or `null` when no extensions are configured. */
|
|
103
|
+
export declare function getTelescopeExtensionRegistry(): ExtensionRegistry | null;
|
|
74
104
|
/** Publish the SSE entry-events bus so the UI stream route can subscribe to it. */
|
|
75
105
|
export declare function setTelescopeEntryEvents(entryEvents: EntryEvents | null): void;
|
|
76
106
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,iDAAiD;IACjD,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,cAAc,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C,4FAA4F;IAC5F,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD;;;;;OAKG;IACH,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;;OAKG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,KAAK,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,2EAA2E;IAC3E,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;IAC7B,iDAAiD;IACjD,qBAAqB,EAAE,OAAO,CAAC;IAC/B;;;;OAIG;IACH,cAAc,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC7C;;;OAGG;IACH,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC5C;;;;;;;;;;OAUG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;;;;OAQG;IACH,eAAe,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7B,4FAA4F;IAC5F,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACnC;;;;OAIG;IACH,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB;;;;;OAKG;IACH,oBAAoB,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClD;;;;;OAKG;IACH,WAAW,EAAE,eAAe,GAAG,IAAI,CAAC;IACpC;;;;;OAKG;IACH,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC;AAqBD,iCAAiC;AACjC,wBAAgB,mBAAmB,IAAI,gBAAgB,CAEtD;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,cAAc,EACrB,qBAAqB,EAAE,OAAO,EAC9B,cAAc,GAAE,qBAAqB,GAAG,IAAW,EACnD,iBAAiB,GAAE,iBAAiB,GAAG,IAAW,GACjD,IAAI,CAKN;AAED,wFAAwF;AACxF,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAErE;AAED,2CAA2C;AAC3C,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAE7C;AAED,yFAAyF;AACzF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE9D;AAED,4FAA4F;AAC5F,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAEtF;AAED,kFAAkF;AAClF,wBAAgB,6BAA6B,IAAI,iBAAiB,GAAG,IAAI,CAExE;AAED,mFAAmF;AACnF,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE7E;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,WAAW,EAAE,oBAAoB,GAAG,IAAI,GAAG,IAAI,CAE/F;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,IAAI,CAE9E;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAE3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAExD;AAED,kEAAkE;AAClE,wBAAgB,qBAAqB,IAAI,IAAI,CAa5C"}
|
package/dist/src/registry.js
CHANGED
|
@@ -5,6 +5,8 @@ const runtime = globalStore[RUNTIME_KEY] ?? {
|
|
|
5
5
|
requestWatcherEnabled: false,
|
|
6
6
|
requestCapture: null,
|
|
7
7
|
requestEnrichment: null,
|
|
8
|
+
selfPath: null,
|
|
9
|
+
enabledWatchers: new Set(),
|
|
8
10
|
registry: null,
|
|
9
11
|
entryEvents: null,
|
|
10
12
|
paused: false,
|
|
@@ -24,10 +26,27 @@ export function setTelescopeRuntime(store, requestWatcherEnabled, requestCapture
|
|
|
24
26
|
runtime.requestCapture = requestCapture;
|
|
25
27
|
runtime.requestEnrichment = requestEnrichment;
|
|
26
28
|
}
|
|
29
|
+
/** Add watcher names to the set the console reads to distinguish "quiet" from "off". */
|
|
30
|
+
export function registerEnabledWatchers(names) {
|
|
31
|
+
for (const name of names)
|
|
32
|
+
runtime.enabledWatchers.add(name);
|
|
33
|
+
}
|
|
34
|
+
/** The watcher names currently running. */
|
|
35
|
+
export function getEnabledWatchers() {
|
|
36
|
+
return [...runtime.enabledWatchers].sort();
|
|
37
|
+
}
|
|
38
|
+
/** Publish (or clear) the dashboard's own path so the request middleware can skip it. */
|
|
39
|
+
export function setTelescopeSelfPath(path) {
|
|
40
|
+
runtime.selfPath = path;
|
|
41
|
+
}
|
|
27
42
|
/** Publish the booted extension registry so the UI can serve its dashboards + providers. */
|
|
28
43
|
export function setTelescopeExtensionRegistry(registry) {
|
|
29
44
|
runtime.registry = registry;
|
|
30
45
|
}
|
|
46
|
+
/** The booted extension registry, or `null` when no extensions are configured. */
|
|
47
|
+
export function getTelescopeExtensionRegistry() {
|
|
48
|
+
return runtime.registry;
|
|
49
|
+
}
|
|
31
50
|
/** Publish the SSE entry-events bus so the UI stream route can subscribe to it. */
|
|
32
51
|
export function setTelescopeEntryEvents(entryEvents) {
|
|
33
52
|
runtime.entryEvents = entryEvents;
|
|
@@ -70,6 +89,8 @@ export function resetTelescopeRuntime() {
|
|
|
70
89
|
runtime.requestCapture = null;
|
|
71
90
|
runtime.requestEnrichment = null;
|
|
72
91
|
runtime.registry = null;
|
|
92
|
+
runtime.selfPath = null;
|
|
93
|
+
runtime.enabledWatchers.clear();
|
|
73
94
|
runtime.entryEvents = null;
|
|
74
95
|
runtime.paused = false;
|
|
75
96
|
runtime.diagnosisCoordinator = null;
|
package/dist/src/registry.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,7 +39,43 @@ export interface RequestEntryContent {
|
|
|
39
39
|
id: string;
|
|
40
40
|
email?: string;
|
|
41
41
|
} | null;
|
|
42
|
+
/**
|
|
43
|
+
* What KIND of request this was — see {@link classifyRequest}. `page` is a screen
|
|
44
|
+
* a person navigated to (Inertia visit or server-rendered HTML), `api` is data
|
|
45
|
+
* fetched by code, `asset` is a static file.
|
|
46
|
+
*
|
|
47
|
+
* Optional because entries recorded before this field existed do not have it, and
|
|
48
|
+
* the console has to keep rendering them.
|
|
49
|
+
*/
|
|
50
|
+
kind?: RequestKind;
|
|
42
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* How a request reached the app.
|
|
54
|
+
*
|
|
55
|
+
* The distinction the console could not make before: `GET /pesquisador/escrita` as a
|
|
56
|
+
* page visit and the dozen XHRs that page then fires are all `request` entries with
|
|
57
|
+
* a url, so "most visited screens" and "busiest endpoints" were the same list — and
|
|
58
|
+
* neither answered either question.
|
|
59
|
+
*/
|
|
60
|
+
export type RequestKind = 'page' | 'api' | 'asset';
|
|
61
|
+
/**
|
|
62
|
+
* Classify a request as a screen visit, an API call, or a static asset.
|
|
63
|
+
*
|
|
64
|
+
* Order matters and encodes what is most reliable:
|
|
65
|
+
*
|
|
66
|
+
* 1. Assets go by URL, before anything else — a `.css` fetched with `Accept: * / *`
|
|
67
|
+
* would otherwise land in `api` and drown the endpoint list.
|
|
68
|
+
* 2. `x-inertia` is decisive for `page`. An Inertia visit asks for JSON and IS a
|
|
69
|
+
* screen navigation; going by `Accept` alone would file every one of them as
|
|
70
|
+
* `api`, which is exactly backwards for an Inertia app.
|
|
71
|
+
* 3. Then the response content-type, which describes what was actually served
|
|
72
|
+
* rather than what the client hoped for.
|
|
73
|
+
* 4. Then `Accept: text/html` — a plain browser navigation to a server-rendered
|
|
74
|
+
* page (an Edge template, a redirect landing).
|
|
75
|
+
*
|
|
76
|
+
* Anything left is `api`.
|
|
77
|
+
*/
|
|
78
|
+
export declare function classifyRequest(request: RequestLike, responseContentType?: string): RequestKind;
|
|
43
79
|
/**
|
|
44
80
|
* Default `requestCapture.maxBodyBytes`: bodies over 128 KiB are not captured.
|
|
45
81
|
* ON by default — the safe-by-default guard so a synchronous redaction walk over
|
|
@@ -165,6 +201,9 @@ export interface ResponseLike {
|
|
|
165
201
|
statusCode?: number;
|
|
166
202
|
/** AdonisJS `Response.getStatus()` — the only status accessor Adonis exposes. */
|
|
167
203
|
getStatus?(): number;
|
|
204
|
+
/** Adonis's `response.getHeader(name)`. Optional so a plain stub still satisfies
|
|
205
|
+
* this shape — classification just falls back to the request headers. */
|
|
206
|
+
getHeader?(name: string): unknown;
|
|
168
207
|
};
|
|
169
208
|
}
|
|
170
209
|
export interface HttpContextLike {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request_watcher.d.ts","sourceRoot":"","sources":["../../src/request_watcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,KAAK,EAA+B,MAAM,YAAY,CAAC;AACrE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,8CAA8C;AAC9C,MAAM,WAAW,mBAAmB;IAClC,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,wCAAwC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf;;;;;OAKG;IACH,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"request_watcher.d.ts","sourceRoot":"","sources":["../../src/request_watcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { currentUserRef } from './context_accessor.js';
|
|
2
2
|
import { EntryType } from './entry.js';
|
|
3
|
+
/** File extensions treated as static assets. */
|
|
4
|
+
const ASSET_EXTENSIONS = /\.(?:js|mjs|cjs|css|map|png|jpe?g|gif|svg|webp|avif|ico|woff2?|ttf|eot|mp4|webm|txt|xml|wasm)$/i;
|
|
5
|
+
/**
|
|
6
|
+
* Classify a request as a screen visit, an API call, or a static asset.
|
|
7
|
+
*
|
|
8
|
+
* Order matters and encodes what is most reliable:
|
|
9
|
+
*
|
|
10
|
+
* 1. Assets go by URL, before anything else — a `.css` fetched with `Accept: * / *`
|
|
11
|
+
* would otherwise land in `api` and drown the endpoint list.
|
|
12
|
+
* 2. `x-inertia` is decisive for `page`. An Inertia visit asks for JSON and IS a
|
|
13
|
+
* screen navigation; going by `Accept` alone would file every one of them as
|
|
14
|
+
* `api`, which is exactly backwards for an Inertia app.
|
|
15
|
+
* 3. Then the response content-type, which describes what was actually served
|
|
16
|
+
* rather than what the client hoped for.
|
|
17
|
+
* 4. Then `Accept: text/html` — a plain browser navigation to a server-rendered
|
|
18
|
+
* page (an Edge template, a redirect landing).
|
|
19
|
+
*
|
|
20
|
+
* Anything left is `api`.
|
|
21
|
+
*/
|
|
22
|
+
export function classifyRequest(request, responseContentType) {
|
|
23
|
+
const url = stripQuery(String(request.url()));
|
|
24
|
+
if (ASSET_EXTENSIONS.test(url))
|
|
25
|
+
return 'asset';
|
|
26
|
+
// An Inertia visit sets this and asks for JSON, but it is a screen navigation.
|
|
27
|
+
if (headerString(request, 'x-inertia') !== undefined)
|
|
28
|
+
return 'page';
|
|
29
|
+
if (responseContentType !== undefined && responseContentType.includes('text/html'))
|
|
30
|
+
return 'page';
|
|
31
|
+
const accept = headerString(request, 'accept') ?? '';
|
|
32
|
+
// `text/html` before any `application/json` in the list: browsers send both, and
|
|
33
|
+
// the FIRST one is what they actually prefer.
|
|
34
|
+
if (accept.includes('text/html'))
|
|
35
|
+
return 'page';
|
|
36
|
+
return 'api';
|
|
37
|
+
}
|
|
3
38
|
/**
|
|
4
39
|
* Default `requestCapture.maxBodyBytes`: bodies over 128 KiB are not captured.
|
|
5
40
|
* ON by default — the safe-by-default guard so a synchronous redaction walk over
|
|
@@ -222,6 +257,7 @@ export async function recordRequest(store, ctx, startedAt, options = {}) {
|
|
|
222
257
|
: enrichment.user !== undefined
|
|
223
258
|
? enrichment.user
|
|
224
259
|
: resolveRequestUser(ctx);
|
|
260
|
+
const kind = classifyRequest(ctx.request, responseContentType(ctx));
|
|
225
261
|
// Body capture (gated). Only when the caller opted in AND the request exposes a
|
|
226
262
|
// body accessor. The gate runs HERE — before the store's synchronous redaction
|
|
227
263
|
// walk — so a huge/binary body is replaced by a marker and never walked; a body
|
|
@@ -237,6 +273,7 @@ export async function recordRequest(store, ctx, startedAt, options = {}) {
|
|
|
237
273
|
status,
|
|
238
274
|
durationMs,
|
|
239
275
|
traceId: options.traceId ?? null,
|
|
276
|
+
kind,
|
|
240
277
|
user,
|
|
241
278
|
...(enrichment.context !== undefined ? { context: enrichment.context } : {}),
|
|
242
279
|
...(captureBody !== undefined ? { body: captureBody } : {}),
|
|
@@ -245,6 +282,7 @@ export async function recordRequest(store, ctx, startedAt, options = {}) {
|
|
|
245
282
|
origin: 'http',
|
|
246
283
|
tags: [
|
|
247
284
|
`method:${method}`,
|
|
285
|
+
`kind:${kind}`,
|
|
248
286
|
...(status !== null ? [`status:${status}`] : []),
|
|
249
287
|
...(user?.id ? [`user:${user.id}`] : []),
|
|
250
288
|
...enrichment.tags,
|
|
@@ -256,6 +294,13 @@ export async function recordRequest(store, ctx, startedAt, options = {}) {
|
|
|
256
294
|
recorded.content.traceId = recorded.traceId;
|
|
257
295
|
return recorded;
|
|
258
296
|
}
|
|
297
|
+
/** The response's content-type, when the host exposes a header accessor. */
|
|
298
|
+
function responseContentType(ctx) {
|
|
299
|
+
const value = ctx.response.getHeader?.('content-type');
|
|
300
|
+
if (typeof value === 'string')
|
|
301
|
+
return value;
|
|
302
|
+
return Array.isArray(value) && typeof value[0] === 'string' ? value[0] : undefined;
|
|
303
|
+
}
|
|
259
304
|
/** Drop a `?query=string` suffix from a url. */
|
|
260
305
|
function stripQuery(url) {
|
|
261
306
|
const q = url.indexOf('?');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request_watcher.js","sourceRoot":"","sources":["../../src/request_watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAc,SAAS,EAAoB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"request_watcher.js","sourceRoot":"","sources":["../../src/request_watcher.ts"],"names":[],"mappings":"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"}
|
package/dist/src/store.d.ts
CHANGED
|
@@ -12,6 +12,13 @@ export interface EntryQuery {
|
|
|
12
12
|
familyHash?: string;
|
|
13
13
|
/** Only entries recorded under this trace id. */
|
|
14
14
|
traceId?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Only entries recorded under ANY of these trace ids. Exists so a page of traces
|
|
17
|
+
* can be hydrated with ONE query instead of one per trace: the traces screen picks
|
|
18
|
+
* its page of ids first (see {@link TelescopeStore.listTraceIds}) and then fetches
|
|
19
|
+
* exactly those entries. Composes with `traceId` as an additional constraint.
|
|
20
|
+
*/
|
|
21
|
+
traceIds?: string[];
|
|
15
22
|
/** Only entries strictly older than this instant (keyset-ish pagination). */
|
|
16
23
|
before?: Date;
|
|
17
24
|
/** Only entries newer than this instant. */
|
|
@@ -24,6 +31,46 @@ export interface EntryQuery {
|
|
|
24
31
|
search?: string;
|
|
25
32
|
/** Cap the number of returned entries. */
|
|
26
33
|
limit?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Skip this many entries before returning, for offset pagination. Applied AFTER
|
|
36
|
+
* ordering (newest-first), so `{ limit: 25, offset: 25 }` is the second page.
|
|
37
|
+
*/
|
|
38
|
+
offset?: number;
|
|
39
|
+
}
|
|
40
|
+
/** One row of {@link TelescopeStore.listTraceIds} — a trace and when it was last seen. */
|
|
41
|
+
export interface TraceIdRow {
|
|
42
|
+
traceId: string;
|
|
43
|
+
/** The newest `createdAt` among the trace's entries. */
|
|
44
|
+
lastAt: Date;
|
|
45
|
+
}
|
|
46
|
+
/** One `(bucket, type)` tally from {@link TelescopeStore.countByBucket}. */
|
|
47
|
+
export interface BucketCountRow {
|
|
48
|
+
/** Zero-based bucket index, counted from `after` in `bucketMs` steps. */
|
|
49
|
+
index: number;
|
|
50
|
+
type: string;
|
|
51
|
+
count: number;
|
|
52
|
+
}
|
|
53
|
+
/** The window and bucket size for {@link TelescopeStore.countByBucket}. */
|
|
54
|
+
export interface BucketCountQuery {
|
|
55
|
+
/** Window start (exclusive), the origin bucket indices are counted from. */
|
|
56
|
+
after: Date;
|
|
57
|
+
/** Window end (inclusive). */
|
|
58
|
+
before: Date;
|
|
59
|
+
/** Bucket width in ms. */
|
|
60
|
+
bucketMs: number;
|
|
61
|
+
/** Only entries of this type. */
|
|
62
|
+
type?: string;
|
|
63
|
+
}
|
|
64
|
+
/** The window + page for {@link TelescopeStore.listTraceIds}. */
|
|
65
|
+
export interface TraceIdQuery {
|
|
66
|
+
/** How many trace ids to return. */
|
|
67
|
+
limit: number;
|
|
68
|
+
/** How many to skip, for offset pagination. */
|
|
69
|
+
offset?: number;
|
|
70
|
+
/** Only traces with an entry strictly older than this instant. */
|
|
71
|
+
before?: Date;
|
|
72
|
+
/** Only traces with an entry newer than this instant. */
|
|
73
|
+
after?: Date;
|
|
27
74
|
}
|
|
28
75
|
/**
|
|
29
76
|
* The storage abstraction Telescope records through and the headless query API
|
|
@@ -52,5 +99,36 @@ export interface TelescopeStore {
|
|
|
52
99
|
prune(olderThan: Date, keepLast?: number): Promise<number>;
|
|
53
100
|
/** Delete every stored entry. */
|
|
54
101
|
clear(): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* OPTIONAL fast path for the traces screen: the page of distinct trace ids,
|
|
104
|
+
* ordered by most-recently-seen, WITHOUT loading their entries.
|
|
105
|
+
*
|
|
106
|
+
* Why it exists: summarizing traces means grouping entries by `traceId`, and doing
|
|
107
|
+
* that in JS requires loading every candidate entry first. On a real table (500k+
|
|
108
|
+
* rows, dominated by whichever watcher is chattiest) asking for 80 traces meant
|
|
109
|
+
* reading 50k rows and discarding 99% of them. A store backed by SQL can answer
|
|
110
|
+
* this with `GROUP BY trace_id ORDER BY MAX(created_at) DESC LIMIT/OFFSET`, which
|
|
111
|
+
* is an index walk instead of a scan.
|
|
112
|
+
*
|
|
113
|
+
* OPTIONAL, and that is deliberate: it is a capability, not a requirement. A store
|
|
114
|
+
* that does not implement it (including any third-party one written before this
|
|
115
|
+
* existed) keeps working — the metrics service falls back to scan-and-group, which
|
|
116
|
+
* is correct, just slower.
|
|
117
|
+
*/
|
|
118
|
+
listTraceIds?(query: TraceIdQuery): Promise<TraceIdRow[]>;
|
|
119
|
+
/**
|
|
120
|
+
* OPTIONAL fast path for the throughput chart: per-bucket, per-type COUNTS,
|
|
121
|
+
* without loading the entries.
|
|
122
|
+
*
|
|
123
|
+
* The chart needs exactly two fields — `createdAt` and `type` — but the only way
|
|
124
|
+
* to get them was `list()`, which selects whole rows including the `content` JSON
|
|
125
|
+
* blob. Drawing sixty bars meant shipping every entry in the window out of the
|
|
126
|
+
* database and parsing each one, to then throw all of it away except a timestamp
|
|
127
|
+
* and a string.
|
|
128
|
+
*
|
|
129
|
+
* OPTIONAL, like {@link listTraceIds}: a store without it falls back to
|
|
130
|
+
* scan-and-bucket, which is what this always used to do.
|
|
131
|
+
*/
|
|
132
|
+
countByBucket?(query: BucketCountQuery): Promise<BucketCountRow[]>;
|
|
55
133
|
}
|
|
56
134
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/src/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,4CAA4C;IAC5C,KAAK,CAAC,EAAE,IAAI,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,4CAA4C;IAC5C,KAAK,CAAC,EAAE,IAAI,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,0FAA0F;AAC1F,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,wDAAwD;IACxD,MAAM,EAAE,IAAI,CAAC;CACd;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,2EAA2E;AAC3E,MAAM,WAAW,gBAAgB;IAC/B,4EAA4E;IAC5E,KAAK,EAAE,IAAI,CAAC;IACZ,8BAA8B;IAC9B,MAAM,EAAE,IAAI,CAAC;IACb,0BAA0B;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iEAAiE;AACjE,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,MAAM,CAAC,EAAE,IAAI,CAAC;IACd,yDAAyD;IACzD,KAAK,CAAC,EAAE,IAAI,CAAC;CACd;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEzE,yDAAyD;IACzD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAEvC,mDAAmD;IACnD,IAAI,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;IAE3C,sCAAsC;IACtC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzB;;;OAGG;IACH,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE3D,iCAAiC;IACjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB;;;;;;;;;;;;;;;OAeG;IACH,YAAY,CAAC,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IAE1D;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;CACpE"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Entry, type RecordInput } from '../entry.js';
|
|
2
|
-
import type { EntryQuery, TelescopeStore } from '../store.js';
|
|
2
|
+
import type { BucketCountQuery, BucketCountRow, EntryQuery, TelescopeStore, TraceIdQuery, TraceIdRow } from '../store.js';
|
|
3
3
|
/**
|
|
4
4
|
* The table {@link LucidTelescopeStore} reads and writes. Override via
|
|
5
5
|
* {@link LucidStoreOptions.tableName} when `telescope_entries` collides with an
|
|
@@ -66,8 +66,15 @@ export interface LucidQueryBuilderLike {
|
|
|
66
66
|
where(column: string, value: unknown): this;
|
|
67
67
|
where(column: string, operator: string, value: unknown): this;
|
|
68
68
|
whereRaw(sql: string, bindings?: unknown[]): this;
|
|
69
|
+
whereIn(column: string, values: readonly unknown[]): this;
|
|
70
|
+
whereNotNull(column: string): this;
|
|
69
71
|
orderBy(column: string, direction: 'asc' | 'desc'): this;
|
|
72
|
+
groupBy(...columns: string[]): this;
|
|
70
73
|
limit(value: number): this;
|
|
74
|
+
offset(value: number): this;
|
|
75
|
+
/** Aggregate MAX with an alias, e.g. `max('created_at as last_at')`. Chainable so it
|
|
76
|
+
* composes with `select()` in a grouped query. */
|
|
77
|
+
max(expression: string): this;
|
|
71
78
|
select(...columns: string[]): Promise<Record<string, unknown>[]>;
|
|
72
79
|
count(column: string, alias: string): Promise<Record<string, unknown>[]>;
|
|
73
80
|
delete(): Promise<number>;
|
|
@@ -127,6 +134,35 @@ export declare class LucidTelescopeStore implements TelescopeStore {
|
|
|
127
134
|
record<TContent>(input: RecordInput<TContent>): Promise<Entry<TContent>>;
|
|
128
135
|
get(id: string): Promise<Entry | null>;
|
|
129
136
|
list(query?: EntryQuery): Promise<Entry[]>;
|
|
137
|
+
/**
|
|
138
|
+
* The page of distinct trace ids, most-recently-seen first — the SQL fast path
|
|
139
|
+
* described on {@link TelescopeStore.listTraceIds}.
|
|
140
|
+
*
|
|
141
|
+
* `GROUP BY trace_id` with `MAX(created_at)` lets the database do the grouping and
|
|
142
|
+
* the paging, so the traces screen reads ~`limit` rows instead of every entry in
|
|
143
|
+
* the window. Entries with a NULL `trace_id` are excluded: they belong to no trace
|
|
144
|
+
* and would collapse into one meaningless bucket.
|
|
145
|
+
*/
|
|
146
|
+
listTraceIds(query: TraceIdQuery): Promise<TraceIdRow[]>;
|
|
147
|
+
/**
|
|
148
|
+
* Per-bucket, per-type counts for the throughput chart.
|
|
149
|
+
*
|
|
150
|
+
* The win here is the PROJECTION, not the grouping: the chart needs `created_at`
|
|
151
|
+
* and `type` and nothing else, but the only way to get them was `list()`, which
|
|
152
|
+
* does `select('*')` — shipping every row's `content` JSON blob out of the database
|
|
153
|
+
* and running it through `hydrate()`, to then discard all of it except a timestamp
|
|
154
|
+
* and a string. Two scalar columns instead of a blob is orders of magnitude less
|
|
155
|
+
* bytes on the wire and no per-row JSON parse.
|
|
156
|
+
*
|
|
157
|
+
* The bucketing itself stays in JS, deliberately. Doing it in SQL needs a raw
|
|
158
|
+
* select expression (`(created_at - ?) / ?`), and Lucid exposes `groupByRaw` but no
|
|
159
|
+
* `selectRaw` — the alternative is `rawQuery`, whose result shape differs per driver
|
|
160
|
+
* (`{ rows }` on Postgres, an array on SQLite). Trading a portability bug for the
|
|
161
|
+
* second-order win is a bad deal; the row count is what would justify it, and after
|
|
162
|
+
* the redis-watcher filter that count drops by roughly an order of magnitude. If
|
|
163
|
+
* this is still hot with a clean table, THAT is when it earns the raw query.
|
|
164
|
+
*/
|
|
165
|
+
countByBucket(query: BucketCountQuery): Promise<BucketCountRow[]>;
|
|
130
166
|
count(): Promise<number>;
|
|
131
167
|
prune(olderThan: Date, keepLast?: number): Promise<number>;
|
|
132
168
|
clear(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lucid.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,KAAK,EAAiB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC5F,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"lucid.d.ts","sourceRoot":"","sources":["../../../src/stores/lucid.ts"],"names":[],"mappings":"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"}
|
package/dist/src/stores/lucid.js
CHANGED
|
@@ -181,6 +181,13 @@ export class LucidTelescopeStore {
|
|
|
181
181
|
builder = builder.where('family_hash', query.familyHash);
|
|
182
182
|
if (query.traceId !== undefined)
|
|
183
183
|
builder = builder.where('trace_id', query.traceId);
|
|
184
|
+
if (query.traceIds !== undefined) {
|
|
185
|
+
// An empty list means "no traces", not "no filter" — whereIn([]) already yields
|
|
186
|
+
// zero rows, but being explicit keeps a caller's empty page from becoming a scan.
|
|
187
|
+
if (query.traceIds.length === 0)
|
|
188
|
+
return [];
|
|
189
|
+
builder = builder.whereIn('trace_id', query.traceIds);
|
|
190
|
+
}
|
|
184
191
|
if (query.before !== undefined)
|
|
185
192
|
builder = builder.where('created_at', '<', query.before.getTime());
|
|
186
193
|
if (query.after !== undefined)
|
|
@@ -200,9 +207,85 @@ export class LucidTelescopeStore {
|
|
|
200
207
|
builder = builder.orderBy('created_at', 'desc').orderBy('sequence', 'desc');
|
|
201
208
|
if (query.limit !== undefined)
|
|
202
209
|
builder = builder.limit(query.limit);
|
|
210
|
+
if (query.offset !== undefined && query.offset > 0)
|
|
211
|
+
builder = builder.offset(query.offset);
|
|
203
212
|
const rows = await builder.select('*');
|
|
204
213
|
return rows.map((r) => hydrate(r));
|
|
205
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* The page of distinct trace ids, most-recently-seen first — the SQL fast path
|
|
217
|
+
* described on {@link TelescopeStore.listTraceIds}.
|
|
218
|
+
*
|
|
219
|
+
* `GROUP BY trace_id` with `MAX(created_at)` lets the database do the grouping and
|
|
220
|
+
* the paging, so the traces screen reads ~`limit` rows instead of every entry in
|
|
221
|
+
* the window. Entries with a NULL `trace_id` are excluded: they belong to no trace
|
|
222
|
+
* and would collapse into one meaningless bucket.
|
|
223
|
+
*/
|
|
224
|
+
async listTraceIds(query) {
|
|
225
|
+
await this.init();
|
|
226
|
+
let builder = this.db.from(this.tableName);
|
|
227
|
+
if (query.before !== undefined)
|
|
228
|
+
builder = builder.where('created_at', '<', query.before.getTime());
|
|
229
|
+
if (query.after !== undefined)
|
|
230
|
+
builder = builder.where('created_at', '>', query.after.getTime());
|
|
231
|
+
// `select()` resolves the query, so it goes LAST — every chainable clause
|
|
232
|
+
// (including the MAX aggregate) has to be applied before it.
|
|
233
|
+
const rows = await builder
|
|
234
|
+
.whereNotNull('trace_id')
|
|
235
|
+
.groupBy('trace_id')
|
|
236
|
+
.max('created_at as last_at')
|
|
237
|
+
.orderBy('last_at', 'desc')
|
|
238
|
+
.limit(query.limit)
|
|
239
|
+
.offset(query.offset ?? 0)
|
|
240
|
+
.select('trace_id');
|
|
241
|
+
return rows.map((row) => ({
|
|
242
|
+
traceId: row.trace_id,
|
|
243
|
+
lastAt: new Date(toInt(row.last_at)),
|
|
244
|
+
}));
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Per-bucket, per-type counts for the throughput chart.
|
|
248
|
+
*
|
|
249
|
+
* The win here is the PROJECTION, not the grouping: the chart needs `created_at`
|
|
250
|
+
* and `type` and nothing else, but the only way to get them was `list()`, which
|
|
251
|
+
* does `select('*')` — shipping every row's `content` JSON blob out of the database
|
|
252
|
+
* and running it through `hydrate()`, to then discard all of it except a timestamp
|
|
253
|
+
* and a string. Two scalar columns instead of a blob is orders of magnitude less
|
|
254
|
+
* bytes on the wire and no per-row JSON parse.
|
|
255
|
+
*
|
|
256
|
+
* The bucketing itself stays in JS, deliberately. Doing it in SQL needs a raw
|
|
257
|
+
* select expression (`(created_at - ?) / ?`), and Lucid exposes `groupByRaw` but no
|
|
258
|
+
* `selectRaw` — the alternative is `rawQuery`, whose result shape differs per driver
|
|
259
|
+
* (`{ rows }` on Postgres, an array on SQLite). Trading a portability bug for the
|
|
260
|
+
* second-order win is a bad deal; the row count is what would justify it, and after
|
|
261
|
+
* the redis-watcher filter that count drops by roughly an order of magnitude. If
|
|
262
|
+
* this is still hot with a clean table, THAT is when it earns the raw query.
|
|
263
|
+
*/
|
|
264
|
+
async countByBucket(query) {
|
|
265
|
+
await this.init();
|
|
266
|
+
const startMs = query.after.getTime();
|
|
267
|
+
const bucketMs = Math.max(1, Math.floor(query.bucketMs));
|
|
268
|
+
let builder = this.db
|
|
269
|
+
.from(this.tableName)
|
|
270
|
+
.where('created_at', '>', startMs)
|
|
271
|
+
.where('created_at', '<=', query.before.getTime());
|
|
272
|
+
if (query.type !== undefined)
|
|
273
|
+
builder = builder.where('type', query.type);
|
|
274
|
+
const rows = (await builder.select('created_at', 'type'));
|
|
275
|
+
const tally = new Map();
|
|
276
|
+
for (const row of rows) {
|
|
277
|
+
const index = Math.floor((toInt(row.created_at) - startMs) / bucketMs);
|
|
278
|
+
const key = `${index}\u0000${row.type}`;
|
|
279
|
+
const seen = tally.get(key);
|
|
280
|
+
if (seen === undefined) {
|
|
281
|
+
tally.set(key, { index, type: row.type, count: 1 });
|
|
282
|
+
}
|
|
283
|
+
else {
|
|
284
|
+
seen.count += 1;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return [...tally.values()];
|
|
288
|
+
}
|
|
206
289
|
async count() {
|
|
207
290
|
await this.init();
|
|
208
291
|
const rows = await this.db.from(this.tableName).count('*', 'total');
|