adonisjs-server-stats 1.10.0 → 1.11.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 +23 -14
- package/dist/core/config-utils.d.ts +8 -0
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/dashboard-data-controller.d.ts +16 -0
- package/dist/core/dashboard-data-helpers.d.ts +12 -0
- package/dist/core/debug-data-controller.d.ts +4 -0
- package/dist/core/define-config-helpers.d.ts +25 -0
- package/dist/core/feature-detect-helpers.d.ts +36 -0
- package/dist/core/field-resolvers.d.ts +64 -0
- package/dist/core/formatters-helpers.d.ts +23 -0
- package/dist/core/formatters.d.ts +15 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +599 -509
- package/dist/core/log-utils-helpers.d.ts +13 -0
- package/dist/core/metrics.d.ts +3 -28
- package/dist/core/pagination.d.ts +0 -9
- package/dist/core/server-stats-controller.d.ts +6 -0
- package/dist/core/transmit-helpers.d.ts +7 -0
- package/dist/core/types-dashboard.d.ts +178 -0
- package/dist/core/types-diagnostics.d.ts +85 -0
- package/dist/core/types.d.ts +10 -442
- package/dist/react/CacheSection-BYN53kYO.js +135 -0
- package/dist/react/CacheStatsBar-CRodCOeP.js +27 -0
- package/dist/react/CacheTab-DOhuK05d.js +106 -0
- package/dist/react/{ConfigSection-DfFd-WRq.js → ConfigSection-B9EHh4Rp.js} +1 -1
- package/dist/react/{ConfigTab-Bdg8YMer.js → ConfigTab-C8kriE2b.js} +1 -1
- package/dist/react/CustomPaneTab-CvzQS_Wh.js +99 -0
- package/dist/react/EmailPreviewOverlay-BmXOAvqG.js +58 -0
- package/dist/react/EmailsSection-BJyFJf7A.js +226 -0
- package/dist/react/EmailsTab-Ch8jp10B.js +110 -0
- package/dist/react/{EventsSection-ByQ-9blq.js → EventsSection-DJPwHeT8.js} +28 -27
- package/dist/react/EventsTab-B-FoehXC.js +58 -0
- package/dist/react/{FilterBar-DQRXpWrb.js → FilterBar-CQ7bD669.js} +15 -15
- package/dist/react/{InternalsContent-DBzsI0CG.js → InternalsContent-O8ino9oM.js} +133 -109
- package/dist/react/InternalsSection-B6VlVx5f.js +22 -0
- package/dist/react/InternalsTab-CkEKpRMU.js +17 -0
- package/dist/react/JobStatsBar-C7RslAFE.js +30 -0
- package/dist/react/JobsSection-DWF4i1t_.js +167 -0
- package/dist/react/JobsTab-DqnifQXV.js +129 -0
- package/dist/react/LogEntryRow-CMMkqA9M.js +43 -0
- package/dist/react/LogsSection-C1xC5aP4.js +198 -0
- package/dist/react/LogsTab-CS4sLfLw.js +79 -0
- package/dist/react/{OverviewSection-C4T1ur51.js → OverviewSection-CxvfOR0v.js} +70 -80
- package/dist/react/QueriesSection-CrMdU5Ax.js +458 -0
- package/dist/react/{QueriesTab-osLUWd4L.js → QueriesTab-x85PjkyS.js} +38 -40
- package/dist/react/RequestsSection-DETN9oZb.js +321 -0
- package/dist/react/{RoutesSection-BUSkM6PY.js → RoutesSection-CmorkJeC.js} +2 -2
- package/dist/react/RoutesTab-CbzBOzpc.js +68 -0
- package/dist/react/SplitPaneWrapper-BiIgT4ND.js +49 -0
- package/dist/react/TimeAgoCell-o3KigGfM.js +8 -0
- package/dist/react/{TimelineTab-Covg5weo.js → TimelineTab-Ue9tUD_n.js} +76 -102
- package/dist/react/index-DwDK-4oX.js +1121 -0
- package/dist/react/index.js +6 -6
- package/dist/react/react/components/shared/CacheStatsBar.d.ts +13 -0
- package/dist/react/react/components/shared/EmailPreviewOverlay.d.ts +29 -0
- package/dist/react/react/components/{Dashboard/shared → shared}/FilterBar.d.ts +4 -3
- package/dist/react/react/components/shared/JobStatsBar.d.ts +12 -0
- package/dist/react/react/components/shared/LogEntryRow.d.ts +9 -0
- package/dist/react/react/components/shared/RelatedLogs.d.ts +2 -2
- package/dist/react/react/components/shared/SplitPaneWrapper.d.ts +7 -0
- package/dist/react/react/components/shared/TimeAgoCell.d.ts +17 -0
- package/dist/react/react/hooks/useDashboardData.d.ts +4 -8
- package/dist/react/react/hooks/useDiagnosticsData.d.ts +14 -0
- package/dist/react/style.css +1 -1
- package/dist/src/collectors/app_collector.d.ts +0 -8
- package/dist/src/collectors/app_collector.js +45 -52
- package/dist/src/collectors/auto_detect.d.ts +0 -23
- package/dist/src/collectors/auto_detect.js +33 -55
- package/dist/src/collectors/db_pool_collector.d.ts +14 -16
- package/dist/src/collectors/db_pool_collector.js +72 -57
- package/dist/src/collectors/log_collector.d.ts +0 -47
- package/dist/src/collectors/log_collector.js +36 -65
- package/dist/src/collectors/queue_collector.d.ts +0 -20
- package/dist/src/collectors/queue_collector.js +60 -76
- package/dist/src/collectors/redis_collector.d.ts +10 -10
- package/dist/src/collectors/redis_collector.js +69 -66
- package/dist/src/config/deprecation_migration.d.ts +7 -0
- package/dist/src/config/deprecation_migration.js +201 -0
- package/dist/src/controller/debug_controller.d.ts +1 -1
- package/dist/src/controller/debug_controller.js +87 -81
- package/dist/src/dashboard/cache_handlers.d.ts +14 -0
- package/dist/src/dashboard/cache_handlers.js +52 -0
- package/dist/src/dashboard/chart_aggregator.d.ts +0 -7
- package/dist/src/dashboard/chart_aggregator.js +68 -50
- package/dist/src/dashboard/coalesce_cache.d.ts +25 -0
- package/dist/src/dashboard/coalesce_cache.js +47 -0
- package/dist/src/dashboard/dashboard_controller.d.ts +11 -37
- package/dist/src/dashboard/dashboard_controller.js +51 -544
- package/dist/src/dashboard/dashboard_page_assets.d.ts +17 -0
- package/dist/src/dashboard/dashboard_page_assets.js +51 -0
- package/dist/src/dashboard/dashboard_store.d.ts +19 -218
- package/dist/src/dashboard/dashboard_store.js +115 -1116
- package/dist/src/dashboard/dashboard_types.d.ts +83 -0
- package/dist/src/dashboard/dashboard_types.js +4 -0
- package/dist/src/dashboard/detail_queries.d.ts +19 -0
- package/dist/src/dashboard/detail_queries.js +98 -0
- package/dist/src/dashboard/email_event_builder.d.ts +8 -0
- package/dist/src/dashboard/email_event_builder.js +65 -0
- package/dist/src/dashboard/explain_query.d.ts +8 -0
- package/dist/src/dashboard/explain_query.js +22 -0
- package/dist/src/dashboard/filter_handlers.d.ts +23 -0
- package/dist/src/dashboard/filter_handlers.js +56 -0
- package/dist/src/dashboard/filtered_queries.d.ts +15 -0
- package/dist/src/dashboard/filtered_queries.js +155 -0
- package/dist/src/dashboard/flush_manager.d.ts +25 -0
- package/dist/src/dashboard/flush_manager.js +107 -0
- package/dist/src/dashboard/format_helpers.d.ts +126 -0
- package/dist/src/dashboard/format_helpers.js +140 -0
- package/dist/src/dashboard/inspector_manager.d.ts +36 -0
- package/dist/src/dashboard/inspector_manager.js +102 -0
- package/dist/src/dashboard/integrations/config_inspector.js +11 -13
- package/dist/src/dashboard/integrations/queue_inspector.d.ts +3 -3
- package/dist/src/dashboard/integrations/queue_inspector.js +13 -10
- package/dist/src/dashboard/jobs_handlers.d.ts +14 -0
- package/dist/src/dashboard/jobs_handlers.js +61 -0
- package/dist/src/dashboard/knex_factory.d.ts +18 -0
- package/dist/src/dashboard/knex_factory.js +91 -0
- package/dist/src/dashboard/migrator.js +30 -159
- package/dist/src/dashboard/migrator_tables.d.ts +19 -0
- package/dist/src/dashboard/migrator_tables.js +153 -0
- package/dist/src/dashboard/overview_queries.d.ts +66 -0
- package/dist/src/dashboard/overview_queries.js +155 -0
- package/dist/src/dashboard/overview_query_runners.d.ts +25 -0
- package/dist/src/dashboard/overview_query_runners.js +84 -0
- package/dist/src/dashboard/overview_store_queries.d.ts +40 -0
- package/dist/src/dashboard/overview_store_queries.js +69 -0
- package/dist/src/dashboard/paginate_helper.d.ts +12 -0
- package/dist/src/dashboard/paginate_helper.js +33 -0
- package/dist/src/dashboard/query_explain_handler.d.ts +10 -0
- package/dist/src/dashboard/query_explain_handler.js +80 -0
- package/dist/src/dashboard/read_queries.d.ts +32 -0
- package/dist/src/dashboard/read_queries.js +107 -0
- package/dist/src/dashboard/saved_filter_queries.d.ts +10 -0
- package/dist/src/dashboard/saved_filter_queries.js +24 -0
- package/dist/src/dashboard/storage_stats.d.ts +41 -0
- package/dist/src/dashboard/storage_stats.js +81 -0
- package/dist/src/dashboard/write_queue.d.ts +106 -0
- package/dist/src/dashboard/write_queue.js +225 -0
- package/dist/src/data/data_access.d.ts +2 -39
- package/dist/src/data/data_access.js +17 -193
- package/dist/src/data/data_access_helpers.d.ts +130 -0
- package/dist/src/data/data_access_helpers.js +212 -0
- package/dist/src/debug/debug_store.js +37 -32
- package/dist/src/debug/email_collector.d.ts +1 -10
- package/dist/src/debug/email_collector.js +78 -81
- package/dist/src/debug/event_collector.d.ts +0 -9
- package/dist/src/debug/event_collector.js +79 -62
- package/dist/src/debug/query_collector.js +23 -19
- package/dist/src/debug/route_inspector.d.ts +1 -5
- package/dist/src/debug/route_inspector.js +50 -51
- package/dist/src/debug/trace_collector.d.ts +9 -1
- package/dist/src/debug/trace_collector.js +21 -15
- package/dist/src/debug/types.d.ts +1 -1
- package/dist/src/define_config.d.ts +0 -65
- package/dist/src/define_config.js +93 -333
- package/dist/src/edge/client/dashboard.js +2 -2
- package/dist/src/edge/client/debug-panel-deferred.js +1 -1
- package/dist/src/edge/client/stats-bar.js +1 -1
- package/dist/src/edge/client-vue/dashboard.js +5 -5
- package/dist/src/edge/client-vue/debug-panel-deferred.js +4 -4
- package/dist/src/edge/client-vue/stats-bar.js +3 -3
- package/dist/src/edge/plugin.d.ts +0 -16
- package/dist/src/edge/plugin.js +57 -64
- package/dist/src/engine/request_metrics.d.ts +1 -0
- package/dist/src/engine/request_metrics.js +32 -42
- package/dist/src/middleware/request_tracking_middleware.d.ts +2 -8
- package/dist/src/middleware/request_tracking_middleware.js +65 -93
- package/dist/src/provider/auth_middleware_detector.d.ts +16 -0
- package/dist/src/provider/auth_middleware_detector.js +97 -0
- package/dist/src/provider/boot_helpers.d.ts +20 -0
- package/dist/src/provider/boot_helpers.js +91 -0
- package/dist/src/provider/boot_initializer.d.ts +28 -0
- package/dist/src/provider/boot_initializer.js +35 -0
- package/dist/src/provider/dashboard_init.d.ts +30 -0
- package/dist/src/provider/dashboard_init.js +138 -0
- package/dist/src/provider/dashboard_setup.d.ts +25 -0
- package/dist/src/provider/dashboard_setup.js +78 -0
- package/dist/src/provider/diagnostics.d.ts +134 -0
- package/dist/src/provider/diagnostics.js +127 -0
- package/dist/src/provider/email_bridge.d.ts +43 -0
- package/dist/src/provider/email_bridge.js +80 -0
- package/dist/src/provider/email_helpers.d.ts +13 -0
- package/dist/src/provider/email_helpers.js +68 -0
- package/dist/src/provider/pino_hook.d.ts +17 -0
- package/dist/src/provider/pino_hook.js +35 -0
- package/dist/src/provider/provider_helpers_extra.d.ts +47 -0
- package/dist/src/provider/provider_helpers_extra.js +177 -0
- package/dist/src/provider/server_stats_provider.d.ts +39 -85
- package/dist/src/provider/server_stats_provider.js +132 -951
- package/dist/src/provider/shutdown_helpers.d.ts +43 -0
- package/dist/src/provider/shutdown_helpers.js +70 -0
- package/dist/src/provider/toolbar_setup.d.ts +57 -0
- package/dist/src/provider/toolbar_setup.js +141 -0
- package/dist/src/routes/dashboard_routes.d.ts +14 -0
- package/dist/src/routes/dashboard_routes.js +197 -0
- package/dist/src/routes/debug_routes.d.ts +14 -0
- package/dist/src/routes/debug_routes.js +101 -0
- package/dist/src/routes/register_routes.d.ts +0 -78
- package/dist/src/routes/register_routes.js +22 -352
- package/dist/src/routes/stats_routes.d.ts +5 -0
- package/dist/src/routes/stats_routes.js +14 -0
- package/dist/src/styles/components.css +163 -0
- package/dist/src/styles/dashboard.css +13 -105
- package/dist/src/styles/debug-panel.css +2 -53
- package/dist/src/styles/utilities.css +3 -1
- package/dist/src/types.d.ts +305 -14
- package/dist/vue/{CacheSection-oFAJL3mo.js → CacheSection-DT2Mwf_s.js} +1 -1
- package/dist/vue/{ConfigSection-BhfJ4KqL.js → ConfigSection-BwKwS9lh.js} +1 -1
- package/dist/vue/CustomPaneTab-Hr1IBHfz.js +172 -0
- package/dist/vue/{EmailsSection-BcNyhyHs.js → EmailsSection-B65g0FVS.js} +1 -1
- package/dist/vue/{EventsSection-r60Q5Lmu.js → EventsSection-CxqtVF-o.js} +1 -1
- package/dist/vue/{JobsSection-BHL-hkQw.js → JobsSection-rMIyMb-g.js} +1 -1
- package/dist/vue/{LogsSection-DRMGzJmg.js → LogsSection-DmmZVJ7D.js} +9 -3
- package/dist/vue/{LogsTab-Bg3o0Mm6.js → LogsTab-47zEK7jL.js} +4 -1
- package/dist/vue/{OverviewSection-CXh6Ja1B.js → OverviewSection-BMabyqw-.js} +49 -50
- package/dist/vue/{QueriesSection-IodIsCJ-.js → QueriesSection-BfDFwGqH.js} +44 -45
- package/dist/vue/{QueriesTab-C8_7oprC.js → QueriesTab-DuTG7cpC.js} +30 -31
- package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-Py1iu9GU.js +77 -0
- package/dist/vue/{RequestsSection-BPuMdmMc.js → RequestsSection-CTu4jPZ_.js} +143 -147
- package/dist/vue/{RoutesSection-NKo3Rbq3.js → RoutesSection-zQZDedL7.js} +1 -1
- package/dist/vue/TimelineTab-DHfXsX7t.js +334 -0
- package/dist/vue/components/shared/RelatedLogs.vue.d.ts +1 -4
- package/dist/vue/composables/useDashboardData.d.ts +12 -23
- package/dist/vue/index-CM3yNVUR.js +1232 -0
- package/dist/vue/index.js +1 -1
- package/dist/vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/react/CacheSection-UCMptWyn.js +0 -146
- package/dist/react/CacheTab-CA8LB1J5.js +0 -123
- package/dist/react/CustomPaneTab-Bxtv_8Rw.js +0 -104
- package/dist/react/EmailsSection-CM7stSyh.js +0 -262
- package/dist/react/EmailsTab-BDhEiomM.js +0 -153
- package/dist/react/EventsTab-CMfY98Rl.js +0 -63
- package/dist/react/InternalsSection-t7ihcWO-.js +0 -32
- package/dist/react/InternalsTab-Oij0A2fN.js +0 -30
- package/dist/react/JobsSection-DF3qEv9O.js +0 -187
- package/dist/react/JobsTab-BbrBWIOb.js +0 -141
- package/dist/react/LogsSection-DcFTZY7b.js +0 -227
- package/dist/react/LogsTab-CicucmVk.js +0 -103
- package/dist/react/QueriesSection-PswteoF9.js +0 -461
- package/dist/react/RelatedLogs-DFDOyUMr.js +0 -40
- package/dist/react/RequestsSection-Nag30rEA.js +0 -341
- package/dist/react/RoutesTab-DgVzd2PZ.js +0 -74
- package/dist/react/index-Cflz9Ebj.js +0 -1069
- package/dist/vue/CustomPaneTab-BJxT5Dp7.js +0 -172
- package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-CB2_TzYW.js +0 -84
- package/dist/vue/TimelineTab-zj5Z5OdT.js +0 -338
- package/dist/vue/index-Dtgysd26.js +0 -1229
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shutdown helper functions extracted from ServerStatsProvider.
|
|
3
|
+
*/
|
|
4
|
+
/** Timer references that need to be cleared on shutdown. */
|
|
5
|
+
export interface TimerRefs {
|
|
6
|
+
intervalId: ReturnType<typeof setInterval> | null;
|
|
7
|
+
flushTimer: ReturnType<typeof setInterval> | null;
|
|
8
|
+
dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
|
|
9
|
+
debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Clear all active timers and null out the references.
|
|
13
|
+
* Returns the (now-nulled) timer refs for convenience.
|
|
14
|
+
*/
|
|
15
|
+
export declare function clearAllTimers(timers: TimerRefs): TimerRefs;
|
|
16
|
+
/** Minimal interface for debug store persistence. */
|
|
17
|
+
interface Persistable {
|
|
18
|
+
saveToDisk(path: string): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Persist debug data to disk. Logs a warning on failure.
|
|
22
|
+
*/
|
|
23
|
+
export declare function persistDebugData(store: Persistable | null, path: string | null): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Unsubscribe from the Redis email bridge channel.
|
|
26
|
+
* Returns null so callers can clear their reference in one step.
|
|
27
|
+
*/
|
|
28
|
+
export declare function unsubscribeEmailBridge(redis: unknown, channel: string): null;
|
|
29
|
+
/** Stoppable service interface. */
|
|
30
|
+
interface Stoppable {
|
|
31
|
+
stop(): void | Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Clean up log stream, dashboard, and middleware resources.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cleanupResources(deps: {
|
|
37
|
+
logStreamService: Stoppable | null;
|
|
38
|
+
dashboardLogStream: Stoppable | null;
|
|
39
|
+
dashboardStore: Stoppable | null;
|
|
40
|
+
debugStore: Stoppable | null;
|
|
41
|
+
engine: Stoppable | null;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shutdown helper functions extracted from ServerStatsProvider.
|
|
3
|
+
*/
|
|
4
|
+
import { setOnRequestComplete, setDashboardPath, setExcludedPrefixes, } from '../middleware/request_tracking_middleware.js';
|
|
5
|
+
import { log } from '../utils/logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Clear all active timers and null out the references.
|
|
8
|
+
* Returns the (now-nulled) timer refs for convenience.
|
|
9
|
+
*/
|
|
10
|
+
export function clearAllTimers(timers) {
|
|
11
|
+
if (timers.intervalId) {
|
|
12
|
+
clearInterval(timers.intervalId);
|
|
13
|
+
timers.intervalId = null;
|
|
14
|
+
}
|
|
15
|
+
if (timers.flushTimer) {
|
|
16
|
+
clearInterval(timers.flushTimer);
|
|
17
|
+
timers.flushTimer = null;
|
|
18
|
+
}
|
|
19
|
+
if (timers.dashboardBroadcastTimer) {
|
|
20
|
+
clearInterval(timers.dashboardBroadcastTimer);
|
|
21
|
+
timers.dashboardBroadcastTimer = null;
|
|
22
|
+
}
|
|
23
|
+
if (timers.debugBroadcastTimer) {
|
|
24
|
+
clearTimeout(timers.debugBroadcastTimer);
|
|
25
|
+
timers.debugBroadcastTimer = null;
|
|
26
|
+
}
|
|
27
|
+
return timers;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Persist debug data to disk. Logs a warning on failure.
|
|
31
|
+
*/
|
|
32
|
+
export async function persistDebugData(store, path) {
|
|
33
|
+
if (!path || !store)
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
await store.saveToDisk(path);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
log.warn('could not save debug data on shutdown — ' + err?.message);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Unsubscribe from the Redis email bridge channel.
|
|
44
|
+
* Returns null so callers can clear their reference in one step.
|
|
45
|
+
*/
|
|
46
|
+
export function unsubscribeEmailBridge(redis, channel) {
|
|
47
|
+
if (!redis)
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
;
|
|
51
|
+
redis.unsubscribe(channel);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Ignore cleanup errors
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Clean up log stream, dashboard, and middleware resources.
|
|
60
|
+
*/
|
|
61
|
+
export async function cleanupResources(deps) {
|
|
62
|
+
deps.logStreamService?.stop();
|
|
63
|
+
deps.dashboardLogStream?.stop();
|
|
64
|
+
setOnRequestComplete(null);
|
|
65
|
+
setDashboardPath(null);
|
|
66
|
+
setExcludedPrefixes([]);
|
|
67
|
+
await deps.dashboardStore?.stop();
|
|
68
|
+
deps.debugStore?.stop();
|
|
69
|
+
await deps.engine?.stop();
|
|
70
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev toolbar and dashboard setup helpers extracted from provider.
|
|
3
|
+
*/
|
|
4
|
+
import type DebugController from '../controller/debug_controller.js';
|
|
5
|
+
import type DashboardController from '../dashboard/dashboard_controller.js';
|
|
6
|
+
import type { DashboardStore } from '../dashboard/dashboard_store.js';
|
|
7
|
+
import type { DebugStore } from '../debug/debug_store.js';
|
|
8
|
+
import type { DevToolbarConfig } from '../debug/types.js';
|
|
9
|
+
import type { StatsEngine } from '../engine/stats_engine.js';
|
|
10
|
+
import type { LogStreamService } from '../log_stream/log_stream_service.js';
|
|
11
|
+
import type { ResolvedServerStatsConfig } from '../types.js';
|
|
12
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
13
|
+
export { initDashboardStore } from './dashboard_init.js';
|
|
14
|
+
export interface ToolbarCoreResult {
|
|
15
|
+
debugStore: DebugStore;
|
|
16
|
+
debugController: DebugController;
|
|
17
|
+
persistPath: string | null;
|
|
18
|
+
flushTimer: ReturnType<typeof setInterval> | null;
|
|
19
|
+
debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
|
|
20
|
+
transmitAvailable: boolean;
|
|
21
|
+
transmitChannels: string[];
|
|
22
|
+
dashboardStore: DashboardStore | null;
|
|
23
|
+
dashboardController: DashboardController | null;
|
|
24
|
+
dashboardLogStream: LogStreamService | null;
|
|
25
|
+
dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
|
|
26
|
+
emailBridgeRedis: unknown;
|
|
27
|
+
emitter: unknown;
|
|
28
|
+
}
|
|
29
|
+
interface ToolbarCoreOptions {
|
|
30
|
+
tc: DevToolbarConfig;
|
|
31
|
+
config: ResolvedServerStatsConfig;
|
|
32
|
+
app: ApplicationService;
|
|
33
|
+
resolve: (binding: string) => Promise<unknown>;
|
|
34
|
+
getDiagnostics: () => unknown;
|
|
35
|
+
}
|
|
36
|
+
/** Core dev toolbar setup: debug store, controllers, broadcasting, dashboard. */
|
|
37
|
+
export declare function setupDevToolbarCore(opts: ToolbarCoreOptions): Promise<ToolbarCoreResult | null>;
|
|
38
|
+
export interface ProviderFields {
|
|
39
|
+
debugStore: DebugStore | null;
|
|
40
|
+
debugController: DebugController | null;
|
|
41
|
+
persistPath: string | null;
|
|
42
|
+
flushTimer: ReturnType<typeof setInterval> | null;
|
|
43
|
+
debugBroadcastTimer: ReturnType<typeof setTimeout> | null;
|
|
44
|
+
transmitAvailable: boolean;
|
|
45
|
+
transmitChannels: string[];
|
|
46
|
+
dashboardStore: DashboardStore | null;
|
|
47
|
+
dashboardController: DashboardController | null;
|
|
48
|
+
dashboardLogStream: LogStreamService | null;
|
|
49
|
+
dashboardBroadcastTimer: ReturnType<typeof setInterval> | null;
|
|
50
|
+
emailBridgeRedis: unknown;
|
|
51
|
+
dashboardDepsAvailable: boolean;
|
|
52
|
+
engine: StatsEngine | null;
|
|
53
|
+
pinoHookActive: boolean;
|
|
54
|
+
app: ApplicationService;
|
|
55
|
+
}
|
|
56
|
+
/** Apply the toolbar core result back onto the provider instance. */
|
|
57
|
+
export declare function applyToolbarResult(result: ToolbarCoreResult, tc: DevToolbarConfig, provider: ProviderFields): void;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev toolbar and dashboard setup helpers extracted from provider.
|
|
3
|
+
*/
|
|
4
|
+
import { setTraceCollector } from '../middleware/request_tracking_middleware.js';
|
|
5
|
+
import { log } from '../utils/logger.js';
|
|
6
|
+
import { initDashboardStore } from './dashboard_init.js';
|
|
7
|
+
import { setupFullEmailBridge } from './email_bridge.js';
|
|
8
|
+
export { initDashboardStore } from './dashboard_init.js';
|
|
9
|
+
/** Core dev toolbar setup: debug store, controllers, broadcasting, dashboard. */
|
|
10
|
+
export async function setupDevToolbarCore(opts) {
|
|
11
|
+
const { tc, config, app, resolve, getDiagnostics } = opts;
|
|
12
|
+
const { DebugStore: DS } = await import('../debug/debug_store.js');
|
|
13
|
+
const debugStore = new DS(tc);
|
|
14
|
+
const container = app.container;
|
|
15
|
+
container.singleton('debug.store', () => debugStore);
|
|
16
|
+
const persistPath = await loadPersistedData(tc, app, debugStore);
|
|
17
|
+
const em = await resolve('emitter');
|
|
18
|
+
if (!em)
|
|
19
|
+
log.warn('emitter not available — query/event collection disabled');
|
|
20
|
+
await debugStore.start(em, await resolve('router'));
|
|
21
|
+
const emailBridgeRedis = await setupBridgeInternal(em, debugStore);
|
|
22
|
+
const debugController = await createDebugController(debugStore, config, getDiagnostics, app);
|
|
23
|
+
if (debugStore.traces)
|
|
24
|
+
setTraceCollector(debugStore.traces);
|
|
25
|
+
const flushTimer = persistPath ? createFlushTimer(debugStore, persistPath) : null;
|
|
26
|
+
const broadcast = await setupDebugBroadcastInternal(debugStore, resolve);
|
|
27
|
+
return {
|
|
28
|
+
debugStore,
|
|
29
|
+
debugController,
|
|
30
|
+
persistPath,
|
|
31
|
+
flushTimer,
|
|
32
|
+
debugBroadcastTimer: broadcast.timer,
|
|
33
|
+
transmitAvailable: broadcast.transmitAvailable,
|
|
34
|
+
transmitChannels: broadcast.channels,
|
|
35
|
+
dashboardStore: null,
|
|
36
|
+
dashboardController: null,
|
|
37
|
+
dashboardLogStream: null,
|
|
38
|
+
dashboardBroadcastTimer: null,
|
|
39
|
+
emailBridgeRedis,
|
|
40
|
+
emitter: em,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async function loadPersistedData(tc, app, debugStore) {
|
|
44
|
+
if (!tc.persistDebugData)
|
|
45
|
+
return null;
|
|
46
|
+
const path = typeof tc.persistDebugData === 'string'
|
|
47
|
+
? app.makePath(tc.persistDebugData)
|
|
48
|
+
: app.makePath('.adonisjs', 'server-stats', 'debug-data.json');
|
|
49
|
+
await debugStore.loadFromDisk(path);
|
|
50
|
+
return path;
|
|
51
|
+
}
|
|
52
|
+
async function createDebugController(debugStore, config, getDiagnostics, app) {
|
|
53
|
+
const DC = (await import('../controller/debug_controller.js')).default;
|
|
54
|
+
return new DC(debugStore, config, {
|
|
55
|
+
getEngine: () => null,
|
|
56
|
+
getDashboardStore: () => null,
|
|
57
|
+
getProviderDiagnostics: getDiagnostics,
|
|
58
|
+
getApp: () => app,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function createFlushTimer(debugStore, persistPath) {
|
|
62
|
+
return setInterval(async () => {
|
|
63
|
+
try {
|
|
64
|
+
await debugStore.saveToDisk(persistPath);
|
|
65
|
+
}
|
|
66
|
+
catch { }
|
|
67
|
+
}, 30_000);
|
|
68
|
+
}
|
|
69
|
+
async function setupBridgeInternal(emitter, debugStore) {
|
|
70
|
+
if (!emitter)
|
|
71
|
+
return null;
|
|
72
|
+
try {
|
|
73
|
+
const { appImport } = await import('../utils/app_import.js');
|
|
74
|
+
const mod = await appImport('@adonisjs/redis/services/main');
|
|
75
|
+
const redis = mod.default;
|
|
76
|
+
return await setupFullEmailBridge(emitter, redis, 'adonisjs-server-stats:emails', { debugEmails: debugStore.emails ?? null, dashboardStore: null });
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function setupDebugBroadcastInternal(debugStore, resolve) {
|
|
83
|
+
const t = await resolve('transmit');
|
|
84
|
+
if (!t)
|
|
85
|
+
return { timer: null, transmitAvailable: false, channels: [] };
|
|
86
|
+
const ch = 'server-stats/debug';
|
|
87
|
+
const pending = new Set();
|
|
88
|
+
let timer = null;
|
|
89
|
+
debugStore.onNewItem((type) => {
|
|
90
|
+
pending.add(type);
|
|
91
|
+
if (timer)
|
|
92
|
+
return;
|
|
93
|
+
timer = setTimeout(() => {
|
|
94
|
+
timer = null;
|
|
95
|
+
const ts = [...pending];
|
|
96
|
+
pending.clear();
|
|
97
|
+
try {
|
|
98
|
+
;
|
|
99
|
+
t.broadcast(ch, { types: ts });
|
|
100
|
+
}
|
|
101
|
+
catch { }
|
|
102
|
+
}, 200);
|
|
103
|
+
});
|
|
104
|
+
return { timer: null, transmitAvailable: true, channels: [ch] };
|
|
105
|
+
}
|
|
106
|
+
/** Apply the toolbar core result back onto the provider instance. */
|
|
107
|
+
export function applyToolbarResult(result, tc, provider) {
|
|
108
|
+
provider.debugStore = result.debugStore;
|
|
109
|
+
provider.debugController = result.debugController;
|
|
110
|
+
provider.persistPath = result.persistPath;
|
|
111
|
+
provider.flushTimer = result.flushTimer;
|
|
112
|
+
provider.debugBroadcastTimer = result.debugBroadcastTimer;
|
|
113
|
+
if (result.transmitAvailable)
|
|
114
|
+
provider.transmitAvailable = true;
|
|
115
|
+
for (const ch of result.transmitChannels) {
|
|
116
|
+
if (!provider.transmitChannels.includes(ch))
|
|
117
|
+
provider.transmitChannels.push(ch);
|
|
118
|
+
}
|
|
119
|
+
provider.emailBridgeRedis = result.emailBridgeRedis;
|
|
120
|
+
if (!tc.dashboard || !provider.dashboardDepsAvailable)
|
|
121
|
+
return;
|
|
122
|
+
setImmediate(() => {
|
|
123
|
+
initDashboardStore({
|
|
124
|
+
tc,
|
|
125
|
+
emitter: result.emitter,
|
|
126
|
+
app: provider.app,
|
|
127
|
+
debugStore: result.debugStore,
|
|
128
|
+
engine: provider.engine,
|
|
129
|
+
pinoHookActive: provider.pinoHookActive,
|
|
130
|
+
transmitChannels: provider.transmitChannels,
|
|
131
|
+
onResult: (r) => {
|
|
132
|
+
provider.dashboardStore = r.dashboardStore;
|
|
133
|
+
provider.dashboardController = r.dashboardController;
|
|
134
|
+
provider.dashboardLogStream = r.dashboardLogStream;
|
|
135
|
+
provider.dashboardBroadcastTimer = r.dashboardBroadcastTimer;
|
|
136
|
+
},
|
|
137
|
+
}).catch((e) => {
|
|
138
|
+
log.warn(`dashboard setup failed: ${e?.message ?? e}`);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApiController } from '../controller/api_controller.js';
|
|
2
|
+
import type DashboardController from '../dashboard/dashboard_controller.js';
|
|
3
|
+
import type { AdonisRouter } from './router_types.js';
|
|
4
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
5
|
+
interface DashboardRoutesOpts {
|
|
6
|
+
router: AdonisRouter;
|
|
7
|
+
dashboardPath: string;
|
|
8
|
+
getDashboardController: () => DashboardController | null;
|
|
9
|
+
getApiController: () => ApiController | null;
|
|
10
|
+
middleware: Array<(ctx: HttpContext, next: () => Promise<void>) => Promise<void>>;
|
|
11
|
+
}
|
|
12
|
+
/** Register dashboard routes. */
|
|
13
|
+
export declare function registerDashboardRoutes(opts: DashboardRoutesOpts): void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
function bindDash(getController, method) {
|
|
2
|
+
return async (ctx) => {
|
|
3
|
+
const controller = getController();
|
|
4
|
+
if (!controller)
|
|
5
|
+
return ctx.response.serviceUnavailable({ error: 'Dashboard is starting up, please retry' });
|
|
6
|
+
return controller[method].call(controller, ctx);
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function bindApi(getApi, fn) {
|
|
10
|
+
return async (ctx) => {
|
|
11
|
+
const api = getApi();
|
|
12
|
+
if (!api)
|
|
13
|
+
return ctx.response.serviceUnavailable({ error: 'Dashboard is starting up, please retry' });
|
|
14
|
+
return fn(api, ctx);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function registerQueryRoutes(router, getApi) {
|
|
18
|
+
router
|
|
19
|
+
.get('/api/queries', bindApi(getApi, async (api, ctx) => {
|
|
20
|
+
const qs = ctx.request.qs();
|
|
21
|
+
return ctx.response.json(await api.getQueries({
|
|
22
|
+
page: Number(qs.page) || 1,
|
|
23
|
+
perPage: Number(qs.perPage) || 25,
|
|
24
|
+
search: qs.search || undefined,
|
|
25
|
+
filters: {
|
|
26
|
+
durationMin: qs.duration_min ? Number(qs.duration_min) : undefined,
|
|
27
|
+
model: qs.model || undefined,
|
|
28
|
+
method: qs.method || undefined,
|
|
29
|
+
connection: qs.connection || undefined,
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
}))
|
|
33
|
+
.as('server-stats.queries');
|
|
34
|
+
}
|
|
35
|
+
function registerEventRoutes(router, getApi) {
|
|
36
|
+
router
|
|
37
|
+
.get('/api/events', bindApi(getApi, async (api, ctx) => {
|
|
38
|
+
const qs = ctx.request.qs();
|
|
39
|
+
return ctx.response.json(await api.getEvents({
|
|
40
|
+
page: Number(qs.page) || 1,
|
|
41
|
+
perPage: Number(qs.perPage) || 25,
|
|
42
|
+
search: qs.search || undefined,
|
|
43
|
+
filters: { eventName: qs.event_name || undefined },
|
|
44
|
+
}));
|
|
45
|
+
}))
|
|
46
|
+
.as('server-stats.events');
|
|
47
|
+
}
|
|
48
|
+
function registerRouteApiRoutes(router, getApi) {
|
|
49
|
+
router
|
|
50
|
+
.get('/api/routes', bindApi(getApi, (api, ctx) => ctx.response.json(api.getRoutes(ctx.request.qs().search || undefined))))
|
|
51
|
+
.as('server-stats.routes');
|
|
52
|
+
}
|
|
53
|
+
function registerLogRoutes(router, getApi) {
|
|
54
|
+
router
|
|
55
|
+
.get('/api/logs', bindApi(getApi, async (api, ctx) => {
|
|
56
|
+
const qs = ctx.request.qs();
|
|
57
|
+
return ctx.response.json(await api.getLogs({
|
|
58
|
+
page: Number(qs.page) || 1,
|
|
59
|
+
perPage: Number(qs.perPage) || 50,
|
|
60
|
+
search: qs.message || qs.search || undefined,
|
|
61
|
+
filters: {
|
|
62
|
+
level: qs.level || undefined,
|
|
63
|
+
requestId: qs.request_id || qs.requestId || undefined,
|
|
64
|
+
},
|
|
65
|
+
}));
|
|
66
|
+
}))
|
|
67
|
+
.as('server-stats.logs');
|
|
68
|
+
}
|
|
69
|
+
function registerEmailRoutes(router, getApi) {
|
|
70
|
+
router
|
|
71
|
+
.get('/api/emails', bindApi(getApi, async (api, ctx) => {
|
|
72
|
+
const qs = ctx.request.qs();
|
|
73
|
+
return ctx.response.json(await api.getEmails({
|
|
74
|
+
page: Number(qs.page) || 1,
|
|
75
|
+
perPage: Number(qs.perPage) || 25,
|
|
76
|
+
search: qs.search || undefined,
|
|
77
|
+
filters: {
|
|
78
|
+
from: qs.from || undefined,
|
|
79
|
+
to: qs.to || undefined,
|
|
80
|
+
subject: qs.subject || undefined,
|
|
81
|
+
status: qs.status || undefined,
|
|
82
|
+
mailer: qs.mailer || undefined,
|
|
83
|
+
},
|
|
84
|
+
}));
|
|
85
|
+
}))
|
|
86
|
+
.as('server-stats.emails');
|
|
87
|
+
router
|
|
88
|
+
.get('/api/emails/:id/preview', bindApi(getApi, async (api, ctx) => {
|
|
89
|
+
const html = await api.getEmailPreview(Number(ctx.params.id));
|
|
90
|
+
if (!html)
|
|
91
|
+
return ctx.response.notFound({ error: 'Email not found' });
|
|
92
|
+
return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
|
|
93
|
+
}))
|
|
94
|
+
.as('server-stats.emails.preview');
|
|
95
|
+
}
|
|
96
|
+
function registerTraceRoutes(router, getApi) {
|
|
97
|
+
router
|
|
98
|
+
.get('/api/traces', bindApi(getApi, async (api, ctx) => {
|
|
99
|
+
const qs = ctx.request.qs();
|
|
100
|
+
return ctx.response.json(await api.getTraces({
|
|
101
|
+
page: Number(qs.page) || 1,
|
|
102
|
+
perPage: Number(qs.perPage) || 25,
|
|
103
|
+
search: qs.search || undefined,
|
|
104
|
+
filters: {
|
|
105
|
+
method: qs.method ? qs.method.toUpperCase() : undefined,
|
|
106
|
+
url: qs.url || undefined,
|
|
107
|
+
statusMin: qs.status_min ? Number(qs.status_min) : undefined,
|
|
108
|
+
statusMax: qs.status_max ? Number(qs.status_max) : undefined,
|
|
109
|
+
},
|
|
110
|
+
}));
|
|
111
|
+
}))
|
|
112
|
+
.as('server-stats.traces');
|
|
113
|
+
router
|
|
114
|
+
.get('/api/traces/:id', bindApi(getApi, async (api, ctx) => {
|
|
115
|
+
const trace = await api.getTraceDetail(Number(ctx.params.id));
|
|
116
|
+
if (!trace)
|
|
117
|
+
return ctx.response.notFound({ error: 'Trace not found' });
|
|
118
|
+
return ctx.response.json(trace);
|
|
119
|
+
}))
|
|
120
|
+
.as('server-stats.traces.show');
|
|
121
|
+
}
|
|
122
|
+
function registerDashboardPageRoutes(router, getDashboardController) {
|
|
123
|
+
router.get('/', bindDash(getDashboardController, 'page')).as('server-stats.dashboard');
|
|
124
|
+
router
|
|
125
|
+
.get('/api/overview', bindDash(getDashboardController, 'overview'))
|
|
126
|
+
.as('server-stats.overview');
|
|
127
|
+
router
|
|
128
|
+
.get('/api/overview/chart', bindDash(getDashboardController, 'overviewChart'))
|
|
129
|
+
.as('server-stats.overview.chart');
|
|
130
|
+
router
|
|
131
|
+
.get('/api/requests', bindDash(getDashboardController, 'requests'))
|
|
132
|
+
.as('server-stats.requests');
|
|
133
|
+
router
|
|
134
|
+
.get('/api/requests/:id', bindDash(getDashboardController, 'requestDetail'))
|
|
135
|
+
.as('server-stats.requests.show');
|
|
136
|
+
}
|
|
137
|
+
function registerQueryDashboardRoutes(router, getDashboardController) {
|
|
138
|
+
router
|
|
139
|
+
.get('/api/queries/grouped', bindDash(getDashboardController, 'queriesGrouped'))
|
|
140
|
+
.as('server-stats.queries.grouped');
|
|
141
|
+
router
|
|
142
|
+
.get('/api/queries/:id/explain', bindDash(getDashboardController, 'queryExplain'))
|
|
143
|
+
.as('server-stats.queries.explain');
|
|
144
|
+
}
|
|
145
|
+
function registerCacheRoutes(router, getDashboardController) {
|
|
146
|
+
router.get('/api/cache', bindDash(getDashboardController, 'cacheStats')).as('server-stats.cache');
|
|
147
|
+
router
|
|
148
|
+
.get('/api/cache/:key', bindDash(getDashboardController, 'cacheKey'))
|
|
149
|
+
.as('server-stats.cache.show')
|
|
150
|
+
.where('key', /.*/);
|
|
151
|
+
router
|
|
152
|
+
.delete('/api/cache/:key', bindDash(getDashboardController, 'cacheKeyDelete'))
|
|
153
|
+
.as('server-stats.cache.delete')
|
|
154
|
+
.where('key', /.*/);
|
|
155
|
+
}
|
|
156
|
+
function registerJobRoutes(router, getDashboardController) {
|
|
157
|
+
router.get('/api/jobs', bindDash(getDashboardController, 'jobs')).as('server-stats.jobs');
|
|
158
|
+
router
|
|
159
|
+
.get('/api/jobs/:id', bindDash(getDashboardController, 'jobDetail'))
|
|
160
|
+
.as('server-stats.jobs.show');
|
|
161
|
+
router
|
|
162
|
+
.post('/api/jobs/:id/retry', bindDash(getDashboardController, 'jobRetry'))
|
|
163
|
+
.as('server-stats.jobs.retry');
|
|
164
|
+
}
|
|
165
|
+
function registerConfigAndFilterRoutes(router, getDashboardController) {
|
|
166
|
+
router.get('/api/config', bindDash(getDashboardController, 'config')).as('server-stats.config');
|
|
167
|
+
router
|
|
168
|
+
.get('/api/filters', bindDash(getDashboardController, 'savedFilters'))
|
|
169
|
+
.as('server-stats.filters');
|
|
170
|
+
router
|
|
171
|
+
.post('/api/filters', bindDash(getDashboardController, 'createSavedFilter'))
|
|
172
|
+
.as('server-stats.filters.create');
|
|
173
|
+
router
|
|
174
|
+
.delete('/api/filters/:id', bindDash(getDashboardController, 'deleteSavedFilter'))
|
|
175
|
+
.as('server-stats.filters.delete');
|
|
176
|
+
}
|
|
177
|
+
/** Register dashboard routes. */
|
|
178
|
+
export function registerDashboardRoutes(opts) {
|
|
179
|
+
const { router, dashboardPath, getDashboardController, getApiController, middleware } = opts;
|
|
180
|
+
const base = dashboardPath.replace(/\/+$/, '');
|
|
181
|
+
router
|
|
182
|
+
.group(() => {
|
|
183
|
+
registerDashboardPageRoutes(router, getDashboardController);
|
|
184
|
+
registerQueryRoutes(router, getApiController);
|
|
185
|
+
registerEventRoutes(router, getApiController);
|
|
186
|
+
registerRouteApiRoutes(router, getApiController);
|
|
187
|
+
registerLogRoutes(router, getApiController);
|
|
188
|
+
registerEmailRoutes(router, getApiController);
|
|
189
|
+
registerTraceRoutes(router, getApiController);
|
|
190
|
+
registerQueryDashboardRoutes(router, getDashboardController);
|
|
191
|
+
registerCacheRoutes(router, getDashboardController);
|
|
192
|
+
registerJobRoutes(router, getDashboardController);
|
|
193
|
+
registerConfigAndFilterRoutes(router, getDashboardController);
|
|
194
|
+
})
|
|
195
|
+
.prefix(base)
|
|
196
|
+
.use(middleware);
|
|
197
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ApiController } from '../controller/api_controller.js';
|
|
2
|
+
import type DebugController from '../controller/debug_controller.js';
|
|
3
|
+
import type { AdonisRouter } from './router_types.js';
|
|
4
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
5
|
+
interface DebugRoutesOpts {
|
|
6
|
+
router: AdonisRouter;
|
|
7
|
+
debugEndpoint: string;
|
|
8
|
+
getDebugController: () => DebugController | null;
|
|
9
|
+
getApiController: () => ApiController | null;
|
|
10
|
+
middleware: Array<(ctx: HttpContext, next: () => Promise<void>) => Promise<void>>;
|
|
11
|
+
}
|
|
12
|
+
/** Register debug panel API routes. */
|
|
13
|
+
export declare function registerDebugRoutes(opts: DebugRoutesOpts): void;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
function bindDebug(getController, method) {
|
|
2
|
+
return async (ctx) => {
|
|
3
|
+
const controller = getController();
|
|
4
|
+
if (!controller)
|
|
5
|
+
return ctx.response.serviceUnavailable({
|
|
6
|
+
error: 'Debug toolbar is starting up, please retry',
|
|
7
|
+
});
|
|
8
|
+
return controller[method].call(controller, ctx);
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function bindApi(getApi, fn) {
|
|
12
|
+
return async (ctx) => {
|
|
13
|
+
const api = getApi();
|
|
14
|
+
if (!api)
|
|
15
|
+
return ctx.response.serviceUnavailable({
|
|
16
|
+
error: 'Debug toolbar is starting up, please retry',
|
|
17
|
+
});
|
|
18
|
+
return fn(api, ctx);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function registerDebugConfigRoutes(router, getDebugController) {
|
|
22
|
+
router.get('/config', bindDebug(getDebugController, 'config')).as('server-stats.debug.config');
|
|
23
|
+
router
|
|
24
|
+
.get('/diagnostics', bindDebug(getDebugController, 'diagnostics'))
|
|
25
|
+
.as('server-stats.debug.diagnostics');
|
|
26
|
+
}
|
|
27
|
+
function registerDebugQueryAndEventRoutes(router, getApiController) {
|
|
28
|
+
router
|
|
29
|
+
.get('/queries', bindApi(getApiController, async (api, ctx) => {
|
|
30
|
+
const queries = await api.getQueries({ source: 'memory' });
|
|
31
|
+
return ctx.response.json({ queries: queries.data, summary: api.getQuerySummary() });
|
|
32
|
+
}))
|
|
33
|
+
.as('server-stats.debug.queries');
|
|
34
|
+
router
|
|
35
|
+
.get('/events', bindApi(getApiController, async (api, ctx) => {
|
|
36
|
+
const result = await api.getEvents({ source: 'memory' });
|
|
37
|
+
return ctx.response.json({ events: result.data, total: result.meta.total });
|
|
38
|
+
}))
|
|
39
|
+
.as('server-stats.debug.events');
|
|
40
|
+
router
|
|
41
|
+
.get('/routes', bindApi(getApiController, (api, ctx) => {
|
|
42
|
+
const result = api.getRoutes();
|
|
43
|
+
return ctx.response.json({ routes: result.data, total: result.meta.total });
|
|
44
|
+
}))
|
|
45
|
+
.as('server-stats.debug.routes');
|
|
46
|
+
}
|
|
47
|
+
function registerDebugLogRoutes(router, getApiController) {
|
|
48
|
+
router
|
|
49
|
+
.get('/logs', bindApi(getApiController, async (api, ctx) => {
|
|
50
|
+
const result = await api.getLogs({ source: 'auto', perPage: 200 });
|
|
51
|
+
return ctx.response.json(result.data);
|
|
52
|
+
}))
|
|
53
|
+
.as('server-stats.debug.logs');
|
|
54
|
+
}
|
|
55
|
+
function registerDebugEmailRoutes(router, getApiController) {
|
|
56
|
+
router
|
|
57
|
+
.get('/emails', bindApi(getApiController, async (api, ctx) => {
|
|
58
|
+
const result = await api.getEmails({});
|
|
59
|
+
return ctx.response.json({ emails: result.data, total: result.meta.total });
|
|
60
|
+
}))
|
|
61
|
+
.as('server-stats.debug.emails');
|
|
62
|
+
router
|
|
63
|
+
.get('/emails/:id/preview', bindApi(getApiController, async (api, ctx) => {
|
|
64
|
+
const html = await api.getEmailPreview(Number(ctx.params.id));
|
|
65
|
+
if (!html)
|
|
66
|
+
return ctx.response.notFound({ error: 'Email not found' });
|
|
67
|
+
return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
|
|
68
|
+
}))
|
|
69
|
+
.as('server-stats.debug.emailPreview');
|
|
70
|
+
}
|
|
71
|
+
function registerDebugTraceRoutes(router, getApiController) {
|
|
72
|
+
router
|
|
73
|
+
.get('/traces', bindApi(getApiController, async (api, ctx) => {
|
|
74
|
+
const result = await api.getTraces({ source: 'memory' });
|
|
75
|
+
return ctx.response.json({ traces: result.data, total: result.meta.total });
|
|
76
|
+
}))
|
|
77
|
+
.as('server-stats.debug.traces');
|
|
78
|
+
router
|
|
79
|
+
.get('/traces/:id', bindApi(getApiController, async (api, ctx) => {
|
|
80
|
+
const trace = await api.getTraceDetail(Number(ctx.params.id), 'memory');
|
|
81
|
+
if (!trace)
|
|
82
|
+
return ctx.response.notFound({ error: 'Trace not found' });
|
|
83
|
+
return ctx.response.json(trace);
|
|
84
|
+
}))
|
|
85
|
+
.as('server-stats.debug.traceDetail');
|
|
86
|
+
}
|
|
87
|
+
/** Register debug panel API routes. */
|
|
88
|
+
export function registerDebugRoutes(opts) {
|
|
89
|
+
const { router, debugEndpoint, getDebugController, getApiController, middleware } = opts;
|
|
90
|
+
const base = debugEndpoint.replace(/\/+$/, '');
|
|
91
|
+
router
|
|
92
|
+
.group(() => {
|
|
93
|
+
registerDebugConfigRoutes(router, getDebugController);
|
|
94
|
+
registerDebugQueryAndEventRoutes(router, getApiController);
|
|
95
|
+
registerDebugLogRoutes(router, getApiController);
|
|
96
|
+
registerDebugEmailRoutes(router, getApiController);
|
|
97
|
+
registerDebugTraceRoutes(router, getApiController);
|
|
98
|
+
})
|
|
99
|
+
.prefix(base)
|
|
100
|
+
.use(middleware);
|
|
101
|
+
}
|