useFullSpanFromTrace.tsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import type {Entry, EntrySpans} from 'sentry/types/event';
  2. import {EntryType} from 'sentry/types/event';
  3. import type {Sort} from 'sentry/utils/discover/fields';
  4. import {MutableSearch} from 'sentry/utils/tokenizeSearch';
  5. import {useSpansIndexed} from 'sentry/views/insights/common/queries/useDiscover';
  6. import {useEventDetails} from 'sentry/views/insights/common/queries/useEventDetails';
  7. import {SpanIndexedField, type SpanIndexedProperty} from 'sentry/views/insights/types';
  8. const DEFAULT_SORT: Sort[] = [{field: 'timestamp', kind: 'desc'}];
  9. // NOTE: Fetching the top one is a bit naive, but works for now. A better
  10. // approach might be to fetch several at a time, and let the hook consumer
  11. // decide how to display them
  12. export function useFullSpanFromTrace(
  13. group?: string,
  14. sorts?: Sort[],
  15. enabled: boolean = true,
  16. extraFilters: Record<string, string> = {}
  17. ) {
  18. const filters = {...extraFilters};
  19. if (group) {
  20. filters[SpanIndexedField.SPAN_GROUP] = group;
  21. }
  22. const indexedSpansResponse = useSpansIndexed(
  23. {
  24. search: MutableSearch.fromQueryObject(filters),
  25. sorts: sorts || DEFAULT_SORT,
  26. limit: 1,
  27. enabled,
  28. fields: [
  29. SpanIndexedField.TIMESTAMP,
  30. SpanIndexedField.TRANSACTION_ID,
  31. SpanIndexedField.PROJECT,
  32. SpanIndexedField.ID,
  33. ...(sorts?.map(sort => sort.field as SpanIndexedProperty) || []),
  34. ],
  35. },
  36. 'api.starfish.full-span-from-trace'
  37. );
  38. const firstIndexedSpan = indexedSpansResponse.data?.[0];
  39. const eventDetailsResponse = useEventDetails({
  40. eventId: firstIndexedSpan?.[SpanIndexedField.TRANSACTION_ID],
  41. projectSlug: firstIndexedSpan?.[SpanIndexedField.PROJECT],
  42. });
  43. const spanEntry = eventDetailsResponse.data?.entries.find(
  44. (entry: Entry): entry is EntrySpans => {
  45. return entry.type === EntryType.SPANS;
  46. }
  47. );
  48. const fullSpan = spanEntry?.data?.find(
  49. span => span.span_id === firstIndexedSpan?.[SpanIndexedField.ID]
  50. );
  51. // N.B. There isn't a great pattern for us to merge the responses together,
  52. // so we're only merging the three most important properties
  53. return {
  54. isLoading: indexedSpansResponse.isPending || eventDetailsResponse.isPending,
  55. isFetching: indexedSpansResponse.isFetching || eventDetailsResponse.isFetching,
  56. isError: indexedSpansResponse.isError || eventDetailsResponse.isError,
  57. data: fullSpan,
  58. };
  59. }