events.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. import {
  2. BaseGroup,
  3. EventMetadata,
  4. EventOrGroupType,
  5. GroupTombstone,
  6. TreeLabelPart,
  7. } from 'sentry/types';
  8. import {Event} from 'sentry/types/event';
  9. import {isMobilePlatform, isNativePlatform} from 'sentry/utils/platform';
  10. function isTombstone(maybe: BaseGroup | Event | GroupTombstone): maybe is GroupTombstone {
  11. return !maybe.hasOwnProperty('type');
  12. }
  13. /**
  14. * Extract the display message from an event.
  15. */
  16. export function getMessage(
  17. event: Event | BaseGroup | GroupTombstone
  18. ): string | undefined {
  19. if (isTombstone(event)) {
  20. return event.culprit || '';
  21. }
  22. const {metadata, type, culprit} = event;
  23. switch (type) {
  24. case EventOrGroupType.ERROR:
  25. return metadata.value;
  26. case EventOrGroupType.CSP:
  27. return metadata.message;
  28. case EventOrGroupType.EXPECTCT:
  29. case EventOrGroupType.EXPECTSTAPLE:
  30. case EventOrGroupType.HPKP:
  31. return '';
  32. default:
  33. return culprit || '';
  34. }
  35. }
  36. /**
  37. * Get the location from an event.
  38. */
  39. export function getLocation(event: Event | BaseGroup | GroupTombstone) {
  40. if (isTombstone(event)) {
  41. return undefined;
  42. }
  43. if (event.type === EventOrGroupType.ERROR && isNativePlatform(event.platform)) {
  44. return event.metadata.filename || undefined;
  45. }
  46. return undefined;
  47. }
  48. export function getTreeLabelPartDetails(part: TreeLabelPart) {
  49. // Note: This function also exists in Python in eventtypes/base.py, to make
  50. // porting efforts simpler it's recommended to keep both variants
  51. // structurally similar.
  52. if (typeof part === 'string') {
  53. return part;
  54. }
  55. const label = part?.function || part?.package || part?.filebase || part?.type;
  56. const classbase = part?.classbase;
  57. if (classbase) {
  58. return label ? `${classbase}.${label}` : classbase;
  59. }
  60. return label || '<unknown>';
  61. }
  62. function computeTitleWithTreeLabel(metadata: EventMetadata) {
  63. const {type, current_tree_label, finest_tree_label} = metadata;
  64. const treeLabel = current_tree_label || finest_tree_label;
  65. const formattedTreeLabel = treeLabel
  66. ? treeLabel.map(labelPart => getTreeLabelPartDetails(labelPart)).join(' | ')
  67. : undefined;
  68. if (!type) {
  69. return {
  70. title: formattedTreeLabel || metadata.function || '<unknown>',
  71. treeLabel,
  72. };
  73. }
  74. if (!formattedTreeLabel) {
  75. return {title: type, treeLabel: undefined};
  76. }
  77. return {
  78. title: `${type} | ${formattedTreeLabel}`,
  79. treeLabel: [{type}, ...(treeLabel ?? [])],
  80. };
  81. }
  82. export function getTitle(
  83. event: Event | BaseGroup,
  84. features: string[] = [],
  85. grouping = false
  86. ) {
  87. const {metadata, type, culprit} = event;
  88. const customTitle =
  89. features.includes('custom-event-title') && metadata?.title
  90. ? metadata.title
  91. : undefined;
  92. switch (type) {
  93. case EventOrGroupType.ERROR: {
  94. if (customTitle) {
  95. return {
  96. title: customTitle,
  97. subtitle: culprit,
  98. treeLabel: undefined,
  99. };
  100. }
  101. const displayTitleWithTreeLabel =
  102. features.includes('grouping-title-ui') &&
  103. (grouping ||
  104. isNativePlatform(event.platform) ||
  105. isMobilePlatform(event.platform));
  106. if (displayTitleWithTreeLabel) {
  107. return {
  108. subtitle: culprit,
  109. ...computeTitleWithTreeLabel(metadata),
  110. };
  111. }
  112. return {
  113. subtitle: culprit,
  114. title: metadata.type || metadata.function || '<unknown>',
  115. treeLabel: undefined,
  116. };
  117. }
  118. case EventOrGroupType.CSP:
  119. return {
  120. title: customTitle ?? metadata.directive ?? '',
  121. subtitle: metadata.uri ?? '',
  122. treeLabel: undefined,
  123. };
  124. case EventOrGroupType.EXPECTCT:
  125. case EventOrGroupType.EXPECTSTAPLE:
  126. case EventOrGroupType.HPKP:
  127. // Due to a regression some reports did not have message persisted
  128. // (https://github.com/getsentry/sentry/pull/19794) so we need to fall
  129. // back to the computed title for these.
  130. return {
  131. title: customTitle ?? (metadata.message || event.title),
  132. subtitle: metadata.origin ?? '',
  133. treeLabel: undefined,
  134. };
  135. case EventOrGroupType.DEFAULT:
  136. return {
  137. title: customTitle ?? metadata.title ?? '',
  138. subtitle: '',
  139. treeLabel: undefined,
  140. };
  141. default:
  142. return {
  143. title: customTitle ?? event.title,
  144. subtitle: '',
  145. treeLabel: undefined,
  146. };
  147. }
  148. }
  149. /**
  150. * Returns a short eventId with only 8 characters
  151. */
  152. export function getShortEventId(eventId: string) {
  153. return eventId.substring(0, 8);
  154. }