mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 19:52:38 +08:00
Instrumentation: Measure app init load times (#67900)
* adding load time metrics for app init. * chore: add the `metrics.ts` to the CODEOWNERS * moved file according to PR feedback. --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
This commit is contained in:
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -453,6 +453,7 @@ lerna.json @grafana/frontend-ops
|
||||
/public/app/angular/ @torkelo
|
||||
/public/app/app.ts @grafana/frontend-ops
|
||||
/public/app/dev.ts @grafana/frontend-ops
|
||||
/public/app/core/utils/metrics.ts @grafana/plugins-platform-frontend
|
||||
/public/app/index.ts @grafana/frontend-ops
|
||||
/public/app/AppWrapper.tsx @grafana/frontend-ops
|
||||
/public/app/partials/ @grafana/grafana-frontend-platform
|
||||
|
@ -67,6 +67,7 @@ import { GAEchoBackend } from './core/services/echo/backends/analytics/GABackend
|
||||
import { RudderstackBackend } from './core/services/echo/backends/analytics/RudderstackBackend';
|
||||
import { GrafanaJavascriptAgentBackend } from './core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend';
|
||||
import { KeybindingSrv } from './core/services/keybindingSrv';
|
||||
import { startMeasure, stopMeasure } from './core/utils/metrics';
|
||||
import { initDevFeatures } from './dev';
|
||||
import { getTimeSrv } from './features/dashboard/services/TimeSrv';
|
||||
import { initGrafanaLive } from './features/live';
|
||||
@ -119,6 +120,8 @@ export class GrafanaApp {
|
||||
|
||||
setBackendSrv(backendSrv);
|
||||
initEchoSrv();
|
||||
// This needs to be done after the `initEchoSrv` since it is being used under the hood.
|
||||
startMeasure('frontend_app_init');
|
||||
addClassIfNoOverlayScrollbar();
|
||||
setLocale(config.bootData.user.locale);
|
||||
setWeekStart(config.bootData.user.weekStart);
|
||||
@ -219,6 +222,8 @@ export class GrafanaApp {
|
||||
} catch (error) {
|
||||
console.error('Failed to start Grafana', error);
|
||||
window.__grafana_load_failed();
|
||||
} finally {
|
||||
stopMeasure('frontend_app_init');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
public/app/core/utils/metrics.ts
Normal file
35
public/app/core/utils/metrics.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { reportPerformance } from '../services/echo/EchoSrv';
|
||||
|
||||
export function startMeasure(eventName: string) {
|
||||
if (!performance) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
performance.mark(`${eventName}_started`);
|
||||
} catch (error) {
|
||||
console.error(`[Metrics] Failed to startMeasure ${eventName}`, error);
|
||||
}
|
||||
}
|
||||
|
||||
export function stopMeasure(eventName: string) {
|
||||
if (!performance) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const started = `${eventName}_started`;
|
||||
const completed = `${eventName}_completed`;
|
||||
const measured = `${eventName}_measured`;
|
||||
|
||||
performance.mark(completed);
|
||||
const measure = performance.measure(measured, started, completed);
|
||||
reportPerformance(`${eventName}_ms`, measure.duration);
|
||||
|
||||
performance.clearMarks(started);
|
||||
performance.clearMarks(completed);
|
||||
performance.clearMeasures(measured);
|
||||
} catch (error) {
|
||||
console.error(`[Metrics] Failed to stopMeasure ${eventName}`, error);
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import type { PluginExtensionLinkConfig } from '@grafana/data';
|
||||
import type { AppPluginConfig } from '@grafana/runtime';
|
||||
import { startMeasure, stopMeasure } from 'app/core/utils/metrics';
|
||||
|
||||
import * as pluginLoader from './plugin_loader';
|
||||
|
||||
@ -10,18 +11,24 @@ export type PluginPreloadResult = {
|
||||
};
|
||||
|
||||
export async function preloadPlugins(apps: Record<string, AppPluginConfig> = {}): Promise<PluginPreloadResult[]> {
|
||||
startMeasure('frontend_plugins_preload');
|
||||
const pluginsToPreload = Object.values(apps).filter((app) => app.preload);
|
||||
return Promise.all(pluginsToPreload.map(preload));
|
||||
const result = await Promise.all(pluginsToPreload.map(preload));
|
||||
stopMeasure('frontend_plugins_preload');
|
||||
return result;
|
||||
}
|
||||
|
||||
async function preload(config: AppPluginConfig): Promise<PluginPreloadResult> {
|
||||
const { path, version, id: pluginId } = config;
|
||||
try {
|
||||
startMeasure(`frontend_plugin_preload_${pluginId}`);
|
||||
const { plugin } = await pluginLoader.importPluginModule(path, version);
|
||||
const { extensionConfigs = [] } = plugin;
|
||||
return { pluginId, extensionConfigs };
|
||||
} catch (error) {
|
||||
console.error(`[Plugins] Failed to preload plugin: ${path} (version: ${version})`, error);
|
||||
return { pluginId, extensionConfigs: [], error };
|
||||
} finally {
|
||||
stopMeasure(`frontend_plugin_preload_${pluginId}`);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user