Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anomaly detection): add anomaly chart preview to new alert #78238

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

natemoo-re
Copy link
Member

@natemoo-re natemoo-re commented Sep 26, 2024

Adds anomaly chart visualization to new alert form (ruleForm.tsx + <TriggersChart />).

Related PRs:

Closes https://getsentry.atlassian.net/browse/ALRT-289

@github-actions github-actions bot added the Scope: Frontend Automatically applied to PRs that change frontend components label Sep 26, 2024
Copy link

codecov bot commented Sep 26, 2024

❌ 7 Tests Failed:

Tests completed Failed Passed Skipped
7945 7 7938 0
View the top 3 failed tests by shortest run time
Incident Rules Create queries insights metrics using the metricsEnhanced dataset and without the metrics layer Incident Rules Create queries insights metrics using the metricsEnhanced dataset and without the metrics layer
Stack Traces | 0.064s run time
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: Anything, ObjectContaining {&quot;query&quot;: {&quot;dataset&quot;: &quot;metricsEnhanced&quot;, &quot;forceMetricsLayer&quot;: undefined, &quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;span.module:db&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;9998m&quot;, &quot;yAxis&quot;: &quot;spm()&quot;}}
Received: &quot;.../organizations/org-slug/events-stats/&quot;, {&quot;error&quot;: [Function error], &quot;query&quot;: {&quot;dataset&quot;: &quot;metricsEnhanced&quot;, &quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;span.module:db&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;7d&quot;, &quot;yAxis&quot;: &quot;spm()&quot;}, &quot;success&quot;: [Function success]}

Number of calls: 1
    at Object.&lt;anonymous&gt; (.../triggers/chart/index.spec.tsx:247:28)
Incident Rules Create does not show &amp; query total count if showTotalCount === false Incident Rules Create does not show &amp; query total count if showTotalCount === false
Stack Traces | 0.073s run time
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: Anything, ObjectContaining {&quot;query&quot;: {&quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;event.type:error&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;9998m&quot;, &quot;yAxis&quot;: &quot;count()&quot;}}
Received: &quot;.../organizations/org-slug/events-stats/&quot;, {&quot;error&quot;: [Function error], &quot;query&quot;: {&quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;event.type:error&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;7d&quot;, &quot;yAxis&quot;: &quot;count()&quot;}, &quot;success&quot;: [Function success]}

Number of calls: 1
    at Object.&lt;anonymous&gt; (.../triggers/chart/index.spec.tsx:101:28)
Incident Rules Create queries custom metrics using the metricsEnhanced dataset and metrics layer Incident Rules Create queries custom metrics using the metricsEnhanced dataset and metrics layer
Stack Traces | 0.084s run time
Error: expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: Anything, ObjectContaining {&quot;query&quot;: {&quot;dataset&quot;: &quot;metricsEnhanced&quot;, &quot;forceMetricsLayer&quot;: &quot;true&quot;, &quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;9998m&quot;, &quot;yAxis&quot;: &quot;count(d:custom/my_metric@seconds)&quot;}}
Received: &quot;.../organizations/org-slug/events-stats/&quot;, {&quot;error&quot;: [Function error], &quot;query&quot;: {&quot;dataset&quot;: &quot;metricsEnhanced&quot;, &quot;forceMetricsLayer&quot;: &quot;true&quot;, &quot;interval&quot;: &quot;1m&quot;, &quot;project&quot;: [2], &quot;query&quot;: &quot;&quot;, &quot;referrer&quot;: &quot;api.organization-event-stats&quot;, &quot;statsPeriod&quot;: &quot;7d&quot;, &quot;yAxis&quot;: &quot;count(d:custom/my_metric@seconds)&quot;}, &quot;success&quot;: [Function success]}

Number of calls: 1
    at Object.&lt;anonymous&gt; (.../triggers/chart/index.spec.tsx:203:28)

To view individual test run time comparison to the main branch, go to the Test Analytics Dashboard

@natemoo-re natemoo-re force-pushed the natemoo-re/anomaly-detection-charts branch from 88f76fd to 48c5e4d Compare October 8, 2024 20:51
Copy link
Contributor

@saponifi3d saponifi3d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mostly just comments about the prop drilling for anomalies and hoping we can create a context. if that's out of scope and want to take it on with ACI, that's cool too.

const firstPoint = new Date(dataArr[0]?.name).getTime();
const lastPoint = new Date(dataArr[dataArr.length - 1]?.name).getTime();
const startDate = new Date(dataArr[0]?.name);
const endDate = new Date(dataArr[dataArr.length - 1]?.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to do any status checks to ensure that dataArr[dataArr.length - 1]?.name isn't the same value as dataArr[0]?.name?

silent: true, // potentially don't make this silent if we want to render the `anomaly detected` in the tooltip
data: anomalyBlocks,
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 - nice.

@@ -144,6 +149,8 @@ type State = {
triggerErrors: Map<number, {[fieldName: string]: string}>;
triggers: Trigger[];
activationCondition?: ActivationConditionType;
chartError?: boolean;
chartErrorMessage?: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 should we add a context to maintain more of these props? (it's also cool if we don't, and plan to refactor this stuff when we get to ACI work)

@@ -931,6 +956,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
seasonality: AlertRuleSeasonality.AUTO,
};
break;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: omit the {}s for consistency with the other switches - we should probably ensure there's a lint rule one way or the other.

includeTimeAggregation: false,
includeTransformedData: false,
limit: 15,
children: noop,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are the components using these props, using children as a renderProp? (could we just pass null instead?)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is decidedly not clean—I think the ideal end state here (after ACI) is that these declarative *Request components go away.

They're already deprecated so I don't want to invest too much in cleaning this up.

@@ -447,32 +465,165 @@ class TriggersChart extends PureComponent<Props, State> {
};

if (isOnDemandMetricAlert) {
const {sampleRate} = this.state;
const baseProps: EventsRequestProps = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we change these baseProps to provide to a context? That way we could decompose all of these sub components fairly easily. I'm a bit nervous about the complexity of this component and being able to grok it.

@@ -63,6 +66,7 @@ import ThresholdsChart from './thresholdsChart';

type Props = {
aggregate: MetricRule['aggregate'];
anomalies: Anomaly[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'd kinda expect these to be loaded as something else into the Chart component (rather than anomalies). something more like a generic for data or something along those lines? 🤔

@@ -28,6 +30,7 @@ import type {MetricRule, Trigger} from '../../types';
import {AlertRuleThresholdType, AlertRuleTriggerType} from '../../types';

type DefaultProps = {
anomalies: Anomaly[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be nice to create a context just for anomalies so we can avoid prop drilling

@@ -0,0 +1,154 @@
import type {MarkAreaComponentOption} from 'echarts';
import moment from 'moment-timezone';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk how kosher this is, but it might be nice to use built in Intl / Datetime stuff rather than moment 😅

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah dropping moment would be great! Going to punt on that until frontend tsc makes some decisions on https://github.com/getsentry/frontend-tsc/issues/69

// Seven days is actually 10080m but Snuba can only return up to 10000 entries, for this
// we approximate to 9998m which prevents rounding errors due to the minutes granularity
// limitations.
SEVEN_DAYS = '9998m',
SEVEN_DAYS = '7d',
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is what's breaking the tests currently. Can try to add more hacks to workaround the limitation, but probably worth asking if this is still needed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 about asking, unfortunately I don't have context over it.

Copy link
Contributor

@saponifi3d saponifi3d left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JS / reasoning behind implementation sounds good to me - i'd recommend having someone on anomaly detection do a quick pass to make sure the UI / features are working as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scope: Frontend Automatically applied to PRs that change frontend components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants