fields.tsx 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import invert from 'lodash/invert';
  2. import type {
  3. SelectValue,
  4. SessionAggregationColumn,
  5. SessionsMeta,
  6. SessionsOperation,
  7. } from 'sentry/types';
  8. import {SessionField, SessionStatus} from 'sentry/types';
  9. import {defined} from 'sentry/utils';
  10. import type {FieldValue} from 'sentry/views/discover/table/types';
  11. import {FieldValueKind} from 'sentry/views/discover/table/types';
  12. enum SessionMetric {
  13. ANR_RATE = 'session.anr_rate',
  14. FOREGROUND_ANR_RATE = 'session.foreground_anr_rate',
  15. SESSION_COUNT = 'session.all',
  16. SESSION_DURATION = 'sentry.sessions.session.duration',
  17. SESSION_ERROR = 'sentry.sessions.session.error',
  18. SESSION_CRASH_FREE_RATE = 'session.crash_free_rate',
  19. USER_CRASH_FREE_RATE = 'session.crash_free_user_rate',
  20. SESSION_CRASH_RATE = 'session.crash_rate',
  21. USER_CRASH_RATE = 'session.crash_user_rate',
  22. USER = 'sentry.sessions.user',
  23. SESSION_HEALTHY = 'session.healthy',
  24. USER_HEALTHY = 'session.healthy_user',
  25. SESSION_ABNORMAL = 'session.abnormal',
  26. USER_ABNORMAL = 'session.abnormal_user',
  27. SESSION_CRASHED = 'session.crashed',
  28. USER_CRASHED = 'session.crashed_user',
  29. SESSION_ERRORED = 'session.errored',
  30. USER_ERRORED = 'session.errored_user',
  31. }
  32. export const DERIVED_STATUS_METRICS_PATTERN =
  33. /count_(abnormal|errored|crashed|healthy)\((user|session)\)/;
  34. export enum DerivedStatusFields {
  35. HEALTHY_SESSIONS = 'count_healthy(session)',
  36. HEALTHY_USERS = 'count_healthy(user)',
  37. ABNORMAL_SESSIONS = 'count_abnormal(session)',
  38. ABNORMAL_USERS = 'count_abnormal(user)',
  39. CRASHED_SESSIONS = 'count_crashed(session)',
  40. CRASHED_USERS = 'count_crashed(user)',
  41. ERRORED_SESSIONS = 'count_errored(session)',
  42. ERRORED_USERS = 'count_errored(user)',
  43. }
  44. export const FIELD_TO_METRICS_EXPRESSION = {
  45. 'foreground_anr_rate()': SessionMetric.FOREGROUND_ANR_RATE,
  46. 'anr_rate()': SessionMetric.ANR_RATE,
  47. 'count_healthy(session)': SessionMetric.SESSION_HEALTHY,
  48. 'count_healthy(user)': SessionMetric.USER_HEALTHY,
  49. 'count_abnormal(session)': SessionMetric.SESSION_ABNORMAL,
  50. 'count_abnormal(user)': SessionMetric.USER_ABNORMAL,
  51. 'count_crashed(session)': SessionMetric.SESSION_CRASHED,
  52. 'count_crashed(user)': SessionMetric.USER_CRASHED,
  53. 'count_errored(session)': SessionMetric.SESSION_ERRORED,
  54. 'count_errored(user)': SessionMetric.USER_ERRORED,
  55. 'count_unique(user)': `count_unique(${SessionMetric.USER})`,
  56. 'sum(session)': SessionMetric.SESSION_COUNT,
  57. 'crash_free_rate(session)': SessionMetric.SESSION_CRASH_FREE_RATE,
  58. 'crash_free_rate(user)': SessionMetric.USER_CRASH_FREE_RATE,
  59. 'crash_rate(session)': SessionMetric.SESSION_CRASH_RATE,
  60. 'crash_rate(user)': SessionMetric.USER_CRASH_RATE,
  61. project: 'project_id',
  62. };
  63. export const METRICS_EXPRESSION_TO_FIELD = invert(FIELD_TO_METRICS_EXPRESSION);
  64. export const DISABLED_SORT = [
  65. 'count_errored(session)',
  66. 'count_errored(user)',
  67. 'count_healthy(session)',
  68. 'count_healthy(user)',
  69. 'session.status',
  70. ];
  71. export const TAG_SORT_DENY_LIST = ['project', 'environment'];
  72. export const SESSIONS_FIELDS: Readonly<Partial<Record<SessionField, SessionsMeta>>> = {
  73. [SessionField.SESSION]: {
  74. name: 'session',
  75. operations: [
  76. 'sum',
  77. 'crash_rate',
  78. 'crash_free_rate',
  79. 'count_healthy',
  80. 'count_abnormal',
  81. 'count_crashed',
  82. 'count_errored',
  83. 'anr_rate',
  84. 'foreground_anr_rate',
  85. ],
  86. type: 'integer',
  87. },
  88. [SessionField.USER]: {
  89. name: 'user',
  90. operations: [
  91. 'count_unique',
  92. 'crash_rate',
  93. 'crash_free_rate',
  94. 'count_healthy',
  95. 'count_abnormal',
  96. 'count_crashed',
  97. 'count_errored',
  98. ],
  99. type: 'string',
  100. },
  101. [SessionField.SESSION_DURATION]: {
  102. name: 'session.duration',
  103. operations: [],
  104. type: 'duration',
  105. },
  106. };
  107. export const SESSIONS_OPERATIONS: Readonly<
  108. Record<SessionsOperation, SessionAggregationColumn>
  109. > = {
  110. anr_rate: {
  111. outputType: 'percentage',
  112. parameters: [],
  113. },
  114. foreground_anr_rate: {
  115. outputType: 'percentage',
  116. parameters: [],
  117. },
  118. sum: {
  119. outputType: 'integer',
  120. parameters: [
  121. {
  122. kind: 'column',
  123. columnTypes: ['integer'],
  124. defaultValue: SessionField.SESSION,
  125. required: true,
  126. },
  127. ],
  128. },
  129. count_unique: {
  130. outputType: 'integer',
  131. parameters: [
  132. {
  133. kind: 'column',
  134. columnTypes: ['string'],
  135. defaultValue: SessionField.USER,
  136. required: true,
  137. },
  138. ],
  139. },
  140. count_healthy: {
  141. outputType: 'integer',
  142. parameters: [
  143. {
  144. kind: 'column',
  145. columnTypes: ['integer', 'string'],
  146. defaultValue: SessionField.SESSION,
  147. required: true,
  148. },
  149. ],
  150. },
  151. count_abnormal: {
  152. outputType: 'integer',
  153. parameters: [
  154. {
  155. kind: 'column',
  156. columnTypes: ['integer', 'string'],
  157. defaultValue: SessionField.SESSION,
  158. required: true,
  159. },
  160. ],
  161. },
  162. count_crashed: {
  163. outputType: 'integer',
  164. parameters: [
  165. {
  166. kind: 'column',
  167. columnTypes: ['integer', 'string'],
  168. defaultValue: SessionField.SESSION,
  169. required: true,
  170. },
  171. ],
  172. },
  173. count_errored: {
  174. outputType: 'integer',
  175. parameters: [
  176. {
  177. kind: 'column',
  178. columnTypes: ['integer', 'string'],
  179. defaultValue: SessionField.SESSION,
  180. required: true,
  181. },
  182. ],
  183. },
  184. crash_rate: {
  185. outputType: 'percentage',
  186. parameters: [
  187. {
  188. kind: 'column',
  189. columnTypes: ['integer', 'string'],
  190. defaultValue: SessionField.SESSION,
  191. required: true,
  192. },
  193. ],
  194. },
  195. crash_free_rate: {
  196. outputType: 'percentage',
  197. parameters: [
  198. {
  199. kind: 'column',
  200. columnTypes: ['integer', 'string'],
  201. defaultValue: SessionField.SESSION,
  202. required: true,
  203. },
  204. ],
  205. },
  206. };
  207. export const SESSIONS_TAGS = ['environment', 'project', 'release', 'session.status'];
  208. export const SESSIONS_FILTER_TAGS = ['environment', 'project', 'release'];
  209. export const SESSION_STATUSES = Object.values(SessionStatus);
  210. export function generateReleaseWidgetFieldOptions(
  211. fields: SessionsMeta[] = Object.values(SESSIONS_FIELDS),
  212. tagKeys?: string[]
  213. ) {
  214. const fieldOptions: Record<string, SelectValue<FieldValue>> = {};
  215. const operations = new Set<SessionsOperation>();
  216. const knownOperations = Object.keys(SESSIONS_OPERATIONS);
  217. fields
  218. .sort((a, b) => a.name.localeCompare(b.name))
  219. .forEach(field => {
  220. field.operations.forEach(operation => operations.add(operation));
  221. fieldOptions[`field:${field.name}`] = {
  222. label: field.name,
  223. value: {
  224. kind: FieldValueKind.METRICS,
  225. meta: {
  226. name: field.name,
  227. dataType: field.type,
  228. },
  229. },
  230. };
  231. });
  232. Array.from(operations)
  233. .filter(operation => knownOperations.includes(operation))
  234. .sort((a, b) => a.localeCompare(b))
  235. .forEach(operation => {
  236. fieldOptions[`function:${operation}`] = {
  237. label: `${operation}(${'\u2026'})`,
  238. value: {
  239. kind: FieldValueKind.FUNCTION,
  240. meta: {
  241. name: operation,
  242. parameters: SESSIONS_OPERATIONS[operation].parameters.map(param => param),
  243. },
  244. },
  245. };
  246. });
  247. if (defined(tagKeys)) {
  248. // Expose environment. session.status, project etc. as fields.
  249. tagKeys
  250. .sort((a, b) => a.localeCompare(b))
  251. .forEach(tag => {
  252. fieldOptions[`field:${tag}`] = {
  253. label: tag,
  254. value: {
  255. kind: FieldValueKind.FIELD,
  256. meta: {name: tag, dataType: 'string'},
  257. },
  258. };
  259. });
  260. }
  261. return fieldOptions;
  262. }