Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import emptyStateImg from 'sentry-images/spot/performance-waiting-for-span.svg';

import {LinkButton} from '@sentry/scraps/button';
import {CodeBlock} from '@sentry/scraps/code';
import {Image} from '@sentry/scraps/image';
import {Flex, Stack} from '@sentry/scraps/layout';
import {Heading, Text} from '@sentry/scraps/text';

import {Panel} from 'sentry/components/panels/panel';
import {t} from 'sentry/locale';

const DOCS_URL =
'https://docs.sentry.io/platforms/javascript/configuration/integrations/bfcache/';

const CODE_SNIPPET = `import * as Sentry from '@sentry/browser';

Sentry.init({
dsn: '__YOUR_DSN__',
integrations: [Sentry.bfcacheIntegration()],
});`;

export function BfcacheMetricsOnboarding() {
return (
<Panel>
<Flex justify="center">
<Flex padding="xl" align="center" wrap="wrap-reverse" gap="3xl" maxWidth="1000px">
<Stack gap="xl" flex="5" align="start">
<Heading as="h3" size="xl">
{t('Monitor Back/Forward Cache')}
</Heading>

<Text as="p" size="md">
{t(
'Track how often the browser back/forward cache (bfcache) restores your pages, why restores are blocked, and how long miss reloads take. Enable the bfcache metrics integration to start collecting data.'
)}
</Text>

<CodeBlock language="javascript">{CODE_SNIPPET}</CodeBlock>

<LinkButton variant="primary" external href={DOCS_URL}>
{t('Read the Docs')}
</LinkButton>
</Stack>

<Flex flex="3" justify="center">
<Image src={emptyStateImg} alt="" width="100%" />
</Flex>
</Flex>
</Flex>
</Panel>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {NodeRuntimeMetricsOnboarding} from 'sentry/views/insights/pages/nodeRunt
import {ModuleName} from 'sentry/views/insights/types';
import {LegacyOnboarding} from 'sentry/views/performance/onboarding';

import {BfcacheMetricsOnboarding} from './bfcacheMetricsOnboarding';
import {GenericOnboarding} from './genericOnboarding';

interface PrebuiltDashboardOnboardingGateProps {
Expand Down Expand Up @@ -89,6 +90,10 @@ export function PrebuiltDashboardOnboardingGate({
return <NodeRuntimeMetricsOnboarding />;
}

if (onboarding.componentId === 'bfcache-metrics') {
return <BfcacheMetricsOnboarding />;
}

return <MCPOnboarding />;
}

Expand Down
9 changes: 8 additions & 1 deletion static/app/views/dashboards/utils/prebuiltConfigs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {MCP_PROMPTS_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuil
import {MCP_RESOURCES_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/ai/mcpResources';
import {MCP_TOOLS_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/ai/mcpTools';
import {BACKEND_OVERVIEW_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/backendOverview/backendOverview';
import {BFCACHE_METRICS_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/bfcache';
import {CACHES_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/caches/caches';
import {FRONTEND_ASSETS_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/frontendAssets/frontendAssets';
import {FRONTEND_ASSETS_DETAILS_PREBUILT_CONFIG} from 'sentry/views/dashboards/utils/prebuiltConfigs/frontendAssets/frontendAssetsDetails';
Expand Down Expand Up @@ -65,6 +66,7 @@ export enum PrebuiltDashboardId {
BACKEND_QUEUE_SUMMARY = 27,
BACKEND_CACHES = 28,
NODE_RUNTIME_METRICS = 29,
BFCACHE_METRICS = 30,
}

/** Boolean flags on Project that indicate whether telemetry data has been received. */
Expand All @@ -81,7 +83,11 @@ type OnboardingConfig =
requiredProjectFlags?: ProjectTelemetryFlag[];
}
| {
componentId: 'agent-monitoring' | 'mcp' | 'node-runtime-metrics';
componentId:
| 'agent-monitoring'
| 'mcp'
| 'node-runtime-metrics'
| 'bfcache-metrics';
requiredProjectFlags: ProjectTelemetryFlag[];
// Custom onboarding component (AI Agents, MCP, Node.js Runtime Metrics)
type: 'custom';
Expand Down Expand Up @@ -148,4 +154,5 @@ export const PREBUILT_DASHBOARDS: Record<PrebuiltDashboardId, PrebuiltDashboard>
[PrebuiltDashboardId.BACKEND_QUEUE_SUMMARY]: QUEUE_DETAILS_PREBUILT_CONFIG,
[PrebuiltDashboardId.BACKEND_CACHES]: CACHES_PREBUILT_CONFIG,
[PrebuiltDashboardId.NODE_RUNTIME_METRICS]: NODE_RUNTIME_METRICS_PREBUILT_CONFIG,
[PrebuiltDashboardId.BFCACHE_METRICS]: BFCACHE_METRICS_PREBUILT_CONFIG,
};
178 changes: 178 additions & 0 deletions static/app/views/dashboards/utils/prebuiltConfigs/bfcache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import {t} from 'sentry/locale';
import {DisplayType, WidgetType} from 'sentry/views/dashboards/types';
import type {PrebuiltDashboard} from 'sentry/views/dashboards/utils/prebuiltConfigs';
import {traceMetricField} from 'sentry/views/dashboards/utils/prebuiltConfigs/utils/traceMetricField';

const INTERVAL = '5m';

// Emitted by the browser SDK's `bfcacheIntegration`.
const NAVIGATION = traceMetricField('sum', 'browser.bfcache.navigation', 'counter', null);
const NOT_RESTORED = traceMetricField(
'sum',
'browser.bfcache.not_restored',
'counter',
null
);
const RELOAD_P75 = 'p75(value,browser.bfcache.reload.duration,distribution,millisecond)';
const RELOAD_P95 = 'p95(value,browser.bfcache.reload.duration,distribution,millisecond)';

export const BFCACHE_METRICS_PREBUILT_CONFIG: PrebuiltDashboard = {
dateCreated: '',
filters: {},
projects: [],
title: 'BFCache Metrics',
widgets: [
{
id: 'bfcache-hits-vs-misses',
title: t('BFCache Hits vs Misses'),
displayType: DisplayType.AREA,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['browser.bfcache.outcome', NAVIGATION],
aggregates: [NAVIGATION],
columns: ['browser.bfcache.outcome'],
orderby: `-${NAVIGATION}`,
},
],
layout: {x: 0, y: 0, w: 3, h: 2, minH: 2},
},
{
id: 'bfcache-outcome-trend',
title: t('BFCache Outcome Trend'),
displayType: DisplayType.LINE,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['browser.bfcache.outcome', NAVIGATION],
aggregates: [NAVIGATION],
columns: ['browser.bfcache.outcome'],
orderby: `-${NAVIGATION}`,
},
],
layout: {x: 3, y: 0, w: 3, h: 2, minH: 2},
},
{
id: 'bfcache-miss-reload-duration',
title: t('BFCache Miss Reload Duration'),
displayType: DisplayType.LINE,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['sentry.transaction', RELOAD_P75, RELOAD_P95],
aggregates: [RELOAD_P75, RELOAD_P95],
columns: ['sentry.transaction'],
orderby: `-${RELOAD_P75}`,
},
],
layout: {x: 0, y: 2, w: 6, h: 2, minH: 2},
},
{
id: 'bfcache-misses-by-route',
title: t('BFCache Misses by Route'),
displayType: DisplayType.CATEGORICAL_BAR,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: 'browser.bfcache.outcome:miss',
fields: ['sentry.transaction', NAVIGATION],
aggregates: [NAVIGATION],
columns: ['sentry.transaction'],
orderby: `-${NAVIGATION}`,
},
],
layout: {x: 0, y: 4, w: 3, h: 3, minH: 2},
},
{
id: 'bfcache-not-restored-reasons',
title: t('Top BFCache Not-Restored Reasons'),
displayType: DisplayType.CATEGORICAL_BAR,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['browser.bfcache.reason', NOT_RESTORED],
aggregates: [NOT_RESTORED],
columns: ['browser.bfcache.reason'],
orderby: `-${NOT_RESTORED}`,
},
],
layout: {x: 3, y: 4, w: 3, h: 3, minH: 2},
},
{
id: 'bfcache-reasons-by-route',
title: t('BFCache Reasons by Route'),
displayType: DisplayType.CATEGORICAL_BAR,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['sentry.transaction', 'browser.bfcache.reason', NOT_RESTORED],
aggregates: [NOT_RESTORED],
columns: ['sentry.transaction', 'browser.bfcache.reason'],
orderby: `-${NOT_RESTORED}`,
},
],
layout: {x: 0, y: 7, w: 3, h: 3, minH: 2},
},
{
id: 'bfcache-outcome-by-browser',
title: t('BFCache Outcome by Browser'),
displayType: DisplayType.CATEGORICAL_BAR,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['browser.name', 'browser.bfcache.outcome', NAVIGATION],
aggregates: [NAVIGATION],
columns: ['browser.name', 'browser.bfcache.outcome'],
orderby: `-${NAVIGATION}`,
},
],
layout: {x: 3, y: 7, w: 3, h: 3, minH: 2},
},
{
id: 'bfcache-blockers-by-frame',
title: t('BFCache Blockers by Frame'),
displayType: DisplayType.CATEGORICAL_BAR,
widgetType: WidgetType.TRACEMETRICS,
interval: INTERVAL,
queries: [
{
name: '',
conditions: '',
fields: ['browser.bfcache.frame', NOT_RESTORED],
aggregates: [NOT_RESTORED],
columns: ['browser.bfcache.frame'],
orderby: `-${NOT_RESTORED}`,
},
],
layout: {x: 0, y: 10, w: 3, h: 2, minH: 2},
},
],
onboarding: {
type: 'custom',
componentId: 'bfcache-metrics',
// bfcache is browser-only, so gate on a frontend-data proxy. There is no
// bfcache-specific project flag; the data only exists once the SDK's
// bfcacheIntegration is enabled.
requiredProjectFlags: ['hasInsightsVitals'],
},
};
Loading