123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- import {Fragment, useMemo} from 'react';
- import styled from '@emotion/styled';
- import {CodeSnippet} from 'sentry/components/codeSnippet';
- import LoadingIndicator from 'sentry/components/loadingIndicator';
- import {space} from 'sentry/styles/space';
- import {
- MissingFrame,
- StackTraceMiniFrame,
- } from 'sentry/views/starfish/components/stackTraceMiniFrame';
- import {useFullSpanFromTrace} from 'sentry/views/starfish/queries/useFullSpanFromTrace';
- import {useIndexedSpans} from 'sentry/views/starfish/queries/useIndexedSpans';
- import type {SpanIndexedFieldTypes} from 'sentry/views/starfish/types';
- import {SpanIndexedField} from 'sentry/views/starfish/types';
- import {SQLishFormatter} from 'sentry/views/starfish/utils/sqlish/SQLishFormatter';
- interface Props {
- groupId: SpanIndexedFieldTypes[SpanIndexedField.SPAN_GROUP];
- op: SpanIndexedFieldTypes[SpanIndexedField.SPAN_OP];
- preliminaryDescription?: string;
- }
- export function SpanDescription(props: Props) {
- const {op, preliminaryDescription} = props;
- if (op.startsWith('db')) {
- return <DatabaseSpanDescription {...props} />;
- }
- return <WordBreak>{preliminaryDescription ?? ''}</WordBreak>;
- }
- const formatter = new SQLishFormatter();
- export function DatabaseSpanDescription({
- groupId,
- preliminaryDescription,
- }: Omit<Props, 'op'>) {
- const {data: indexedSpans, isFetching: areIndexedSpansLoading} = useIndexedSpans({
- filters: {'span.group': groupId},
- sorts: [INDEXED_SPAN_SORT],
- limit: 1,
- fields: [
- SpanIndexedField.PROJECT_ID,
- SpanIndexedField.TRANSACTION_ID,
- SpanIndexedField.SPAN_DESCRIPTION,
- ],
- referrer: 'api.starfish.span-description',
- });
- const indexedSpan = indexedSpans?.[0];
- // NOTE: We only need this for `span.data`! If this info existed in indexed spans, we could skip it
- const {data: rawSpan, isFetching: isRawSpanLoading} = useFullSpanFromTrace(
- groupId,
- [INDEXED_SPAN_SORT],
- Boolean(indexedSpan)
- );
- const rawDescription =
- rawSpan?.description || indexedSpan?.['span.description'] || preliminaryDescription;
- const formatterDescription = useMemo(() => {
- return formatter.toString(rawDescription ?? '');
- }, [rawDescription]);
- return (
- <Frame>
- {areIndexedSpansLoading ? (
- <WithPadding>
- <LoadingIndicator mini />
- </WithPadding>
- ) : (
- <CodeSnippet language="sql" isRounded={false}>
- {formatterDescription}
- </CodeSnippet>
- )}
- {!areIndexedSpansLoading && !isRawSpanLoading && (
- <Fragment>
- {rawSpan?.data?.['code.filepath'] ? (
- <StackTraceMiniFrame
- projectId={indexedSpan?.project_id?.toString()}
- eventId={indexedSpan?.['transaction.id']}
- frame={{
- filename: rawSpan?.data?.['code.filepath'],
- lineNo: rawSpan?.data?.['code.lineno'],
- function: rawSpan?.data?.['code.function'],
- }}
- />
- ) : (
- <MissingFrame />
- )}
- </Fragment>
- )}
- </Frame>
- );
- }
- const INDEXED_SPAN_SORT = {
- field: 'span.self_time',
- kind: 'desc' as const,
- };
- export const Frame = styled('div')`
- border: solid 1px ${p => p.theme.border};
- border-radius: ${p => p.theme.borderRadius};
- overflow: hidden;
- `;
- const WithPadding = styled('div')`
- display: flex;
- padding: ${space(1)} ${space(2)};
- `;
- const WordBreak = styled('div')`
- word-break: break-word;
- `;
|