messageSpanSamplesTable.tsx 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import type {ComponentProps} from 'react';
  2. import styled from '@emotion/styled';
  3. import type {Location} from 'history';
  4. import GridEditable, {
  5. COL_WIDTH_UNDEFINED,
  6. type GridColumnHeader,
  7. } from 'sentry/components/gridEditable';
  8. import {t} from 'sentry/locale';
  9. import type {Organization} from 'sentry/types/organization';
  10. import type {EventsMetaType} from 'sentry/utils/discover/eventView';
  11. import {getFieldRenderer} from 'sentry/utils/discover/fieldRenderers';
  12. import {useLocation} from 'sentry/utils/useLocation';
  13. import useOrganization from 'sentry/utils/useOrganization';
  14. import {renderHeadCell} from 'sentry/views/insights/common/components/tableCells/renderHeadCell';
  15. import {SpanIdCell} from 'sentry/views/insights/common/components/tableCells/spanIdCell';
  16. import {MessageActorType} from 'sentry/views/insights/queues/settings';
  17. import type {SpanIndexedResponse} from 'sentry/views/insights/types';
  18. import {ModuleName, SpanIndexedField} from 'sentry/views/insights/types';
  19. import {TraceViewSources} from 'sentry/views/performance/newTraceDetails/traceHeader/breadcrumbs';
  20. type DataRowKeys =
  21. | SpanIndexedField.PROJECT
  22. | SpanIndexedField.TRANSACTION_ID
  23. | SpanIndexedField.TRACE
  24. | SpanIndexedField.TIMESTAMP
  25. | SpanIndexedField.ID
  26. | SpanIndexedField.SPAN_DESCRIPTION
  27. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  28. | SpanIndexedField.MESSAGING_MESSAGE_RECEIVE_LATENCY
  29. | SpanIndexedField.MESSAGING_MESSAGE_ID
  30. | SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT
  31. | SpanIndexedField.TRACE_STATUS
  32. | SpanIndexedField.SPAN_DURATION;
  33. type ColumnKeys =
  34. | SpanIndexedField.ID
  35. | SpanIndexedField.MESSAGING_MESSAGE_ID
  36. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  37. | SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT
  38. | SpanIndexedField.TRACE_STATUS
  39. | SpanIndexedField.SPAN_DURATION;
  40. type DataRow = Pick<SpanIndexedResponse, DataRowKeys>;
  41. type Column = GridColumnHeader<ColumnKeys>;
  42. const CONSUMER_COLUMN_ORDER: Column[] = [
  43. {
  44. key: SpanIndexedField.ID,
  45. name: t('Span ID'),
  46. width: 150,
  47. },
  48. {
  49. key: SpanIndexedField.MESSAGING_MESSAGE_ID,
  50. name: t('Message ID'),
  51. width: COL_WIDTH_UNDEFINED,
  52. },
  53. {
  54. key: SpanIndexedField.SPAN_DURATION,
  55. name: t('Span Duration'),
  56. width: COL_WIDTH_UNDEFINED,
  57. },
  58. {
  59. key: SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT,
  60. name: t('Retries'),
  61. width: COL_WIDTH_UNDEFINED,
  62. },
  63. {
  64. key: SpanIndexedField.TRACE_STATUS,
  65. name: t('Status'),
  66. width: COL_WIDTH_UNDEFINED,
  67. },
  68. ];
  69. const PRODUCER_COLUMN_ORDER: Column[] = [
  70. {
  71. key: SpanIndexedField.ID,
  72. name: t('Span ID'),
  73. width: 150,
  74. },
  75. {
  76. key: SpanIndexedField.MESSAGING_MESSAGE_ID,
  77. name: t('Message ID'),
  78. width: COL_WIDTH_UNDEFINED,
  79. },
  80. {
  81. key: SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE,
  82. name: t('Message Size'),
  83. width: COL_WIDTH_UNDEFINED,
  84. },
  85. {
  86. key: SpanIndexedField.TRACE_STATUS,
  87. name: t('Status'),
  88. width: COL_WIDTH_UNDEFINED,
  89. },
  90. ];
  91. interface Props {
  92. data: DataRow[];
  93. isLoading: boolean;
  94. type: MessageActorType;
  95. error?: Error | null;
  96. highlightedSpanId?: string;
  97. meta?: EventsMetaType;
  98. onSampleMouseOut?: ComponentProps<typeof GridEditable>['onRowMouseOut'];
  99. onSampleMouseOver?: ComponentProps<typeof GridEditable>['onRowMouseOver'];
  100. }
  101. export function MessageSpanSamplesTable({
  102. data,
  103. isLoading,
  104. error,
  105. meta,
  106. onSampleMouseOver,
  107. onSampleMouseOut,
  108. highlightedSpanId,
  109. type,
  110. }: Props) {
  111. const location = useLocation();
  112. const organization = useOrganization();
  113. return (
  114. <GridEditable
  115. aria-label={t('Span Samples')}
  116. isLoading={isLoading}
  117. error={error}
  118. data={data}
  119. columnOrder={
  120. type === MessageActorType.PRODUCER ? PRODUCER_COLUMN_ORDER : CONSUMER_COLUMN_ORDER
  121. }
  122. columnSortBy={[]}
  123. grid={{
  124. renderHeadCell: col =>
  125. renderHeadCell({
  126. column: col,
  127. location,
  128. }),
  129. renderBodyCell: (column, row) =>
  130. renderBodyCell(column, row, meta, location, organization),
  131. }}
  132. highlightedRowKey={data.findIndex(row => row.span_id === highlightedSpanId)}
  133. onRowMouseOver={onSampleMouseOver}
  134. onRowMouseOut={onSampleMouseOut}
  135. />
  136. );
  137. }
  138. function renderBodyCell(
  139. column: Column,
  140. row: DataRow,
  141. meta: EventsMetaType | undefined,
  142. location: Location,
  143. organization: Organization
  144. ) {
  145. const key = column.key;
  146. if (row[key] === undefined) {
  147. return (
  148. <AlignRight>
  149. <NoValue>{' \u2014 '}</NoValue>
  150. </AlignRight>
  151. );
  152. }
  153. if (key === SpanIndexedField.ID) {
  154. return (
  155. <SpanIdCell
  156. moduleName={ModuleName.QUEUE}
  157. projectSlug={row.project}
  158. traceId={row.trace}
  159. timestamp={row.timestamp}
  160. transactionId={row[SpanIndexedField.TRANSACTION_ID]}
  161. spanId={row[SpanIndexedField.ID]}
  162. source={TraceViewSources.QUEUES_MODULE}
  163. location={location}
  164. />
  165. );
  166. }
  167. if (!meta?.fields) {
  168. return row[column.key];
  169. }
  170. const renderer = getFieldRenderer(column.key, meta.fields, false);
  171. return renderer(row, {
  172. location,
  173. organization,
  174. unit: meta.units?.[column.key],
  175. });
  176. }
  177. const AlignRight = styled('span')`
  178. text-align: right;
  179. `;
  180. const NoValue = styled('span')`
  181. color: ${p => p.theme.gray300};
  182. `;