import {CSSProperties, Fragment, useMemo, useState} from 'react'; import styled from '@emotion/styled'; import {Button} from 'sentry/components/button'; import {HeaderTitleLegend} from 'sentry/components/charts/styles'; import Count from 'sentry/components/count'; import EmptyStateWarning from 'sentry/components/emptyStateWarning'; import IdBadge from 'sentry/components/idBadge'; import Link from 'sentry/components/links/link'; import LoadingIndicator from 'sentry/components/loadingIndicator'; import {Panel} from 'sentry/components/panels'; import PerformanceDuration from 'sentry/components/performanceDuration'; import ScoreBar from 'sentry/components/scoreBar'; import TextOverflow from 'sentry/components/textOverflow'; import {Tooltip} from 'sentry/components/tooltip'; import {CHART_PALETTE} from 'sentry/constants/chartPalette'; import {IconChevron, IconWarning} from 'sentry/icons'; import {t, tct} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {EventsResultsDataRow} from 'sentry/utils/profiling/hooks/types'; import {useProfileFunctions} from 'sentry/utils/profiling/hooks/useProfileFunctions'; import {generateProfileFlamechartRouteWithQuery} from 'sentry/utils/profiling/routes'; import {MutableSearch} from 'sentry/utils/tokenizeSearch'; import useOrganization from 'sentry/utils/useOrganization'; import useProjects from 'sentry/utils/useProjects'; const MAX_FUNCTIONS = 3; export function SlowestFunctionsWidget() { const [expandedIndex, setExpandedIndex] = useState(0); const query = useMemo(() => { const conditions = new MutableSearch(''); conditions.setFilterValues('is_application', ['1']); return conditions.formatString(); }, []); const functionsQuery = useProfileFunctions({ fields: functionsFields, referrer: 'api.profiling.suspect-functions.list', sort: { key: 'sum()', order: 'desc', }, query, limit: MAX_FUNCTIONS, }); const hasFunctions = useMemo(() => { return (functionsQuery.data?.data?.length || 0) > 0; }, [functionsQuery.data]); const totalsQuery = useProfileFunctions({ fields: totalsFields, referrer: 'api.profiling.suspect-functions.totals', sort: { key: 'sum()', order: 'desc', }, query, limit: MAX_FUNCTIONS, // make sure to query for the projects from the top functions projects: functionsQuery.isFetched ? [ ...new Set( (functionsQuery.data?.data ?? []).map(func => func['project.id'] as number) ), ] : [], enabled: functionsQuery.isFetched && hasFunctions, }); return ( {t('Suspect Functions')} {t('Slowest functions by total time spent.')} {(functionsQuery.isLoading || (hasFunctions && totalsQuery.isLoading)) && ( )} {(functionsQuery.isError || totalsQuery.isError) && ( )} {functionsQuery.isFetched && !hasFunctions && (

{t('No functions found')}

)} {functionsQuery.isFetched && totalsQuery.isFetched && ( {(functionsQuery.data?.data ?? []).map((f, i) => { const projectEntry = totalsQuery.data?.data?.find( row => row['project.id'] === f['project.id'] ); const projectTotalDuration = projectEntry?.['sum()'] ?? f['sum()']; return ( setExpandedIndex(i)} func={f} totalDuration={projectTotalDuration as number} /> ); })} )}
); } interface SlowestFunctionEntryProps { func: EventsResultsDataRow; isExpanded: boolean; setExpanded: () => void; totalDuration: number; } const BARS = 10; function SlowestFunctionEntry({ func, isExpanded, setExpanded, totalDuration, }: SlowestFunctionEntryProps) { const organization = useOrganization(); const {projects} = useProjects(); const project = projects.find(p => p.id === String(func['project.id'])); const score = Math.ceil((((func['sum()'] as number) ?? 0) / totalDuration) * BARS); const palette = new Array(BARS).fill([CHART_PALETTE[0][0]]); const query = useMemo(() => { const conditions = new MutableSearch(''); conditions.setFilterValues('is_application', ['1']); conditions.setFilterValues('project.id', [String(func['project.id'])]); conditions.setFilterValues('package', [String(func.package)]); conditions.setFilterValues('function', [String(func.function)]); return conditions.formatString(); }, [func]); const functionTransactionsQuery = useProfileFunctions({ fields: functionTransactionsFields, referrer: 'api.profiling.suspect-functions.transactions', sort: { key: 'sum()', order: 'desc', }, query, limit: 5, enabled: isExpanded, }); return ( {project && } {func.function} , totalSelfTime: ( ), })} >