Skip to content

Commit

Permalink
wip: add anomaly support to alert create form
Browse files Browse the repository at this point in the history
  • Loading branch information
natemoo-re committed Sep 26, 2024
1 parent 51ca36f commit f9b0916
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 2 deletions.
18 changes: 18 additions & 0 deletions static/app/views/alerts/rules/metric/ruleForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,24 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
dataset,
alertType,
isQueryValid,
// sensitivity,
// seasonality
} = this.state;
// const params = {
// organization_id: organization.id,
// project_id: project.id,
// config: {
// time_period: timeWindow,
// sensitivity,
// direction: thresholdType,
// expected_seasonality: seasonality
// },
// context: {
// history: [],
// current: []
// }
// }
// console.log('renderTriggerChart', { params });

const isOnDemand = isOnDemandMetricAlert(dataset, aggregate, query);

Expand All @@ -1065,6 +1082,7 @@ class RuleFormContainer extends DeprecatedAsyncComponent<Props, State> {
aggregate,
formattedAggregate: formattedAggregate,
dataset,
includePrevious: comparisonType === AlertRuleComparisonType.DYNAMIC,
newAlertOrQuery: !ruleId || query !== rule.query,
timeWindow,
environment,
Expand Down
12 changes: 12 additions & 0 deletions static/app/views/alerts/rules/metric/triggers/chart/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {capitalize} from 'sentry/utils/string/capitalize';
import withApi from 'sentry/utils/withApi';
import {COMPARISON_DELTA_OPTIONS} from 'sentry/views/alerts/rules/metric/constants';
import {shouldUseErrorsDiscoverDataset} from 'sentry/views/alerts/rules/utils';
import type {Anomaly} from 'sentry/views/alerts/types';
import {isSessionAggregate, SESSION_AGGREGATE_TO_FIELD} from 'sentry/views/alerts/utils';
import {getComparisonMarkLines} from 'sentry/views/alerts/utils/getComparisonMarkLines';
import {AlertWizardAlertNames} from 'sentry/views/alerts/wizard/options';
Expand Down Expand Up @@ -77,6 +78,7 @@ type Props = {
thresholdType: MetricRule['thresholdType'];
timeWindow: MetricRule['timeWindow'];
triggers: Trigger[];
anomalies?: Anomaly[];
comparisonDelta?: number;
formattedAggregate?: string;
header?: React.ReactNode;
Expand Down Expand Up @@ -305,6 +307,7 @@ class TriggersChart extends PureComponent<Props, State> {
isReloading: boolean;
orgFeatures: string[];
timeseriesData: Series[];
anomalies?: Anomaly[];
comparisonData?: Series[];
comparisonMarkLines?: LineChartSeries[];
errorMessage?: string;
Expand Down Expand Up @@ -359,6 +362,9 @@ class TriggersChart extends PureComponent<Props, State> {
minValue={minBy(timeseriesData[0]?.data, ({value}) => value)?.value}
maxValue={maxBy(timeseriesData[0]?.data, ({value}) => value)?.value}
data={timeseriesData}
includePrevious={
this.props.comparisonType === AlertRuleComparisonType.DYNAMIC
}
comparisonData={comparisonData ?? []}
comparisonSeriesName={this.comparisonSeriesName}
comparisonMarkLines={comparisonMarkLines ?? []}
Expand Down Expand Up @@ -579,13 +585,19 @@ class TriggersChart extends PureComponent<Props, State> {
thresholdType
);
}
// console.log('timeseriesData', {
// timeWindow,
// timeseriesData,
// comparisonTimeseriesData,
// });

return this.renderChart({
timeseriesData: timeseriesData as Series[],
isLoading: loading,
isReloading: reloading,
comparisonData: comparisonTimeseriesData,
comparisonMarkLines,
anomalies: [],
errorMessage,
isQueryValid,
errored,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,23 @@ import {PureComponent} from 'react';
import color from 'color';
import type {TooltipComponentFormatterCallbackParams} from 'echarts';
import debounce from 'lodash/debounce';
import moment from 'moment-timezone';

import {extrapolatedAreaStyle} from 'sentry/components/alerts/onDemandMetricAlert';
import {AreaChart} from 'sentry/components/charts/areaChart';
import {AreaChart, type AreaChartSeries} from 'sentry/components/charts/areaChart';
import Graphic from 'sentry/components/charts/components/graphic';
import MarkLine from 'sentry/components/charts/components/markLine';
import {defaultFormatAxisLabel} from 'sentry/components/charts/components/tooltip';
import type {LineChartSeries} from 'sentry/components/charts/lineChart';
import LineSeries from 'sentry/components/charts/series/lineSeries';
import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
import {CHART_PALETTE} from 'sentry/constants/chartPalette';
import ConfigStore from 'sentry/stores/configStore';
import {space} from 'sentry/styles/space';
import type {PageFilters} from 'sentry/types/core';
import type {ReactEchartsRef, Series} from 'sentry/types/echarts';
import theme from 'sentry/utils/theme';
import type {Anomaly} from 'sentry/views/alerts/types';
import {
ALERT_CHART_MIN_MAX_BUFFER,
alertAxisFormatter,
Expand All @@ -28,6 +32,7 @@ import type {MetricRule, Trigger} from '../../types';
import {AlertRuleThresholdType, AlertRuleTriggerType} from '../../types';

type DefaultProps = {
anomalies: Anomaly[];
comparisonData: Series[];
comparisonMarkLines: LineChartSeries[];
data: Series[];
Expand All @@ -40,6 +45,7 @@ type Props = DefaultProps & {
thresholdType: MetricRule['thresholdType'];
triggers: Trigger[];
comparisonSeriesName?: string;
includePrevious?: boolean;
isExtrapolatedData?: boolean;
maxValue?: number;
minValue?: number;
Expand Down Expand Up @@ -74,6 +80,7 @@ const COLOR = {
export default class ThresholdsChart extends PureComponent<Props, State> {
static defaultProps: DefaultProps = {
data: [],
anomalies: [],
comparisonData: [],
comparisonMarkLines: [],
};
Expand Down Expand Up @@ -295,6 +302,45 @@ export default class ThresholdsChart extends PureComponent<Props, State> {
);
};

getAnomalyMarkerSeries = (lineColor: string, timestamp: string): AreaChartSeries => {
const formatter = ({value}: any) => {
const time = formatTooltipDate(moment(value), 'MMM D, YYYY LT');
return [
`<div class="tooltip-series"><div>`,
`</div>Anomaly Detected</div>`,
`<div class="tooltip-footer">${time}</div>`,
'<div class="tooltip-arrow"></div>',
].join('');
};

return {
seriesName: 'Anomaly Line',
type: 'line',
markLine: MarkLine({
silent: false,
lineStyle: {color: lineColor, type: 'dashed'},
label: {
silent: true,
show: false,
},
data: [
{
xAxis: timestamp,
},
],
tooltip: {
formatter,
},
}),
data: [],
tooltip: {
trigger: 'item',
alwaysShowContent: true,
formatter,
},
};
};

clampMaxValue(value: number) {
// When we apply top buffer to the crash free percentage (99.7% * 1.03), it
// can cross 100%, so we clamp it
Expand Down Expand Up @@ -431,7 +477,11 @@ export default class ThresholdsChart extends PureComponent<Props, State> {
]),
})}
colors={CHART_PALETTE[0]}
series={[...dataWithoutRecentBucket, ...comparisonMarkLines]}
series={[
...dataWithoutRecentBucket,
...comparisonMarkLines,
this.getAnomalyMarkerSeries('#f00', '1727386850000'),
]}
additionalSeries={comparisonDataWithoutRecentBucket.map(
({data: _data, ...otherSeriesProps}) =>
LineSeries({
Expand All @@ -454,3 +504,10 @@ export default class ThresholdsChart extends PureComponent<Props, State> {
);
}
}

function formatTooltipDate(date: moment.MomentInput, format: string): string {
const {
options: {timezone},
} = ConfigStore.get('user');
return moment.tz(date, timezone).format(format);
}

0 comments on commit f9b0916

Please sign in to comment.