import type {Location} from 'history'; import {getContextKeys} from 'sentry/components/events/contexts/utils'; import {generateTraceTarget} from 'sentry/components/quickTrace/utils'; import {t} from 'sentry/locale'; import type {Event} from 'sentry/types/event'; import type {KeyValueListData} from 'sentry/types/group'; import type {Organization} from 'sentry/types/organization'; import {defined} from 'sentry/utils'; import {transactionSummaryRouteWithQuery} from 'sentry/views/performance/transactionSummary/utils'; enum TraceContextKeys { TRACE_ID = 'trace_id', SPAN_ID = 'span_id', PARENT_SPAN_ID = 'parent_span_id', OP_NAME = 'op', STATUS = 'status', EXCLUSIVE_TIME = 'exclusive_time', CLIENT_SAMPLE_RATE = 'client_sample_rate', DYNAMIC_SAMPLING_CONTEXT = 'dynamic_sampling_context', ORIGIN = 'origin', DATA = 'data', } export interface TraceContext { // Any custom keys users may set [key: string]: any; [TraceContextKeys.TRACE_ID]?: string; [TraceContextKeys.SPAN_ID]?: string; [TraceContextKeys.PARENT_SPAN_ID]?: string; [TraceContextKeys.OP_NAME]?: string; [TraceContextKeys.STATUS]?: string; [TraceContextKeys.EXCLUSIVE_TIME]?: number; [TraceContextKeys.CLIENT_SAMPLE_RATE]?: number; [TraceContextKeys.DYNAMIC_SAMPLING_CONTEXT]?: Record; [TraceContextKeys.ORIGIN]?: string; [TraceContextKeys.DATA]?: Record; } export function getTraceContextData({ data, event, location, organization, meta, }: { data: TraceContext; event: Event; location: Location; organization: Organization; meta?: Record; }): KeyValueListData { return getContextKeys({data}) .map(ctxKey => { switch (ctxKey) { case TraceContextKeys.TRACE_ID: { const traceId = data.trace_id || ''; if (!traceId) { return undefined; } const link = generateTraceTarget(event, organization, location); return { key: ctxKey, subject: t('Trace ID'), value: traceId, action: {link}, }; } case TraceContextKeys.SPAN_ID: { return { key: ctxKey, subject: t('Span ID'), value: data.span_id || '', }; } case TraceContextKeys.PARENT_SPAN_ID: { return { key: ctxKey, subject: t('Parent Span ID'), value: data.parent_span_id || '', }; } case TraceContextKeys.OP_NAME: { return { key: ctxKey, subject: t('Operation Name'), value: data.op || '', }; } case TraceContextKeys.STATUS: { return { key: ctxKey, subject: t('Status'), value: data.status || '', }; } case TraceContextKeys.EXCLUSIVE_TIME: { return { key: ctxKey, subject: t('Exclusive Time (ms)'), value: data.exclusive_time, }; } case TraceContextKeys.CLIENT_SAMPLE_RATE: { return { key: ctxKey, subject: t('Client Sample Rate'), value: data.client_sample_rate, }; } case TraceContextKeys.DYNAMIC_SAMPLING_CONTEXT: { return { key: ctxKey, subject: t('Dynamic Sampling Context'), value: data.dynamic_sampling_context, }; } case TraceContextKeys.ORIGIN: { return { key: ctxKey, subject: t('Origin'), value: data.origin, }; } case TraceContextKeys.DATA: { return { key: ctxKey, subject: t('Data'), value: data.data, }; } case 'transaction_name': { const eventTag = event?.tags.find(tag => { return tag.key === 'transaction'; }); if (!eventTag || typeof eventTag.value !== 'string') { return undefined; } const transactionName = eventTag.value; if (!organization.features.includes('performance-view')) { return { key: ctxKey, subject: t('Transaction'), value: transactionName, }; } const link = transactionSummaryRouteWithQuery({ orgSlug: organization.slug, transaction: transactionName, projectID: event.projectID, query: {}, }); return { key: ctxKey, subject: t('Transaction'), value: transactionName, action: {link}, }; } default: return { key: ctxKey, subject: ctxKey, value: data[ctxKey], meta: meta?.[ctxKey]?.[''], }; } }) .filter(defined); }