fields.tsx 8.1 KB

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