fields.tsx 7.6 KB

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