mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 11:11:47 +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/angular/ @torkelo
|
||||||
/public/app/app.ts @grafana/frontend-ops
|
/public/app/app.ts @grafana/frontend-ops
|
||||||
/public/app/dev.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/index.ts @grafana/frontend-ops
|
||||||
/public/app/AppWrapper.tsx @grafana/frontend-ops
|
/public/app/AppWrapper.tsx @grafana/frontend-ops
|
||||||
/public/app/partials/ @grafana/grafana-frontend-platform
|
/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 { RudderstackBackend } from './core/services/echo/backends/analytics/RudderstackBackend';
|
||||||
import { GrafanaJavascriptAgentBackend } from './core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend';
|
import { GrafanaJavascriptAgentBackend } from './core/services/echo/backends/grafana-javascript-agent/GrafanaJavascriptAgentBackend';
|
||||||
import { KeybindingSrv } from './core/services/keybindingSrv';
|
import { KeybindingSrv } from './core/services/keybindingSrv';
|
||||||
|
import { startMeasure, stopMeasure } from './core/utils/metrics';
|
||||||
import { initDevFeatures } from './dev';
|
import { initDevFeatures } from './dev';
|
||||||
import { getTimeSrv } from './features/dashboard/services/TimeSrv';
|
import { getTimeSrv } from './features/dashboard/services/TimeSrv';
|
||||||
import { initGrafanaLive } from './features/live';
|
import { initGrafanaLive } from './features/live';
|
||||||
@ -119,6 +120,8 @@ export class GrafanaApp {
|
|||||||
|
|
||||||
setBackendSrv(backendSrv);
|
setBackendSrv(backendSrv);
|
||||||
initEchoSrv();
|
initEchoSrv();
|
||||||
|
// This needs to be done after the `initEchoSrv` since it is being used under the hood.
|
||||||
|
startMeasure('frontend_app_init');
|
||||||
addClassIfNoOverlayScrollbar();
|
addClassIfNoOverlayScrollbar();
|
||||||
setLocale(config.bootData.user.locale);
|
setLocale(config.bootData.user.locale);
|
||||||
setWeekStart(config.bootData.user.weekStart);
|
setWeekStart(config.bootData.user.weekStart);
|
||||||
@ -219,6 +222,8 @@ export class GrafanaApp {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to start Grafana', error);
|
console.error('Failed to start Grafana', error);
|
||||||
window.__grafana_load_failed();
|
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 { PluginExtensionLinkConfig } from '@grafana/data';
|
||||||
import type { AppPluginConfig } from '@grafana/runtime';
|
import type { AppPluginConfig } from '@grafana/runtime';
|
||||||
|
import { startMeasure, stopMeasure } from 'app/core/utils/metrics';
|
||||||
|
|
||||||
import * as pluginLoader from './plugin_loader';
|
import * as pluginLoader from './plugin_loader';
|
||||||
|
|
||||||
@ -10,18 +11,24 @@ export type PluginPreloadResult = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function preloadPlugins(apps: Record<string, AppPluginConfig> = {}): Promise<PluginPreloadResult[]> {
|
export async function preloadPlugins(apps: Record<string, AppPluginConfig> = {}): Promise<PluginPreloadResult[]> {
|
||||||
|
startMeasure('frontend_plugins_preload');
|
||||||
const pluginsToPreload = Object.values(apps).filter((app) => app.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> {
|
async function preload(config: AppPluginConfig): Promise<PluginPreloadResult> {
|
||||||
const { path, version, id: pluginId } = config;
|
const { path, version, id: pluginId } = config;
|
||||||
try {
|
try {
|
||||||
|
startMeasure(`frontend_plugin_preload_${pluginId}`);
|
||||||
const { plugin } = await pluginLoader.importPluginModule(path, version);
|
const { plugin } = await pluginLoader.importPluginModule(path, version);
|
||||||
const { extensionConfigs = [] } = plugin;
|
const { extensionConfigs = [] } = plugin;
|
||||||
return { pluginId, extensionConfigs };
|
return { pluginId, extensionConfigs };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`[Plugins] Failed to preload plugin: ${path} (version: ${version})`, error);
|
console.error(`[Plugins] Failed to preload plugin: ${path} (version: ${version})`, error);
|
||||||
return { pluginId, extensionConfigs: [], error };
|
return { pluginId, extensionConfigs: [], error };
|
||||||
|
} finally {
|
||||||
|
stopMeasure(`frontend_plugin_preload_${pluginId}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user