anomaliesQuery.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. import {EventsStatsData, Organization} from 'sentry/types';
  2. import GenericDiscoverQuery, {
  3. DiscoverQueryProps,
  4. GenericChildrenProps,
  5. } from 'sentry/utils/discover/genericDiscoverQuery';
  6. import withApi from 'sentry/utils/withApi';
  7. import {ANOMALY_FLAG} from 'sentry/views/performance/transactionSummary/transactionAnomalies/utils';
  8. type AnomaliesProps = {};
  9. type RequestProps = DiscoverQueryProps & AnomaliesProps;
  10. export type ChildrenProps = Omit<GenericChildrenProps<AnomaliesProps>, 'tableData'> & {
  11. data: AnomalyPayload | null;
  12. };
  13. type Props = Omit<RequestProps, 'orgSlug'> & {
  14. children: (props: ChildrenProps) => React.ReactNode;
  15. organization: Organization;
  16. };
  17. export type AnomalyConfidence = 'high' | 'low';
  18. // Should match events stats data in format.
  19. type AnomalyStatsData = {
  20. data: EventsStatsData;
  21. end?: number;
  22. start?: number;
  23. };
  24. // Anomaly info describes what the anomaly service determines is an 'anomaly area'.
  25. export type AnomalyInfo = {
  26. confidence: AnomalyConfidence;
  27. end: number;
  28. expected: number;
  29. id: string;
  30. received: number;
  31. start: number;
  32. };
  33. export type AnomalyPayload = {
  34. anomalies: AnomalyInfo[];
  35. y: AnomalyStatsData;
  36. yhat_lower: AnomalyStatsData;
  37. yhat_upper: AnomalyStatsData;
  38. };
  39. function transformStatsTimes(stats: AnomalyStatsData) {
  40. stats.data.forEach(d => (d[0] = d[0] * 1000));
  41. return stats;
  42. }
  43. function transformAnomaliesTimes(anoms: AnomalyInfo[]) {
  44. anoms.forEach(a => {
  45. a.start = a.start * 1000;
  46. a.end = a.end * 1000;
  47. });
  48. return anoms;
  49. }
  50. function transformPayload(payload: AnomalyPayload): AnomalyPayload {
  51. const newPayload = {...payload};
  52. if (!payload.y || !payload.yhat_lower || !payload.yhat_upper || !payload.anomalies) {
  53. return newPayload;
  54. }
  55. newPayload.y = transformStatsTimes(payload.y);
  56. newPayload.yhat_upper = transformStatsTimes(payload.yhat_upper);
  57. newPayload.yhat_lower = transformStatsTimes(payload.yhat_lower);
  58. newPayload.anomalies = transformAnomaliesTimes(payload.anomalies);
  59. return newPayload;
  60. }
  61. function AnomaliesSeriesQuery(props: Props) {
  62. if (!props.organization.features.includes(ANOMALY_FLAG)) {
  63. return (
  64. <div>
  65. {props.children({data: null, isLoading: false, error: null, pageLinks: null})}
  66. </div>
  67. );
  68. }
  69. return (
  70. <GenericDiscoverQuery<AnomalyPayload, {}>
  71. route="transaction-anomaly-detection"
  72. {...props}
  73. >
  74. {({tableData, ...rest}) => {
  75. return props.children({
  76. data: tableData && tableData.y ? transformPayload(tableData) : null,
  77. ...rest,
  78. });
  79. }}
  80. </GenericDiscoverQuery>
  81. );
  82. }
  83. export default withApi(AnomaliesSeriesQuery);