-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
feat(aci): Add missing anomaly detection conditions #103004
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
Changes from 3 commits
a86f435
d1ff1b6
fc3473d
25cf1dc
4295ec0
c4f6690
81647e2
b8c726f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,32 +80,28 @@ export type DetectorType = | |
| | 'uptime_domain_failure' | ||
| | 'issue_stream'; | ||
|
|
||
| interface BaseMetricDetectorConfig { | ||
| thresholdPeriod: number; | ||
| } | ||
|
|
||
| /** | ||
| * Configuration for static/threshold-based detection | ||
| */ | ||
| interface MetricDetectorConfigStatic extends BaseMetricDetectorConfig { | ||
| interface MetricDetectorConfigStatic { | ||
| detectionType: 'static'; | ||
| } | ||
|
|
||
| /** | ||
| * Configuration for percentage-based change detection | ||
| */ | ||
| interface MetricDetectorConfigPercent extends BaseMetricDetectorConfig { | ||
| interface MetricDetectorConfigPercent { | ||
| comparisonDelta: number; | ||
| detectionType: 'percent'; | ||
| } | ||
|
|
||
| /** | ||
| * Configuration for dynamic/anomaly detection | ||
| */ | ||
| interface MetricDetectorConfigDynamic extends BaseMetricDetectorConfig { | ||
| interface MetricDetectorConfigDynamic { | ||
| detectionType: 'dynamic'; | ||
| seasonality?: 'auto' | 'daily' | 'weekly' | 'monthly'; | ||
| sensitivity?: AlertRuleSensitivity; | ||
| sensitivity?: 'low' | 'medium' | 'high'; | ||
scttcper marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| thresholdType?: AlertRuleThresholdType; | ||
| } | ||
|
|
||
|
|
@@ -233,7 +229,7 @@ export interface MetricCondition { | |
| /** | ||
| * See AnomalyDetectionHandler | ||
| */ | ||
| interface AnomalyDetectionComparison { | ||
| export interface AnomalyDetectionComparison { | ||
| seasonality: | ||
| | 'auto' | ||
| | 'hourly' | ||
|
|
@@ -243,8 +239,8 @@ interface AnomalyDetectionComparison { | |
| | 'hourly_weekly' | ||
| | 'hourly_daily_weekly' | ||
| | 'daily_weekly'; | ||
| sensitivity: 'low' | 'medium' | 'high'; | ||
| threshold_type: 0 | 1 | 2; | ||
| sensitivity: AlertRuleSensitivity; | ||
| thresholdType: AlertRuleThresholdType; | ||
| } | ||
|
|
||
| type MetricDataCondition = AnomalyDetectionComparison | number; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { | |
| DetectorPriorityLevel, | ||
| } from 'sentry/types/workflowEngine/dataConditions'; | ||
| import type { | ||
| AnomalyDetectionComparison, | ||
| Detector, | ||
| MetricCondition, | ||
| MetricConditionGroup, | ||
|
|
@@ -183,6 +184,22 @@ interface NewDataSource { | |
| timeWindow: number; | ||
| } | ||
|
|
||
| function createAnomalyDetectionCondition( | ||
| data: Pick<MetricDetectorFormData, 'sensitivity' | 'thresholdType'> | ||
| ): NewConditionGroup['conditions'] { | ||
| return [ | ||
| { | ||
| type: DataConditionType.ANOMALY_DETECTION, | ||
| comparison: { | ||
| sensitivity: data.sensitivity, | ||
| seasonality: 'auto' as const, | ||
| thresholdType: data.thresholdType, | ||
| }, | ||
| conditionResult: DetectorPriorityLevel.HIGH, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Creates escalation conditions based on priority level and available thresholds | ||
| */ | ||
|
|
@@ -303,30 +320,31 @@ function createDataSource(data: MetricDetectorFormData): NewDataSource { | |
| export function metricDetectorFormDataToEndpointPayload( | ||
| data: MetricDetectorFormData | ||
| ): MetricDetectorUpdatePayload { | ||
| const conditions = createConditions(data); | ||
| const conditions = | ||
| data.detectionType === 'dynamic' | ||
| ? createAnomalyDetectionCondition(data) | ||
| : createConditions(data); | ||
|
|
||
| const dataSource = createDataSource(data); | ||
|
|
||
| // Create config based on detection type | ||
| let config: MetricDetectorConfig; | ||
| switch (data.detectionType) { | ||
| case 'percent': | ||
| config = { | ||
| thresholdPeriod: 1, | ||
| detectionType: 'percent', | ||
| comparisonDelta: data.conditionComparisonAgo || 3600, | ||
| }; | ||
| break; | ||
| case 'dynamic': | ||
| config = { | ||
| thresholdPeriod: 1, | ||
| detectionType: 'dynamic', | ||
| sensitivity: data.sensitivity, | ||
| }; | ||
| break; | ||
| case 'static': | ||
| default: | ||
| config = { | ||
| thresholdPeriod: 1, | ||
| detectionType: 'static', | ||
| }; | ||
| break; | ||
|
|
@@ -423,6 +441,24 @@ function processDetectorConditions( | |
| }; | ||
| } | ||
|
|
||
| function getAnomalyCondition(detector: MetricDetector): AnomalyDetectionComparison { | ||
| const anomalyCondition = detector.conditionGroup?.conditions?.find( | ||
| condition => condition.type === DataConditionType.ANOMALY_DETECTION | ||
| ); | ||
|
|
||
| const comparison = anomalyCondition?.comparison; | ||
| if (typeof comparison === 'object') { | ||
| return comparison; | ||
| } | ||
|
|
||
| // Fallback to default values | ||
| return { | ||
| sensitivity: AlertRuleSensitivity.MEDIUM, | ||
| seasonality: 'auto', | ||
| thresholdType: AlertRuleThresholdType.ABOVE_AND_BELOW, | ||
| }; | ||
| } | ||
scttcper marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * Converts a Detector to MetricDetectorFormData for editing | ||
| */ | ||
|
|
@@ -444,6 +480,7 @@ export function metricSavedDetectorToFormData( | |
| : DetectorDataset.SPANS; | ||
|
|
||
| const datasetConfig = getDatasetConfig(dataset); | ||
| const anomalyCondition = getAnomalyCondition(detector); | ||
|
|
||
| return { | ||
| // Core detector fields | ||
|
|
@@ -471,15 +508,8 @@ export function metricSavedDetectorToFormData( | |
| ? detector.config.comparisonDelta | ||
| : DEFAULT_THRESHOLD_METRIC_FORM_DATA.conditionComparisonAgo, | ||
|
|
||
| // Dynamic fields - extract from config for dynamic detectors | ||
| sensitivity: | ||
| detector.config.detectionType === 'dynamic' && defined(detector.config.sensitivity) | ||
| ? detector.config.sensitivity | ||
| : DEFAULT_THRESHOLD_METRIC_FORM_DATA.sensitivity, | ||
| thresholdType: | ||
| detector.config.detectionType === 'dynamic' && | ||
| defined(detector.config.thresholdType) | ||
| ? detector.config.thresholdType | ||
| : DEFAULT_THRESHOLD_METRIC_FORM_DATA.thresholdType, | ||
| // Dynamic fields - extract from anomaly detection condition for dynamic detectors | ||
| sensitivity: anomalyCondition.sensitivity, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should also be removed here
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this one is sensitivity |
||
| thresholdType: anomalyCondition.thresholdType, | ||
| }; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.