Skip to content
Merged
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
36 changes: 28 additions & 8 deletions static/app/components/events/breadcrumbs/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -198,16 +198,39 @@ export interface EnhancedCrumb {
export function getEnhancedBreadcrumbs(event: Event, theme: Theme): EnhancedCrumb[] {
const breadcrumbEntryIndex =
event.entries?.findIndex(entry => entry.type === EntryType.BREADCRUMBS) ?? -1;
const breadcrumbs: any[] = event.entries?.[breadcrumbEntryIndex]?.data?.values ?? [];

if (breadcrumbs.length === 0) {
return [];
}
const breadcrumbs: RawCrumb[] =
event.entries?.[breadcrumbEntryIndex]?.data?.values ?? [];

// Mapping of breadcrumb index -> breadcrumb meta
const meta: Record<number, any> =
event._meta?.entries?.[breadcrumbEntryIndex]?.data?.values ?? {};

return getEnhancedBreadcrumbsFromValues({
breadcrumbs,
theme,
meta,
virtualCrumb: getVirtualCrumb(event),
});
}

/**
* Prefer `getEnhancedBreadcrumbs` when an `Event` is available.
*/
export function getEnhancedBreadcrumbsFromValues({
breadcrumbs,
theme,
meta = {},
virtualCrumb,
}: {
breadcrumbs: RawCrumb[];
theme: Theme;
meta?: Record<number, any>;
virtualCrumb?: RawCrumb;
}): EnhancedCrumb[] {
if (breadcrumbs.length === 0) {
return [];
}

const enhancedCrumbs = breadcrumbs.map<
Pick<EnhancedCrumb, 'raw' | 'meta' | 'breadcrumb'>
>((raw, i) => ({
Expand All @@ -217,9 +240,6 @@ export function getEnhancedBreadcrumbs(event: Event, theme: Theme): EnhancedCrum
breadcrumb: convertCrumbType(raw),
}));

// The virtual crumb is a representation of this event, displayed alongside
// the rest of the breadcrumbs for more additional context.
const virtualCrumb = getVirtualCrumb(event);
const allCrumbs = virtualCrumb
? [...enhancedCrumbs, {breadcrumb: virtualCrumb}]
: enhancedCrumbs;
Expand Down
2 changes: 1 addition & 1 deletion static/app/components/events/contexts/contextCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import {useOrganization} from 'sentry/utils/useOrganization';

interface ContextCardProps {
alias: string;
event: Event;
type: string;
event?: Event;
project?: Project;
value?: ContextValue;
}
Expand Down
22 changes: 20 additions & 2 deletions static/app/components/events/contexts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,25 @@ export interface ContextItem {
}

export function getOrderedContextItems(event: Event): ContextItem[] {
const {user, contexts} = event;
return getOrderedContextItemsFromContexts({
contexts: event.contexts,
user: event.user,
hasSyntheticTrace: eventHasSyntheticTrace(event),
});
}

/**
* Prefer `getOrderedContextItems` when an `Event` is available.
*/
export function getOrderedContextItemsFromContexts({
contexts,
user,
hasSyntheticTrace = false,
}: {
contexts: Event['contexts'] | undefined;
hasSyntheticTrace?: boolean;
user?: Event['user'];
}): ContextItem[] {
const {data: customUserData, ...userContext} = user ?? {};

// hide `flags` in the contexts section since we display this
Expand Down Expand Up @@ -64,7 +82,7 @@ export function getOrderedContextItems(event: Event): ContextItem[] {

const items = orderedContext
.filter(([alias, ctxValue]) => {
if (alias === 'trace' && eventHasSyntheticTrace(event)) {
if (alias === 'trace' && hasSyntheticTrace) {
return false;
}
const contextKeys = Object.keys(ctxValue ?? {});
Expand Down
4 changes: 2 additions & 2 deletions static/app/components/events/contexts/knownContext/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export function getAppContextData({
meta,
}: {
data: AppContext;
event: Event;
event?: Event;
meta?: Record<keyof AppContext, any>;
}): KeyValueListData {
return getContextKeys({data}).map(ctxKey => {
Expand All @@ -79,7 +79,7 @@ export function getAppContextData({
key: ctxKey,
subject: t('Start Time'),
value: getRelativeTimeFromEventDateCreated(
event.dateCreated ? event.dateCreated : event.dateReceived,
event?.dateCreated ?? event?.dateReceived,
data.app_start_time
),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export function getDeviceContextData({
meta,
}: {
data: DeviceContext;
event: Event;
event?: Event;
meta?: Record<keyof DeviceContext, any>;
}): KeyValueListData {
return getContextKeys({data: getInferredData(data)}).map(ctxKey => {
Expand Down Expand Up @@ -284,7 +284,7 @@ export function getDeviceContextData({
key: ctxKey,
subject: t('Boot Time'),
value: getRelativeTimeFromEventDateCreated(
event.dateCreated ? event.dateCreated : event.dateReceived,
event?.dateCreated ?? event?.dateReceived,
data.boot_time
),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export function getProfileContextData({
meta,
}: {
data: ProfileContext;
event: Event;
organization: Organization;
event?: Event;
meta?: Record<keyof ProfileContext, any>;
project?: Project;
}): KeyValueListData {
Expand Down Expand Up @@ -72,7 +72,7 @@ function getProfileIdEntry(

function getProfilerIdEntry(
data: ProfileContext,
event: Event,
event: Event | undefined,
organization: Organization,
project?: Project
) {
Expand All @@ -82,7 +82,7 @@ function getProfilerIdEntry(
}
const [start, end] = getStartEnd(event);
const link =
project?.slug && start && end
event && project?.slug && start && end
? generateContinuousProfileFlamechartRouteWithQuery({
organization,
projectSlug: project.slug,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ export function getTraceContextData({
meta,
}: {
data: TraceContext;
event: Event;
location: Location;
organization: Organization;
event?: Event;
meta?: Record<keyof TraceContext, any>;
}): KeyValueListData {
return getContextKeys({data})
Expand All @@ -66,7 +66,9 @@ export function getTraceContextData({
const traceWasSampled = data?.sampled ?? true;

if (traceWasSampled) {
const link = getTraceTargetFromEvent(event, organization, location);
const link = event
? getTraceTargetFromEvent(event, organization, location)
: undefined;
const hasPerformanceView = organization.features.includes('performance-view');

return {
Expand Down Expand Up @@ -171,7 +173,7 @@ export function getTraceContextData({
const link = transactionSummaryRouteWithQuery({
organization,
transaction: transactionName,
projectID: event.projectID,
projectID: event?.projectID,
query: {},
});

Expand Down
26 changes: 18 additions & 8 deletions static/app/components/events/contexts/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function generateIconName(
}

export function getRelativeTimeFromEventDateCreated(
eventDateCreated: string,
eventDateCreated: string | undefined,
timestamp?: string,
showTimestamp = true
) {
Expand All @@ -120,7 +120,14 @@ export function getRelativeTimeFromEventDateCreated(
return timestamp;
}

const relativeTime = `(${dateTime.from(eventDateCreated, true)} ${t(
// Without a valid reference date (e.g. the event isn't available) we can't
// compute a relative time, so just show the timestamp on its own.
const referenceDate = moment(eventDateCreated);
if (!eventDateCreated || !referenceDate.isValid()) {
return timestamp;
}

const relativeTime = `(${dateTime.from(referenceDate, true)} ${t(
'before this event'
)})`;

Expand Down Expand Up @@ -314,17 +321,20 @@ export function getContextTitle({
}
}

export function getContextMeta(event: Event, contextType: string): Record<string, any> {
const defaultMeta = event._meta?.contexts?.[contextType] ?? {};
export function getContextMeta(
event: Event | undefined,
contextType: string
): Record<string, any> {
const defaultMeta = event?._meta?.contexts?.[contextType] ?? {};
switch (contextType) {
case 'memory_info': // Current
case 'Memory Info': // Legacy
return event._meta?.contexts?.['Memory Info'] ?? defaultMeta;
return event?._meta?.contexts?.['Memory Info'] ?? defaultMeta;
case 'threadpool_info': // Current
case 'ThreadPool Info': // Legacy
return event._meta?.contexts?.['ThreadPool Info'] ?? defaultMeta;
return event?._meta?.contexts?.['ThreadPool Info'] ?? defaultMeta;
case 'user':
return event._meta?.user ?? defaultMeta;
return event?._meta?.user ?? defaultMeta;
default:
return defaultMeta;
}
Expand Down Expand Up @@ -392,9 +402,9 @@ export function getFormattedContextData({
}: {
contextType: string;
contextValue: any;
event: Event;
location: Location;
organization: Organization;
event?: Event;
project?: Project;
}): KeyValueListData {
const meta = getContextMeta(event, contextType);
Expand Down
2 changes: 1 addition & 1 deletion static/app/types/event.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export type EntryDebugMeta = {
type: EntryType.DEBUGMETA;
};

type EntryBreadcrumbs = {
export type EntryBreadcrumbs = {
data: {
values: RawCrumb[];
};
Expand Down
7 changes: 7 additions & 0 deletions static/app/views/explore/hooks/useTraceItemDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {skipToken, useQuery, useQueryClient} from '@tanstack/react-query';

import {normalizeDateTimeParams} from 'sentry/components/pageFilters/parse';
import {usePageFilters} from 'sentry/components/pageFilters/usePageFilters';
import type {RawCrumb} from 'sentry/types/breadcrumbs';
import type {EventTransaction} from 'sentry/types/event';
import type {Meta} from 'sentry/types/group';
import {apiOptions} from 'sentry/utils/api/apiOptions';
import {normalizeTimestampToSeconds} from 'sentry/utils/dates';
Expand Down Expand Up @@ -66,6 +68,11 @@ export interface TraceItemDetailsResponse {
itemId: string;
meta: TraceItemDetailsMeta;
timestamp: string;
event?: {
breadcrumbs?: {values: RawCrumb[]};
contexts?: EventTransaction['contexts'];
extra?: EventTransaction['context'];
};
links?: TraceItemResponseLink[];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {getOrderedContextItems} from 'sentry/components/events/contexts';
import {getOrderedContextItemsFromContexts} from 'sentry/components/events/contexts';
import {ContextCard} from 'sentry/components/events/contexts/contextCard';
import {KeyValueData} from 'sentry/components/keyValueData';
import {t} from 'sentry/locale';
import {EntryType, type EventTransaction} from 'sentry/types/event';
import type {EventTransaction} from 'sentry/types/event';
import type {Project} from 'sentry/types/project';
import {SectionKey} from 'sentry/views/issueDetails/context';
import {FoldSection} from 'sentry/views/issueDetails/foldSection';
Expand All @@ -11,7 +11,6 @@ import {
AdditionalData,
hasAdditionalData,
} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/transaction/sections/additionalData';
import {Request} from 'sentry/views/performance/newTraceDetails/traceDrawer/details/transaction/sections/request';

// List of context types that are displayed as span attributes.
// These should not be displayed in the contexts section.
Expand All @@ -31,39 +30,26 @@ const DUPLICATES_FROM_ATTRIBUTES = [
];

export function Contexts({
event,
contexts,
extra,
project,
}: {
event: EventTransaction | undefined;
contexts: EventTransaction['contexts'] | undefined;
extra: EventTransaction['context'] | undefined;
project: Project | undefined;
}) {
if (!event) {
return null;
}

const extraContexts = getOrderedContextItems(event).filter(
const extraContexts = getOrderedContextItemsFromContexts({contexts}).filter(
({type}) => !DUPLICATES_FROM_ATTRIBUTES.includes(type)
);
const eventHasExtraContexts = Object.keys(extraContexts).length > 0;

const eventHasRequestEntry = event?.entries.some(
entry => entry.type === EntryType.REQUEST
);
const eventHasAdditionalData = event ? hasAdditionalData(event) : false;
const eventHasExtraContexts = extraContexts.length > 0;
const eventHasAdditionalData = hasAdditionalData(extra);

if (!eventHasRequestEntry && !eventHasAdditionalData && !eventHasExtraContexts) {
if (!eventHasExtraContexts && !eventHasAdditionalData) {
return null;
}

const extraContextCards = extraContexts.map(({alias, type, value}) => (
<ContextCard
key={alias}
type={type}
alias={alias}
value={value}
event={event}
project={project}
/>
<ContextCard key={alias} type={type} alias={alias} value={value} project={project} />
));

return (
Expand All @@ -79,8 +65,7 @@ export function Contexts({
}
disableCollapsePersistence
>
{eventHasRequestEntry ? <Request event={event} /> : null}
{eventHasAdditionalData ? <AdditionalData event={event} /> : null}
{eventHasAdditionalData ? <AdditionalData extra={extra} /> : null}
{eventHasExtraContexts ? (
<KeyValueData.Container>{extraContextCards}</KeyValueData.Container>
) : null}
Expand Down
Loading
Loading