getReasonGroupName.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. import {Outcome} from 'sentry/types/core';
  2. // List of Relay's current invalid reasons - https://github.com/getsentry/relay/blob/89a8dd7caaad1f126e1cacced0d73bb50fcd4f5a/relay-server/src/services/outcome.rs#L333
  3. enum DiscardReason {
  4. DUPLICATE = 'duplicate',
  5. PROJECT_ID = 'project_id',
  6. AUTH_VERSION = 'auth_version',
  7. AUTH_CLIENT = 'auth_client',
  8. NO_DATA = 'no_data',
  9. DISALLOWED_METHOD = 'disallowed_method',
  10. CONTENT_TYPE = 'content_type',
  11. INVALID_MULTIPART = 'invalid_multipart',
  12. INVALID_MSGPACK = 'invalid_msgpack',
  13. INVALID_JSON = 'invalid_json',
  14. INVALID_ENVELOPE = 'invalid_envelope',
  15. TIMESTAMP = 'timestamp',
  16. DUPLICATE_ITEM = 'duplicate_item',
  17. INVALID_TRANSACTION = 'invalid_transaction',
  18. INVALID_SPAN = 'invalid_span',
  19. INVALID_REPLAY = 'invalid_replay',
  20. INVALID_REPLAY_RECORDING = 'invalid_replay_recording',
  21. INVALID_REPLAY_VIDEO = 'invalid_replay_video',
  22. PAYLOAD = 'payload',
  23. INVALID_COMPRESSION = 'invalid_compression',
  24. TOO_LARGE = 'too_large',
  25. MISSING_MINIDUMP_UPLOAD = 'missing_minidump_upload',
  26. INVALID_MINIDUMP = 'invalid_minidump',
  27. SECURITY_REPORT = 'security_report',
  28. SECURITY_REPORT_TYPE = 'security_report_type',
  29. PROCESS_UNREAL = 'process_unreal',
  30. CORS = 'cors',
  31. NO_EVENT_PAYLOAD = 'no_event_payload',
  32. EMPTY_ENVELOPE = 'empty_envelope',
  33. INVALID_REPLAY_NO_PAYLOAD = 'invalid_replay_no_payload',
  34. TRANSACTION_SAMPLED = 'transaction_sampled',
  35. INTERNAL = 'internal',
  36. MULTI_PROJECT_ID = 'multi_project_id',
  37. PROJECT_STATE = 'project_state',
  38. PROJECT_STATE_PII = 'project_state_pii',
  39. INVALID_REPLAY_PII_SCRUBBER_FAILED = 'invalid_replay_pii_scrubber_failed',
  40. FEATURE_DISABLED = 'feature_disabled',
  41. }
  42. // List of Relay's current filtered reasons - https://github.com/getsentry/relay/blob/ce5520b4a3bea022808982a52a66bfddacc70ac0/relay-filter/src/common.rs#L11
  43. enum FilteredReason {
  44. BROWSER_EXTENSION = 'browser-extensions',
  45. DENIED_NAME = 'denied-name',
  46. DISABLED_NAMESPACE = 'disabled-namespace',
  47. ERROR_MESSAGE = 'error-message',
  48. FILTERED_TRANSACTION = 'filtered-transaction',
  49. INVALID_CSP = 'invalid-csp',
  50. IP_ADDRESS = 'ip-address',
  51. LEGACY_BROWSER = 'legacy-browsers',
  52. LOCALHOST = 'localhost',
  53. RELEASE_VERSION = 'release-version',
  54. WEB_CRAWLER = 'web-crawlers',
  55. }
  56. // List of Client Discard Reason according to the Client Report's doc - https://develop.sentry.dev/sdk/client-reports/#envelope-item-payload
  57. enum ClientDiscardReason {
  58. QUEUE_OVERFLOW = 'queue_overflow',
  59. CACHE_OVERFLOW = 'cache_overflow',
  60. RATELIMIT_BACKOFF = 'ratelimit_backoff',
  61. NETWORK_ERROR = 'network_error',
  62. SAMPLE_RATE = 'sample_rate',
  63. BEFORE_SEND = 'before_send',
  64. EVENT_PROCESSSOR = 'event_processor',
  65. SEND_ERROR = 'send_error',
  66. INTERNAL_SDK_ERROR = 'internal_sdk_error',
  67. INSUFFICIENT_DATA = 'insufficient_data',
  68. BACKPRESSURE = 'backpressure',
  69. }
  70. enum RateLimitedReason {
  71. PROJECT_QUOTA = 'project_quota',
  72. ORG_QUOTA = 'org_quota',
  73. KEY_QUOTA = 'key_quota',
  74. SPIKE_PROTECTION = 'spike_protection',
  75. SMART_RATE_LIMIT = 'smart_rate_limit',
  76. }
  77. // Invalid reasons should not be exposed directly, but instead in the following groups:
  78. const invalidReasonsGroup: Record<string, DiscardReason[]> = {
  79. duplicate: [DiscardReason.DUPLICATE],
  80. project_missing: [DiscardReason.PROJECT_ID],
  81. invalid_request: [
  82. DiscardReason.AUTH_VERSION,
  83. DiscardReason.AUTH_CLIENT,
  84. DiscardReason.NO_DATA,
  85. DiscardReason.DISALLOWED_METHOD,
  86. DiscardReason.CONTENT_TYPE,
  87. DiscardReason.INVALID_MULTIPART,
  88. DiscardReason.INVALID_MSGPACK,
  89. DiscardReason.INVALID_JSON,
  90. DiscardReason.INVALID_ENVELOPE,
  91. DiscardReason.TIMESTAMP,
  92. DiscardReason.DUPLICATE_ITEM,
  93. ],
  94. invalid_data: [
  95. DiscardReason.INVALID_TRANSACTION,
  96. DiscardReason.INVALID_SPAN,
  97. DiscardReason.INVALID_REPLAY,
  98. DiscardReason.INVALID_REPLAY_RECORDING,
  99. DiscardReason.INVALID_REPLAY_VIDEO,
  100. ],
  101. payload: [DiscardReason.PAYLOAD, DiscardReason.INVALID_COMPRESSION],
  102. too_large: [DiscardReason.TOO_LARGE],
  103. minidump: [DiscardReason.MISSING_MINIDUMP_UPLOAD, DiscardReason.INVALID_MINIDUMP],
  104. security_report: [DiscardReason.SECURITY_REPORT, DiscardReason.SECURITY_REPORT_TYPE],
  105. unreal: [DiscardReason.PROCESS_UNREAL],
  106. cors: [DiscardReason.CORS],
  107. empty: [
  108. DiscardReason.NO_EVENT_PAYLOAD,
  109. DiscardReason.EMPTY_ENVELOPE,
  110. DiscardReason.INVALID_REPLAY_NO_PAYLOAD,
  111. ],
  112. sampling: [DiscardReason.TRANSACTION_SAMPLED],
  113. };
  114. function getInvalidReasonGroupName(reason: DiscardReason): string {
  115. for (const [group, reasons] of Object.entries(invalidReasonsGroup)) {
  116. if (reasons.includes(reason)) {
  117. return group;
  118. }
  119. }
  120. return 'internal';
  121. }
  122. function getRateLimitedReasonGroupName(reason: RateLimitedReason | string): string {
  123. if (reason.endsWith('_usage_exceeded')) {
  124. return 'quota';
  125. }
  126. if (reason.endsWith('_disabled')) {
  127. return 'disabled';
  128. }
  129. switch (reason) {
  130. case RateLimitedReason.ORG_QUOTA:
  131. case RateLimitedReason.PROJECT_QUOTA:
  132. return 'global limit';
  133. case RateLimitedReason.KEY_QUOTA:
  134. return 'DSN limit';
  135. case RateLimitedReason.SPIKE_PROTECTION:
  136. case RateLimitedReason.SMART_RATE_LIMIT:
  137. return 'spike protection';
  138. default:
  139. return 'internal';
  140. }
  141. }
  142. function getFilteredReasonGroupName(reason: FilteredReason): string {
  143. switch (reason) {
  144. case FilteredReason.BROWSER_EXTENSION:
  145. case FilteredReason.ERROR_MESSAGE:
  146. case FilteredReason.FILTERED_TRANSACTION:
  147. case FilteredReason.INVALID_CSP:
  148. case FilteredReason.IP_ADDRESS:
  149. case FilteredReason.LEGACY_BROWSER:
  150. case FilteredReason.LOCALHOST:
  151. case FilteredReason.RELEASE_VERSION:
  152. case FilteredReason.WEB_CRAWLER:
  153. return reason;
  154. default:
  155. return 'other';
  156. }
  157. }
  158. function getClientDiscardReasonGroupName(reason: ClientDiscardReason): string {
  159. switch (reason) {
  160. case ClientDiscardReason.QUEUE_OVERFLOW:
  161. case ClientDiscardReason.CACHE_OVERFLOW:
  162. case ClientDiscardReason.RATELIMIT_BACKOFF:
  163. case ClientDiscardReason.NETWORK_ERROR:
  164. case ClientDiscardReason.SAMPLE_RATE:
  165. case ClientDiscardReason.BEFORE_SEND:
  166. case ClientDiscardReason.EVENT_PROCESSSOR:
  167. case ClientDiscardReason.SEND_ERROR:
  168. case ClientDiscardReason.INTERNAL_SDK_ERROR:
  169. case ClientDiscardReason.INSUFFICIENT_DATA:
  170. case ClientDiscardReason.BACKPRESSURE:
  171. return reason;
  172. default:
  173. return 'other';
  174. }
  175. }
  176. export function getReasonGroupName(outcome: string | number, reason: string): string {
  177. switch (outcome) {
  178. case Outcome.INVALID:
  179. return getInvalidReasonGroupName(reason as DiscardReason);
  180. case Outcome.CARDINALITY_LIMITED:
  181. case Outcome.RATE_LIMITED:
  182. case Outcome.ABUSE:
  183. return getRateLimitedReasonGroupName(reason as RateLimitedReason);
  184. case Outcome.FILTERED:
  185. return getFilteredReasonGroupName(reason as FilteredReason);
  186. case Outcome.CLIENT_DISCARD:
  187. return getClientDiscardReasonGroupName(reason as ClientDiscardReason);
  188. default:
  189. return String(reason);
  190. }
  191. }