123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- import type {Location, LocationDescriptorObject} from 'history';
- import {PAGE_URL_PARAM} from 'sentry/constants/pageFilters';
- import type {Organization} from 'sentry/types';
- import {getTimeStampFromTableDateField} from 'sentry/utils/dates';
- import type {
- EventLite,
- TraceError,
- TraceFull,
- TraceFullDetailed,
- TraceSplitResults,
- } from 'sentry/utils/performance/quickTrace/types';
- import {isTraceSplitResult, reduceTrace} from 'sentry/utils/performance/quickTrace/utils';
- import normalizeUrl from 'sentry/utils/url/normalizeUrl';
- import {DEFAULT_TRACE_ROWS_LIMIT} from './limitExceededMessage';
- import type {TraceInfo} from './types';
- export function getTraceDetailsUrl({
- organization,
- traceSlug,
- dateSelection,
- timestamp,
- spanId,
- eventId,
- demo,
- location,
- source,
- }: {
- dateSelection;
- location: Location;
- organization: Organization;
- traceSlug: string;
- demo?: string;
- eventId?: string;
- source?: string;
- spanId?: string;
- timestamp?: string | number;
- }): LocationDescriptorObject {
- const {start, end, statsPeriod} = dateSelection;
- const queryParams = {
- ...location.query,
- statsPeriod,
- [PAGE_URL_PARAM.PAGE_START]: start,
- [PAGE_URL_PARAM.PAGE_END]: end,
- };
- const oldTraceUrl = {
- pathname: normalizeUrl(
- `/organizations/${organization.slug}/performance/trace/${traceSlug}/`
- ),
- query: queryParams,
- };
- if (shouldForceRouteToOldView(organization, timestamp)) {
- return oldTraceUrl;
- }
- if (organization.features.includes('trace-view-v1')) {
- if (spanId) {
- queryParams.node = [`span-${spanId}`, `txn-${eventId}`];
- }
- return {
- pathname: normalizeUrl(
- `/organizations/${organization.slug}/performance/trace/${traceSlug}/`
- ),
- query: {
- ...queryParams,
- timestamp: getTimeStampFromTableDateField(timestamp),
- eventId,
- demo,
- source,
- },
- };
- }
- if (organization.features.includes('trace-view-load-more')) {
- queryParams.limit = DEFAULT_TRACE_ROWS_LIMIT;
- }
- return oldTraceUrl;
- }
- /**
- * Single tenant, on-premise etc. users may not have span extraction enabled.
- *
- * This code can be removed at the time we're sure all STs have rolled out span extraction.
- */
- export function shouldForceRouteToOldView(
- organization: Organization,
- timestamp: string | number | undefined
- ) {
- const usableTimestamp = getTimeStampFromTableDateField(timestamp);
- if (!usableTimestamp) {
- // Timestamps must always be provided for the new view, if it doesn't exist, fall back to the old view.
- return true;
- }
- return (
- organization.extraOptions?.traces.checkSpanExtractionDate &&
- organization.extraOptions?.traces.spansExtractionDate <= usableTimestamp
- );
- }
- 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.performanceIssues.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 | undefined,
- orphanErrors: TraceError[] | undefined
- ): boolean {
- return Boolean(
- (traces && traces.length > 0) || (orphanErrors && orphanErrors.length > 0)
- );
- }
- export function getTraceSplitResults<U extends TraceFullDetailed | TraceFull | EventLite>(
- trace: TraceSplitResults<U> | U[],
- organization: Organization
- ) {
- let transactions: U[] | undefined;
- let orphanErrors: TraceError[] | undefined;
- if (
- trace &&
- organization.features.includes('performance-tracing-without-performance') &&
- isTraceSplitResult<TraceSplitResults<U>, U[]>(trace)
- ) {
- orphanErrors = trace.orphan_errors;
- transactions = trace.transactions;
- }
- return {transactions, orphanErrors};
- }
- export function getTraceInfo(
- traces: TraceFullDetailed[] = [],
- orphanErrors: TraceError[] = []
- ) {
- const initial = {
- projects: new Set<string>(),
- errors: new Set<string>(),
- performanceIssues: new Set<string>(),
- transactions: new Set<string>(),
- startTimestamp: Number.MAX_SAFE_INTEGER,
- endTimestamp: 0,
- maxGeneration: 0,
- trailingOrphansCount: 0,
- };
- const transactionsInfo = traces.reduce(
- (info: TraceInfo, trace: TraceFullDetailed) =>
- reduceTrace<TraceInfo>(trace, transactionVisitor(), info),
- initial
- );
- // Accumulate orphan error information.
- return orphanErrors.reduce((accumulator: TraceInfo, event: TraceError) => {
- accumulator.errors.add(event.event_id);
- accumulator.trailingOrphansCount++;
- 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;
- }
|