projectIssueGrouping.tsx 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. import {Fragment} from 'react';
  2. import styled from '@emotion/styled';
  3. import {GroupingConfigItem} from 'sentry/components/events/groupingInfo';
  4. import {Field} from 'sentry/components/forms/types';
  5. import ExternalLink from 'sentry/components/links/externalLink';
  6. import {t, tct} from 'sentry/locale';
  7. import {space} from 'sentry/styles/space';
  8. import marked from 'sentry/utils/marked';
  9. // Export route to make these forms searchable by label/help
  10. export const route = '/settings/:orgId/projects/:projectId/issue-grouping/';
  11. const groupingConfigField: Field = {
  12. name: 'groupingConfig',
  13. type: 'select',
  14. label: t('Grouping Config'),
  15. saveOnBlur: false,
  16. saveMessageAlertType: 'info',
  17. saveMessage: t(
  18. 'Changing grouping config will apply to future events only (can take up to a minute).'
  19. ),
  20. selectionInfoFunction: args => {
  21. const {groupingConfigs, value} = args;
  22. const selection = groupingConfigs.find(({id}) => id === value);
  23. const changelog = selection?.changelog || '';
  24. if (!changelog) {
  25. return null;
  26. }
  27. return (
  28. <Changelog>
  29. <ChangelogTitle>
  30. {tct('New in version [version]', {version: selection.id})}:
  31. </ChangelogTitle>
  32. <div dangerouslySetInnerHTML={{__html: marked(changelog)}} />
  33. </Changelog>
  34. );
  35. },
  36. choices: ({groupingConfigs}) =>
  37. groupingConfigs.map(({id, hidden}) => [
  38. id.toString(),
  39. <GroupingConfigItem key={id} isHidden={hidden}>
  40. {id}
  41. </GroupingConfigItem>,
  42. ]),
  43. help: t('Sets the grouping algorithm to be used for new events.'),
  44. visible: ({features}) => features.has('set-grouping-config'),
  45. };
  46. export const fields: Record<string, Field> = {
  47. fingerprintingRules: {
  48. name: 'fingerprintingRules',
  49. type: 'string',
  50. label: t('Fingerprint Rules'),
  51. hideLabel: true,
  52. placeholder: t(
  53. 'error.type:MyException -> fingerprint-value\nstack.function:some_panic_function -> fingerprint-value'
  54. ),
  55. multiline: true,
  56. monospace: true,
  57. autosize: true,
  58. inline: false,
  59. maxRows: 20,
  60. saveOnBlur: false,
  61. saveMessageAlertType: 'info',
  62. saveMessage: t(
  63. 'Changing fingerprint rules will apply to future events only (can take up to a minute).'
  64. ),
  65. formatMessageValue: false,
  66. help: () => (
  67. <Fragment>
  68. <RuleDescription>
  69. {tct(
  70. `This can be used to modify the fingerprint rules on the server with custom rules.
  71. Rules follow the pattern [pattern]. To learn more about fingerprint rules, [docs:read the docs].`,
  72. {
  73. pattern: <code>matcher:glob -&gt; fingerprint, values</code>,
  74. docs: (
  75. <ExternalLink href="https://docs.sentry.io/product/data-management-settings/event-grouping/fingerprint-rules/" />
  76. ),
  77. }
  78. )}
  79. </RuleDescription>
  80. <RuleExample>
  81. {`# force all errors of the same type to have the same fingerprint
  82. error.type:DatabaseUnavailable -> system-down
  83. # force all memory allocation errors to be grouped together
  84. stack.function:malloc -> memory-allocation-error`}
  85. </RuleExample>
  86. </Fragment>
  87. ),
  88. visible: true,
  89. },
  90. groupingEnhancements: {
  91. name: 'groupingEnhancements',
  92. type: 'string',
  93. label: t('Stack Trace Rules'),
  94. hideLabel: true,
  95. placeholder: t(
  96. 'stack.function:raise_an_exception ^-group\nstack.function:namespace::* +app'
  97. ),
  98. multiline: true,
  99. monospace: true,
  100. autosize: true,
  101. inline: false,
  102. maxRows: 20,
  103. saveOnBlur: false,
  104. saveMessageAlertType: 'info',
  105. saveMessage: t(
  106. 'Changing stack trace rules will apply to future events only (can take up to a minute).'
  107. ),
  108. formatMessageValue: false,
  109. help: () => (
  110. <Fragment>
  111. <RuleDescription>
  112. {tct(
  113. `This can be used to enhance the grouping algorithm with custom rules.
  114. Rules follow the pattern [pattern]. To learn more about stack trace rules, [docs:read the docs].`,
  115. {
  116. pattern: <code>matcher:glob [v^]?[+-]flag</code>,
  117. docs: (
  118. <ExternalLink href="https://docs.sentry.io/product/data-management-settings/event-grouping/stack-trace-rules/" />
  119. ),
  120. }
  121. )}
  122. </RuleDescription>
  123. <RuleExample>
  124. {`# remove all frames above a certain function from grouping
  125. stack.function:panic_handler ^-group
  126. # mark all functions following a prefix in-app
  127. stack.function:mylibrary_* +app`}
  128. </RuleExample>
  129. </Fragment>
  130. ),
  131. validate: () => [],
  132. visible: true,
  133. },
  134. groupingConfig: groupingConfigField,
  135. secondaryGroupingConfig: {
  136. ...groupingConfigField,
  137. name: 'secondaryGroupingConfig',
  138. label: t('Fallback/Secondary Grouping Config'),
  139. help: t(
  140. 'Sets the secondary grouping algorithm that should be run in addition to avoid creating too many new groups. Controlled by expiration date below.'
  141. ),
  142. saveMessage: t(
  143. 'Changing the secondary grouping strategy will affect how many new issues are created.'
  144. ),
  145. },
  146. secondaryGroupingExpiry: {
  147. name: 'secondaryGroupingExpiry',
  148. type: 'number',
  149. label: t('Expiration date of secondary grouping'),
  150. help: t(
  151. 'If this UNIX timestamp is in the past, the secondary grouping configuration stops applying automatically.'
  152. ),
  153. saveOnBlur: false,
  154. saveMessageAlertType: 'info',
  155. saveMessage: t(
  156. 'Changing the expiration date will affect how many new issues are created.'
  157. ),
  158. },
  159. groupingAutoUpdate: {
  160. name: 'groupingAutoUpdate',
  161. type: 'boolean',
  162. label: t('Automatically Update Grouping'),
  163. saveOnBlur: false,
  164. help: t(
  165. 'When enabled projects will in the future automatically update to the latest grouping algorithm. Right now this setting does nothing.'
  166. ),
  167. saveMessage: ({value}) =>
  168. value
  169. ? t(
  170. 'Enabling automatic upgrading will take effect on the next incoming event once auto updating has been rolled out.'
  171. )
  172. : t(
  173. 'Disabling auto updates will cause you to no longer receive improvements to the grouping algorithm.'
  174. ),
  175. },
  176. };
  177. const RuleDescription = styled('div')`
  178. margin-bottom: ${space(1)};
  179. margin-top: -${space(1)};
  180. margin-right: 36px;
  181. `;
  182. const RuleExample = styled('pre')`
  183. margin-bottom: ${space(1)};
  184. margin-right: 36px;
  185. `;
  186. const Changelog = styled('div')`
  187. position: relative;
  188. top: -1px;
  189. margin-bottom: -1px;
  190. padding: ${space(2)};
  191. border-bottom: 1px solid ${p => p.theme.innerBorder};
  192. background: ${p => p.theme.backgroundSecondary};
  193. font-size: ${p => p.theme.fontSizeMedium};
  194. &:last-child {
  195. border: 0;
  196. border-bottom-left-radius: ${p => p.theme.borderRadius};
  197. border-bottom-right-radius: ${p => p.theme.borderRadius};
  198. }
  199. `;
  200. const ChangelogTitle = styled('h3')`
  201. font-size: ${p => p.theme.fontSizeMedium};
  202. margin-bottom: ${space(0.75)} !important;
  203. `;