Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(profiling) hint to opening aggregate flamegraph #80698

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion static/app/components/profiling/billing/alerts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const ProfilingAM1OrMMXUpgrade = HookOrDefault({
<h3>{t('Function level insights')}</h3>
<p>
{t(
'Discover slow-to-execute or resource intensive functions within your application'
'Discover slow-to-execute or resource intensive functions within your application.'
)}
</p>
</Fragment>
Expand Down
6 changes: 6 additions & 0 deletions static/app/utils/analytics/profilingAnalyticsEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export type ProfilingEventParameters = {
source: ProfilingEventSource;
};
'profiling_views.landing': {};
'profiling_views.missing_transactions_banner.flamegraph_clicked': {};
'profiling_views.missing_transactions_banner.viewed': {};
'profiling_views.onboarding': {};
'profiling_views.onboarding_action': {
action: 'done' | 'dismissed';
Expand All @@ -63,6 +65,10 @@ export const profilingEventMap: Record<EventKey, string> = {
'profiling_views.onboarding_action': 'Profiling Actions: Onboarding Action',
'profiling_views.give_feedback_action': 'Profiling Actions: Feedback Action',
'profiling_views.visit_discord_channel': 'Profiling Actions: Visit Discord Channel',
'profiling_views.missing_transactions_banner.viewed':
'Profiling Views: Missing Transactions Banner Viewed',
'profiling_views.missing_transactions_banner.flamegraph_clicked':
'Profiling Views: Missing Transactions Banner Flamegraph Clicked',
'profiling_ui_events.transaction_hovercard_view':
'Profiling Actions: Viewed Transaction Hovercard',
};
102 changes: 91 additions & 11 deletions static/app/views/profiling/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {Button, LinkButton} from 'sentry/components/button';
import SearchBar from 'sentry/components/events/searchBar';
import FeedbackWidgetButton from 'sentry/components/feedback/widget/feedbackWidgetButton';
import * as Layout from 'sentry/components/layouts/thirds';
import Link from 'sentry/components/links/link';
import {DatePageFilter} from 'sentry/components/organizations/datePageFilter';
import {EnvironmentPageFilter} from 'sentry/components/organizations/environmentPageFilter';
import PageFilterBar from 'sentry/components/organizations/pageFilterBar';
Expand All @@ -27,12 +28,14 @@ import type {SmartSearchBarProps} from 'sentry/components/smartSearchBar';
import {TabList, Tabs} from 'sentry/components/tabs';
import {MAX_QUERY_LENGTH} from 'sentry/constants';
import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
import {t} from 'sentry/locale';
import {t, tct} from 'sentry/locale';
import SidebarPanelStore from 'sentry/stores/sidebarPanelStore';
import {space} from 'sentry/styles/space';
import {trackAnalytics} from 'sentry/utils/analytics';
import {browserHistory} from 'sentry/utils/browserHistory';
import {useHasProfilingChunks} from 'sentry/utils/profiling/hooks/useHasProfileChunks';
import {useProfileEvents} from 'sentry/utils/profiling/hooks/useProfileEvents';
import {useProfileEventsStats} from 'sentry/utils/profiling/hooks/useProfileEventsStats';
import {formatError, formatSort} from 'sentry/utils/profiling/hooks/utils';
import {decodeScalar} from 'sentry/utils/queryString';
import {useLocation} from 'sentry/utils/useLocation';
Expand Down Expand Up @@ -136,6 +139,14 @@ function ProfilingContentLegacy({location}: ProfilingContentProps) {
);
}, [selection.projects, projects]);

const profileStats = useProfileEventsStats({
query,
dataset: 'profiles',
referrer: 'api.profiling.landing-chart',
yAxes: SERIES_ORDER,
continuousProfilingCompat: true,
});

return (
<SentryDocumentTitle title={t('Profiling')} orgSlug={organization.slug}>
<PageFiltersContainer
Expand Down Expand Up @@ -200,7 +211,7 @@ function ProfilingContentLegacy({location}: ProfilingContentProps) {
<h3>{t('Function level insights')}</h3>
<p>
{t(
'Discover slow-to-execute or resource intensive functions within your application'
'Discover slow-to-execute or resource intensive functions within your application.'
)}
</p>
</Fragment>
Expand Down Expand Up @@ -234,9 +245,8 @@ function ProfilingContentLegacy({location}: ProfilingContentProps) {
<Fragment>
<ProfilesChartWidget
chartHeight={150}
referrer="api.profiling.landing-chart"
userQuery={query}
selection={selection}
profileStats={profileStats}
/>
<WidgetsContainer>
<LandingWidgetSelector
Expand Down Expand Up @@ -371,6 +381,7 @@ function ProfilingContent({location}: ProfilingContentProps) {
<ProfilingTransactionsContent
tab={tab}
shouldShowProfilingOnboardingPanel={shouldShowProfilingOnboardingPanel}
onSeeFlamegraphTabClick={() => onTabChange('flamegraph')}
/>
</Layout.Body>
) : null}
Expand All @@ -383,6 +394,7 @@ function ProfilingContent({location}: ProfilingContentProps) {
interface ProfilingTabContentProps {
shouldShowProfilingOnboardingPanel: boolean;
tab: 'flamegraph' | 'transactions';
onSeeFlamegraphTabClick?: () => void;
}

function ProfilingFlamegraphTabContent(props: ProfilingTabContentProps) {
Expand All @@ -409,6 +421,8 @@ function ProfilingFlamegraphTabContent(props: ProfilingTabContentProps) {
);
}

const SERIES_ORDER = ['p99()', 'p95()', 'p75()', 'p50()'] as const;

function ProfilingTransactionsContent(props: ProfilingTabContentProps) {
const organization = useOrganization();
const location = useLocation();
Expand Down Expand Up @@ -450,13 +464,36 @@ function ProfilingTransactionsContent(props: ProfilingTabContentProps) {
[location]
);

const hasProfileChunks = useHasProfilingChunks();

const profileStats = useProfileEventsStats({
dataset: 'profiles',
query,
referrer: 'api.profiling.landing-chart',
yAxes: SERIES_ORDER,
continuousProfilingCompat: true,
});

const showGoToAggregateFlamegraph =
hasProfileChunks.status === 'success' &&
hasProfileChunks.data &&
profileStats.status === 'success' &&
profileStats.data.data.every(d => d.values.every(v => v === 0));

return (
<Layout.Main fullWidth>
{transactionsError && (
<Alert type="error" showIcon>
{transactionsError}
</Alert>
)}

{showGoToAggregateFlamegraph ? (
<ProfilingMissingTransactionsAlert
onSeeFlamegraphTabClick={props.onSeeFlamegraphTabClick}
/>
) : null}

<ActionBar>
<PageFilterBar condensed>
<ProjectPageFilter resetParamsOnChange={CURSOR_PARAMS} />
Expand Down Expand Up @@ -489,21 +526,17 @@ function ProfilingTransactionsContent(props: ProfilingTabContentProps) {
<Fragment>
<ProfilesChartWidget
chartHeight={150}
referrer="api.profiling.landing-chart"
userQuery={query}
selection={selection}
continuousProfilingCompat
profileStats={profileStats}
/>
<SlowestFunctionsTable userQuery={query} />
</Fragment>
) : organization.features.includes('profiling-global-suspect-functions') ? (
<Fragment>
<ProfilesChartWidget
chartHeight={150}
referrer="api.profiling.landing-chart"
userQuery={query}
selection={selection}
continuousProfilingCompat
profileStats={profileStats}
/>
<WidgetsContainer>
<LandingWidgetSelector
Expand Down Expand Up @@ -563,6 +596,53 @@ function ProfilingTransactionsContent(props: ProfilingTabContentProps) {
);
}

function ProfilingMissingTransactionsAlert(props: {
onSeeFlamegraphTabClick: (() => void) | undefined;
}) {
const organization = useOrganization();

useEffect(() => {
trackAnalytics('profiling_views.missing_transactions_banner.viewed', {
organization,
});
}, [organization]);

const onSeeFlamegraphTabClick = props.onSeeFlamegraphTabClick;
const onViewFlamegraphClick = useCallback(() => {
trackAnalytics('profiling_views.missing_transactions_banner.flamegraph_clicked', {
organization,
});
onSeeFlamegraphTabClick?.();
}, [organization, onSeeFlamegraphTabClick]);

return (
<Alert
type="warning"
showIcon
trailingItems={
<Button onClick={onViewFlamegraphClick} size="xs">
{t('View Flamegraph')}
</Button>
}
>
{t(
'Looks like you are only sending us continuous profiling data and not tracing data.'
)}{' '}
{tct('Learn why this happens [docsLink].', {
docsLink: (
<Link
to={
'https://docs.sentry.io/product/explore/profiling/transaction-vs-continuous-profiling/#missing-transaction-data'
}
>
{t('here')}
</Link>
),
})}
</Alert>
);
}

function ProfilingOnboardingCTA() {
const organization = useOrganization();
// Open the modal on demand
Expand All @@ -585,7 +665,7 @@ function ProfilingOnboardingCTA() {
<h3>{t('Function level insights')}</h3>
<p>
{t(
'Discover slow-to-execute or resource intensive functions within your application'
'Discover slow-to-execute or resource intensive functions within your application.'
)}
</p>
</Fragment>
Expand Down
18 changes: 3 additions & 15 deletions static/app/views/profiling/landing/profilesChartWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {t} from 'sentry/locale';
import type {PageFilters} from 'sentry/types/core';
import type {Series} from 'sentry/types/echarts';
import {axisLabelFormatter, tooltipFormatter} from 'sentry/utils/discover/charts';
import {useProfileEventsStats} from 'sentry/utils/profiling/hooks/useProfileEventsStats';
import type {useProfileEventsStats} from 'sentry/utils/profiling/hooks/useProfileEventsStats';
import useOrganization from 'sentry/utils/useOrganization';

import {
Expand All @@ -20,36 +20,24 @@ import {

interface ProfilesChartWidgetProps {
chartHeight: number;
referrer: string;
continuousProfilingCompat?: boolean;
profileStats: ReturnType<typeof useProfileEventsStats>;
header?: ReactNode;
selection?: PageFilters;
userQuery?: string;
widgetHeight?: string;
}

const SERIES_ORDER = ['p99()', 'p95()', 'p75()', 'p50()'] as const;

export function ProfilesChartWidget({
chartHeight,
continuousProfilingCompat,
header,
referrer,
selection,
userQuery,
widgetHeight,
profileStats,
}: ProfilesChartWidgetProps) {
const theme = useTheme();
const organization = useOrganization();

const profileStats = useProfileEventsStats({
dataset: 'profiles',
query: userQuery,
referrer,
yAxes: SERIES_ORDER,
continuousProfilingCompat,
});

const series: Series[] = useMemo(() => {
if (profileStats.status !== 'success') {
return [];
Expand Down
2 changes: 1 addition & 1 deletion static/app/views/profiling/profilingOnboardingPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function ProfilingOnboardingPanel(props: ProfilingOnboardingPanelProps) {
<h3>{t('Function level insights')}</h3>
<p>
{t(
'Discover slow-to-execute or resource intensive functions within your application'
'Discover slow-to-execute or resource intensive functions within your application.'
)}
</p>
</Fragment>
Expand Down
Loading