messageSpanSamplesTable.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 {SpanIndexedResponse} 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<SpanIndexedResponse, 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('Span Duration'),
  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. />
  135. );
  136. }
  137. function renderBodyCell(
  138. column: Column,
  139. row: DataRow,
  140. meta: EventsMetaType | undefined,
  141. location: Location,
  142. organization: Organization
  143. ) {
  144. const key = column.key;
  145. if (row[key] === undefined) {
  146. return (
  147. <AlignRight>
  148. <NoValue>{' \u2014 '}</NoValue>
  149. </AlignRight>
  150. );
  151. }
  152. if (key === SpanIndexedField.ID) {
  153. return (
  154. <SpanIdCell
  155. moduleName={ModuleName.QUEUE}
  156. projectSlug={row.project}
  157. traceId={row.trace}
  158. timestamp={row.timestamp}
  159. transactionId={row[SpanIndexedField.TRANSACTION_ID]}
  160. spanId={row[SpanIndexedField.ID]}
  161. />
  162. );
  163. }
  164. if (!meta?.fields) {
  165. return row[column.key];
  166. }
  167. const renderer = getFieldRenderer(column.key, meta.fields, false);
  168. return renderer(row, {
  169. location,
  170. organization,
  171. unit: meta.units?.[column.key],
  172. });
  173. }
  174. const AlignRight = styled('span')`
  175. text-align: right;
  176. `;
  177. const NoValue = styled('span')`
  178. color: ${p => p.theme.gray300};
  179. `;