messageSpanSamplesTable.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  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 {MessageActorType} from 'sentry/views/performance/queues/settings';
  15. import {renderHeadCell} from 'sentry/views/starfish/components/tableCells/renderHeadCell';
  16. import {SpanIdCell} from 'sentry/views/starfish/components/tableCells/spanIdCell';
  17. import type {IndexedResponse} from 'sentry/views/starfish/types';
  18. import {ModuleName, SpanIndexedField} from 'sentry/views/starfish/types';
  19. type DataRowKeys =
  20. | SpanIndexedField.PROJECT
  21. | SpanIndexedField.TRANSACTION_ID
  22. | SpanIndexedField.TRACE
  23. | SpanIndexedField.TIMESTAMP
  24. | SpanIndexedField.ID
  25. | SpanIndexedField.SPAN_DESCRIPTION
  26. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  27. | SpanIndexedField.MESSAGING_MESSAGE_RECEIVE_LATENCY
  28. | SpanIndexedField.MESSAGING_MESSAGE_ID
  29. | SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT
  30. | SpanIndexedField.TRACE_STATUS
  31. | SpanIndexedField.SPAN_DURATION;
  32. type ColumnKeys =
  33. | SpanIndexedField.ID
  34. | SpanIndexedField.MESSAGING_MESSAGE_ID
  35. | SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE
  36. | SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT
  37. | SpanIndexedField.TRACE_STATUS
  38. | SpanIndexedField.SPAN_DURATION;
  39. type DataRow = Pick<IndexedResponse, DataRowKeys>;
  40. type Column = GridColumnHeader<ColumnKeys>;
  41. const CONSUMER_COLUMN_ORDER: Column[] = [
  42. {
  43. key: SpanIndexedField.ID,
  44. name: t('Span ID'),
  45. width: 150,
  46. },
  47. {
  48. key: SpanIndexedField.MESSAGING_MESSAGE_ID,
  49. name: t('Message ID'),
  50. width: COL_WIDTH_UNDEFINED,
  51. },
  52. {
  53. key: SpanIndexedField.SPAN_DURATION,
  54. name: t('Processing Time'),
  55. width: COL_WIDTH_UNDEFINED,
  56. },
  57. {
  58. key: SpanIndexedField.MESSAGING_MESSAGE_RETRY_COUNT,
  59. name: t('Retries'),
  60. width: COL_WIDTH_UNDEFINED,
  61. },
  62. {
  63. key: SpanIndexedField.TRACE_STATUS,
  64. name: t('Status'),
  65. width: COL_WIDTH_UNDEFINED,
  66. },
  67. ];
  68. const PRODUCER_COLUMN_ORDER: Column[] = [
  69. {
  70. key: SpanIndexedField.ID,
  71. name: t('Span ID'),
  72. width: 150,
  73. },
  74. {
  75. key: SpanIndexedField.MESSAGING_MESSAGE_ID,
  76. name: t('Message ID'),
  77. width: COL_WIDTH_UNDEFINED,
  78. },
  79. {
  80. key: SpanIndexedField.MESSAGING_MESSAGE_BODY_SIZE,
  81. name: t('Message Size'),
  82. width: COL_WIDTH_UNDEFINED,
  83. },
  84. {
  85. key: SpanIndexedField.TRACE_STATUS,
  86. name: t('Status'),
  87. width: COL_WIDTH_UNDEFINED,
  88. },
  89. ];
  90. interface Props {
  91. data: DataRow[];
  92. isLoading: boolean;
  93. type: MessageActorType;
  94. error?: Error | null;
  95. highlightedSpanId?: string;
  96. meta?: EventsMetaType;
  97. onSampleMouseOut?: ComponentProps<typeof GridEditable>['onRowMouseOut'];
  98. onSampleMouseOver?: ComponentProps<typeof GridEditable>['onRowMouseOver'];
  99. }
  100. export function MessageSpanSamplesTable({
  101. data,
  102. isLoading,
  103. error,
  104. meta,
  105. onSampleMouseOver,
  106. onSampleMouseOut,
  107. highlightedSpanId,
  108. type,
  109. }: Props) {
  110. const location = useLocation();
  111. const organization = useOrganization();
  112. return (
  113. <GridEditable
  114. aria-label={t('Span Samples')}
  115. isLoading={isLoading}
  116. error={error}
  117. data={data}
  118. columnOrder={
  119. type === MessageActorType.PRODUCER ? PRODUCER_COLUMN_ORDER : CONSUMER_COLUMN_ORDER
  120. }
  121. columnSortBy={[]}
  122. grid={{
  123. renderHeadCell: col =>
  124. renderHeadCell({
  125. column: col,
  126. location,
  127. }),
  128. renderBodyCell: (column, row) =>
  129. renderBodyCell(column, row, meta, location, organization),
  130. }}
  131. highlightedRowKey={data.findIndex(row => row.span_id === highlightedSpanId)}
  132. onRowMouseOver={onSampleMouseOver}
  133. onRowMouseOut={onSampleMouseOut}
  134. location={location}
  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. />
  163. );
  164. }
  165. if (!meta?.fields) {
  166. return row[column.key];
  167. }
  168. const renderer = getFieldRenderer(column.key, meta.fields, false);
  169. return renderer(row, {
  170. location,
  171. organization,
  172. unit: meta.units?.[column.key],
  173. });
  174. }
  175. const AlignRight = styled('span')`
  176. text-align: right;
  177. `;
  178. const NoValue = styled('span')`
  179. color: ${p => p.theme.gray300};
  180. `;