diff --git a/public/app/core/utils/metrics.ts b/public/app/core/utils/metrics.ts index 97551a721cc..e244851aa74 100644 --- a/public/app/core/utils/metrics.ts +++ b/public/app/core/utils/metrics.ts @@ -1,7 +1,7 @@ import { reportPerformance } from '../services/echo/EchoSrv'; export function startMeasure(eventName: string) { - if (!performance) { + if (!performance || !performance.mark) { return; } @@ -13,7 +13,7 @@ export function startMeasure(eventName: string) { } export function stopMeasure(eventName: string) { - if (!performance) { + if (!performance || !performance.mark) { return; } @@ -29,7 +29,9 @@ export function stopMeasure(eventName: string) { performance.clearMarks(started); performance.clearMarks(completed); performance.clearMeasures(measured); + return measure; } catch (error) { console.error(`[Metrics] Failed to stopMeasure ${eventName}`, error); + return; } } diff --git a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts index c9132a9415e..66c00150b0e 100644 --- a/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts +++ b/public/app/features/dashboard-scene/pages/DashboardScenePageStateManager.ts @@ -2,12 +2,14 @@ import { locationUtil } from '@grafana/data'; import { config, getBackendSrv, isFetchError, locationService } from '@grafana/runtime'; import { StateManagerBase } from 'app/core/services/StateManagerBase'; import { default as localStorageStore } from 'app/core/store'; +import { startMeasure, stopMeasure } from 'app/core/utils/metrics'; import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv'; import { getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { DASHBOARD_FROM_LS_KEY, removeDashboardToFetchFromLocalStorage, } from 'app/features/dashboard/state/initDashboard'; +import { trackDashboardSceneLoaded } from 'app/features/dashboard/utils/tracking'; import { DashboardDTO, DashboardRoutes } from 'app/types'; import { PanelEditor } from '../panel-edit/PanelEditor'; @@ -26,6 +28,8 @@ export interface DashboardScenePageState { export const DASHBOARD_CACHE_TTL = 500; +const LOAD_SCENE_MEASUREMENT = 'loadDashboardScene'; + /** Only used by cache in loading home in DashboardPageProxy and initDashboard (Old arch), can remove this after old dashboard arch is gone */ export const HOME_DASHBOARD_CACHE_KEY = '__grafana_home_uid__'; @@ -167,6 +171,7 @@ export class DashboardScenePageStateManager extends StateManagerBase { - const unsetDashboardInteractionsScenesContext = DashboardInteractions.setScenesContext(); - - trackDashboardLoaded(model, model.version); - - return () => { - unsetDashboardInteractionsScenesContext(); - }; - }; -} - function registerPanelInteractionsReporter(scene: DashboardScene) { // Subscriptions set with subscribeToEvent are automatically unsubscribed when the scene deactivated scene.subscribeToEvent(UserActionEvent, (e) => { diff --git a/public/app/features/dashboard/state/initDashboard.ts b/public/app/features/dashboard/state/initDashboard.ts index af312e80738..4d77b54728d 100644 --- a/public/app/features/dashboard/state/initDashboard.ts +++ b/public/app/features/dashboard/state/initDashboard.ts @@ -6,6 +6,7 @@ import { createErrorNotification } from 'app/core/copy/appNotification'; import { backendSrv } from 'app/core/services/backend_srv'; import { KeybindingSrv } from 'app/core/services/keybindingSrv'; import store from 'app/core/store'; +import { startMeasure, stopMeasure } from 'app/core/utils/metrics'; import { dashboardLoaderSrv } from 'app/features/dashboard/services/DashboardLoaderSrv'; import { DashboardSrv, getDashboardSrv } from 'app/features/dashboard/services/DashboardSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; @@ -30,6 +31,8 @@ import { PanelModel } from './PanelModel'; import { emitDashboardViewEvent } from './analyticsProcessor'; import { dashboardInitCompleted, dashboardInitFailed, dashboardInitFetching, dashboardInitServices } from './reducers'; +const INIT_DASHBOARD_MEASUREMENT = 'initDashboard'; + export interface InitDashboardArgs { urlUid?: string; urlSlug?: string; @@ -174,7 +177,7 @@ const getQueriesByDatasource = ( */ export function initDashboard(args: InitDashboardArgs): ThunkResult { return async (dispatch, getState) => { - const initStart = performance.now(); + startMeasure(INIT_DASHBOARD_MEASUREMENT); // set fetching state dispatch(dashboardInitFetching()); @@ -287,8 +290,8 @@ export function initDashboard(args: InitDashboardArgs): ThunkResult { }) ); - const duration = performance.now() - initStart; - trackDashboardLoaded(dashboard, duration, versionBeforeMigration); + const measure = stopMeasure(INIT_DASHBOARD_MEASUREMENT); + trackDashboardLoaded(dashboard, measure?.duration, versionBeforeMigration); // yay we are done dispatch(dashboardInitCompleted(dashboard)); diff --git a/public/app/features/dashboard/utils/tracking.test.ts b/public/app/features/dashboard/utils/tracking.test.ts index 79fc467fba9..9adb9e6d39b 100644 --- a/public/app/features/dashboard/utils/tracking.test.ts +++ b/public/app/features/dashboard/utils/tracking.test.ts @@ -37,6 +37,7 @@ describe('trackDashboardLoaded', () => { expect(reportInteractionSpy).toHaveBeenCalledWith('dashboards_init_dashboard_completed', { duration: 200, + isScene: false, uid: 'dashboard-123', title: 'Test Dashboard', schemaVersion: model.schemaVersion, // This value is based on public/app/features/dashboard/state/DashboardMigrator.ts#L81 diff --git a/public/app/features/dashboard/utils/tracking.ts b/public/app/features/dashboard/utils/tracking.ts index 5031a396072..a70c8b84ab4 100644 --- a/public/app/features/dashboard/utils/tracking.ts +++ b/public/app/features/dashboard/utils/tracking.ts @@ -1,23 +1,14 @@ +import { Panel, VariableModel } from '@grafana/schema/dist/esm/index'; +import { DashboardScene } from 'app/features/dashboard-scene/scene/DashboardScene'; import { DashboardInteractions } from 'app/features/dashboard-scene/utils/interactions'; -import { DashboardModel } from '../state'; +import { DashboardModel, PanelModel } from '../state'; -export function trackDashboardLoaded(dashboard: DashboardModel, duration: number, versionBeforeMigration?: number) { +export function trackDashboardLoaded(dashboard: DashboardModel, duration?: number, versionBeforeMigration?: number) { // Count the different types of variables - const variables = dashboard.templating.list - .map((v) => v.type) - .reduce((r: Record, k) => { - r[variableName(k)] = 1 + r[variableName(k)] || 1; - return r; - }, {}); - + const variables = getVariables(dashboard.templating.list); // Count the different types of panels - const panels = dashboard.panels - .map((p) => p.type) - .reduce((r: Record, p) => { - r[panelName(p)] = 1 + r[panelName(p)] || 1; - return r; - }, {}); + const panels = getPanelCounts(dashboard.panels); DashboardInteractions.dashboardInitialized({ uid: dashboard.uid, @@ -31,8 +22,49 @@ export function trackDashboardLoaded(dashboard: DashboardModel, duration: number settings_nowdelay: dashboard.timepicker.nowDelay, settings_livenow: !!dashboard.liveNow, duration, + isScene: false, }); } +export function trackDashboardSceneLoaded(dashboard: DashboardScene, duration?: number) { + const initialSaveModel = dashboard.getInitialSaveModel(); + if (initialSaveModel) { + const panels = getPanelCounts(initialSaveModel.panels || []); + const variables = getVariables(initialSaveModel.templating?.list || []); + DashboardInteractions.dashboardInitialized({ + uid: initialSaveModel.uid, + title: initialSaveModel.title, + theme: undefined, + schemaVersion: initialSaveModel.schemaVersion, + version_before_migration: initialSaveModel.version, + panels_count: initialSaveModel.panels?.length || 0, + ...panels, + ...variables, + settings_nowdelay: undefined, + settings_livenow: !!initialSaveModel.liveNow, + duration, + isScene: true, + }); + } +} + +function getPanelCounts(panels: Panel[] | PanelModel[]) { + return panels + .map((p) => p.type) + .reduce((r: Record, p) => { + r[panelName(p)] = 1 + r[panelName(p)] || 1; + return r; + }, {}); +} + +function getVariables(variableList: VariableModel[]) { + return variableList + .map((v) => v.type) + .reduce((r: Record, k) => { + r[variableName(k)] = 1 + r[variableName(k)] || 1; + return r; + }, {}); +} + const variableName = (type: string) => `variable_type_${type}_count`; const panelName = (type: string) => `panel_type_${type}_count`;