import {LocationDescriptor, Query} from 'history'; import {PAGE_URL_PARAM} from 'sentry/constants/pageFilters'; import {OrganizationSummary} from 'sentry/types'; import {TraceError, TraceFullDetailed} from 'sentry/utils/performance/quickTrace/types'; import {reduceTrace} from 'sentry/utils/performance/quickTrace/utils'; import {TraceInfo} from './types'; export function getTraceDetailsUrl( organization: OrganizationSummary, traceSlug: string, dateSelection, query: Query ): LocationDescriptor { const {start, end, statsPeriod} = dateSelection; return { pathname: `/organizations/${organization.slug}/performance/trace/${traceSlug}/`, query: { ...query, statsPeriod, [PAGE_URL_PARAM.PAGE_START]: start, [PAGE_URL_PARAM.PAGE_END]: end, }, }; } function transactionVisitor() { return (accumulator: TraceInfo, event: TraceFullDetailed) => { for (const error of event.errors ?? []) { accumulator.errors.add(error.event_id); } for (const performanceIssue of event.performance_issues ?? []) { accumulator.errors.add(performanceIssue.event_id); } accumulator.transactions.add(event.event_id); accumulator.projects.add(event.project_slug); accumulator.startTimestamp = Math.min( accumulator.startTimestamp, event.start_timestamp ); accumulator.endTimestamp = Math.max(accumulator.endTimestamp, event.timestamp); accumulator.maxGeneration = Math.max(accumulator.maxGeneration, event.generation); return accumulator; }; } export function hasTraceData( traces: TraceFullDetailed[] | null, orphanErrors: TraceError[] | undefined ): boolean { return Boolean( (traces && traces.length > 0) || (orphanErrors && orphanErrors.length > 0) ); } export function getTraceInfo( traces: TraceFullDetailed[] = [], orphanErrors: TraceError[] = [] ) { const initial = { projects: new Set(), errors: new Set(), performanceIssues: new Set(), transactions: new Set(), startTimestamp: Number.MAX_SAFE_INTEGER, endTimestamp: 0, maxGeneration: 0, }; const transactionsInfo = traces.reduce( (info: TraceInfo, trace: TraceFullDetailed) => reduceTrace(trace, transactionVisitor(), info), initial ); // Accumulate orphan error information. return orphanErrors.reduce((accumulator: TraceInfo, event: TraceError) => { accumulator.errors.add(event.event_id); if (event.timestamp) { accumulator.startTimestamp = Math.min(accumulator.startTimestamp, event.timestamp); accumulator.endTimestamp = Math.max(accumulator.endTimestamp, event.timestamp); } return accumulator; }, transactionsInfo); } export function shortenErrorTitle(title: string): string { return title.split(':')[0]; } export function isRootTransaction(trace: TraceFullDetailed): boolean { // Root transactions has no parent_span_id return trace.parent_span_id === null; }