-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[AO] Adding charts to the alert details page for metric threshold (#1…
…52697) Closes #151412 ## 📝 Summary This PR adds preview charts to the metric threshold's rule details page.  **Note** - This is only the first step, so there are limitations that will be tackled in the follow-up PRs, such as: - Allow custom time range for preview chart - Adding extra alert annotation on the preview charts - Sync chart pointers ## ✅ Acceptance Criteria - Create a metric threshold rule that fires and check the related alert details page
- Loading branch information
1 parent
3872fd6
commit 563ee27
Showing
15 changed files
with
365 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
...gins/infra/public/alerting/metric_threshold/components/alert_details_app_section.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { coreMock as mockCoreMock } from '@kbn/core/public/mocks'; | ||
import React from 'react'; | ||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react'; | ||
import { render } from '@testing-library/react'; | ||
import { buildMetricThresholdRule } from '../mocks/metric_threshold_rule'; | ||
import AlertDetailsAppSection from './alert_details_app_section'; | ||
|
||
jest.mock('../../../hooks/use_kibana', () => ({ | ||
useKibanaContextForPlugin: () => ({ | ||
services: mockCoreMock.createStart(), | ||
}), | ||
})); | ||
|
||
jest.mock('../../../containers/metrics_source/use_source_via_http', () => ({ | ||
useSourceViaHttp: () => ({ | ||
source: { id: 'default' }, | ||
createDerivedIndexPattern: () => ({ fields: [], title: 'metricbeat-*' }), | ||
}), | ||
})); | ||
|
||
describe('AlertDetailsAppSection', () => { | ||
const renderComponent = () => { | ||
return render( | ||
<IntlProvider locale="en"> | ||
<AlertDetailsAppSection rule={buildMetricThresholdRule()} /> | ||
</IntlProvider> | ||
); | ||
}; | ||
|
||
it('should render rule data correctly', async () => { | ||
const result = renderComponent(); | ||
|
||
expect((await result.findByTestId('metricThresholdAppSection')).children.length).toBe(3); | ||
}); | ||
}); |
61 changes: 61 additions & 0 deletions
61
...k/plugins/infra/public/alerting/metric_threshold/components/alert_details_app_section.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; | ||
import React, { useMemo } from 'react'; | ||
import { Rule } from '@kbn/alerting-plugin/common'; | ||
import { MetricThresholdRuleTypeParams } from '..'; | ||
import { generateUniqueKey } from '../lib/generate_unique_key'; | ||
import { MetricsExplorerChartType } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; | ||
import { ExpressionChart } from './expression_chart'; | ||
import { useSourceViaHttp } from '../../../containers/metrics_source/use_source_via_http'; | ||
import { useKibanaContextForPlugin } from '../../../hooks/use_kibana'; | ||
|
||
// TODO Use a generic props for app sections https://github.com/elastic/kibana/issues/152690 | ||
interface AppSectionProps { | ||
rule: Rule< | ||
MetricThresholdRuleTypeParams & { | ||
filterQueryText?: string; | ||
groupBy?: string | string[]; | ||
} | ||
>; | ||
} | ||
|
||
export function AlertDetailsAppSection({ rule }: AppSectionProps) { | ||
const { http, notifications } = useKibanaContextForPlugin().services; | ||
const { source, createDerivedIndexPattern } = useSourceViaHttp({ | ||
sourceId: 'default', | ||
fetch: http.fetch, | ||
toastWarning: notifications.toasts.addWarning, | ||
}); | ||
const derivedIndexPattern = useMemo( | ||
() => createDerivedIndexPattern(), | ||
[createDerivedIndexPattern] | ||
); | ||
|
||
return !!rule.params.criteria ? ( | ||
<EuiFlexGroup direction="column" data-test-subj="metricThresholdAppSection"> | ||
{rule.params.criteria.map((criterion) => ( | ||
<EuiFlexItem key={generateUniqueKey(criterion)}> | ||
<EuiPanel hasBorder hasShadow={false}> | ||
<ExpressionChart | ||
expression={criterion} | ||
derivedIndexPattern={derivedIndexPattern} | ||
source={source} | ||
filterQuery={rule.params.filterQueryText} | ||
groupBy={rule.params.groupBy} | ||
chartType={MetricsExplorerChartType.line} | ||
/> | ||
</EuiPanel> | ||
</EuiFlexItem> | ||
))} | ||
</EuiFlexGroup> | ||
) : null; | ||
} | ||
|
||
// eslint-disable-next-line import/no-default-export | ||
export default AlertDetailsAppSection; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
x-pack/plugins/infra/public/alerting/metric_threshold/lib/generate_unique_key.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { Aggregators, Comparator } from '../../../../common/alerting/metrics'; | ||
import { MetricExpression } from '../types'; | ||
import { generateUniqueKey } from './generate_unique_key'; | ||
|
||
describe('generateUniqueKey', () => { | ||
const mockedCriteria: Array<[MetricExpression, string]> = [ | ||
[ | ||
{ | ||
aggType: Aggregators.COUNT, | ||
comparator: Comparator.LT, | ||
threshold: [2000, 5000], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
}, | ||
'count<2000,5000', | ||
], | ||
[ | ||
{ | ||
aggType: Aggregators.CUSTOM, | ||
comparator: Comparator.GT_OR_EQ, | ||
threshold: [30], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
}, | ||
'custom>=30', | ||
], | ||
[ | ||
{ | ||
aggType: Aggregators.AVERAGE, | ||
comparator: Comparator.LT_OR_EQ, | ||
threshold: [500], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
metric: 'metric', | ||
}, | ||
'avg(metric)<=500', | ||
], | ||
]; | ||
it.each(mockedCriteria)('unique key of %p is %s', (input, output) => { | ||
const uniqueKey = generateUniqueKey(input); | ||
|
||
expect(uniqueKey).toBe(output); | ||
}); | ||
}); |
14 changes: 14 additions & 0 deletions
14
x-pack/plugins/infra/public/alerting/metric_threshold/lib/generate_unique_key.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { MetricExpression } from '../types'; | ||
|
||
export const generateUniqueKey = (criterion: MetricExpression) => { | ||
const metric = criterion.metric ? `(${criterion.metric})` : ''; | ||
|
||
return criterion.aggType + metric + criterion.comparator + criterion.threshold.join(','); | ||
}; |
122 changes: 122 additions & 0 deletions
122
x-pack/plugins/infra/public/alerting/metric_threshold/mocks/metric_threshold_rule.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0; you may not use this file except in compliance with the Elastic License | ||
* 2.0. | ||
*/ | ||
|
||
import { Rule } from '@kbn/alerting-plugin/common'; | ||
import { v4 as uuidv4 } from 'uuid'; | ||
import { Aggregators, Comparator } from '../../../../common/alerting/metrics'; | ||
import { MetricThresholdRuleTypeParams } from '..'; | ||
|
||
export const buildMetricThresholdRule = ( | ||
rule: Partial<Rule<MetricThresholdRuleTypeParams>> = {} | ||
): Rule<MetricThresholdRuleTypeParams> => { | ||
return { | ||
alertTypeId: 'metrics.alert.threshold', | ||
createdBy: 'admin', | ||
updatedBy: 'admin', | ||
createdAt: new Date('2023-02-20T15:25:32.125Z'), | ||
updatedAt: new Date('2023-03-02T16:24:41.177Z'), | ||
apiKey: 'apiKey', | ||
apiKeyOwner: 'admin', | ||
notifyWhen: null, | ||
muteAll: false, | ||
mutedInstanceIds: [], | ||
snoozeSchedule: [], | ||
executionStatus: { | ||
lastExecutionDate: new Date('2023-03-10T12:58:07.823Z'), | ||
lastDuration: 3882, | ||
status: 'ok', | ||
}, | ||
actions: [], | ||
scheduledTaskId: 'cfd9c4f0-b132-11ed-88f2-77e0607bce49', | ||
isSnoozedUntil: null, | ||
lastRun: { | ||
outcomeMsg: null, | ||
outcomeOrder: 0, | ||
alertsCount: { | ||
new: 0, | ||
ignored: 0, | ||
recovered: 0, | ||
active: 0, | ||
}, | ||
warning: null, | ||
outcome: 'succeeded', | ||
}, | ||
nextRun: new Date('2023-03-10T12:59:07.592Z'), | ||
id: uuidv4(), | ||
consumer: 'alerts', | ||
tags: [], | ||
name: 'Monitoring hosts', | ||
enabled: true, | ||
throttle: null, | ||
running: false, | ||
schedule: { | ||
interval: '1m', | ||
}, | ||
params: { | ||
criteria: [ | ||
{ | ||
aggType: Aggregators.COUNT, | ||
comparator: Comparator.GT, | ||
threshold: [2000], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
}, | ||
{ | ||
aggType: Aggregators.MAX, | ||
comparator: Comparator.GT, | ||
threshold: [4], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
metric: 'system.cpu.user.pct', | ||
warningComparator: Comparator.GT, | ||
warningThreshold: [2.2], | ||
}, | ||
{ | ||
aggType: Aggregators.MIN, | ||
comparator: Comparator.GT, | ||
threshold: [0.8], | ||
timeSize: 15, | ||
timeUnit: 'm', | ||
metric: 'system.memory.used.pct', | ||
}, | ||
], | ||
filterQuery: | ||
'{"bool":{"filter":[{"bool":{"should":[{"term":{"host.hostname":{"value":"Maryams-MacBook-Pro.local"}}}],"minimum_should_match":1}},{"bool":{"should":[{"term":{"service.type":{"value":"system"}}}],"minimum_should_match":1}}]}}', | ||
groupBy: ['host.hostname'], | ||
}, | ||
monitoring: { | ||
run: { | ||
history: [ | ||
{ | ||
duration: 4433, | ||
success: true, | ||
timestamp: 1678375661786, | ||
}, | ||
], | ||
calculated_metrics: { | ||
success_ratio: 1, | ||
p99: 7745, | ||
p50: 4909.5, | ||
p95: 6319, | ||
}, | ||
last_run: { | ||
timestamp: '2023-03-10T12:58:07.823Z', | ||
metrics: { | ||
total_search_duration_ms: null, | ||
total_indexing_duration_ms: null, | ||
total_alerts_detected: null, | ||
total_alerts_created: null, | ||
gap_duration_s: null, | ||
duration: 3882, | ||
}, | ||
}, | ||
}, | ||
}, | ||
revision: 1, | ||
...rule, | ||
}; | ||
}; |
Oops, something went wrong.