Alerting: Remove filter for state without reason (#93604)

This commit is contained in:
Gilles De Mey 2024-09-26 15:40:04 +02:00 committed by GitHub
parent 7aaa4b241e
commit 4b1d8eeef0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 1937 additions and 96 deletions

View File

@ -9,7 +9,7 @@ import { stateHistoryApi } from '../../../api/stateHistoryApi';
import { DataSourceInformation } from '../../../home/Insights';
import { LIMIT_EVENTS } from './EventListSceneObject';
import { historyResultToDataFrame } from './utils';
import { getStateFilterFromInQueryParams, getStateFilterToInQueryParams, historyResultToDataFrame } from './utils';
const historyDataSourceUid = '__history_api_ds_uid__';
const historyDataSourcePluginId = '__history_api_ds_pluginId__';
@ -47,8 +47,14 @@ class HistoryAPIDatasource extends RuntimeDataSource {
const from = request.range.from.unix();
const to = request.range.to.unix();
// Get the labels and states filters from the URL
const stateTo = getStateFilterToInQueryParams();
const stateFrom = getStateFilterFromInQueryParams();
const historyResult = await getHistory(from, to);
return {
data: historyResultToDataFrame(await getHistory(from, to)),
data: historyResultToDataFrame(historyResult, { stateTo, stateFrom }),
};
}

View File

@ -1,9 +1,9 @@
import { css, cx } from '@emotion/css';
import { ReactElement, useMemo, useState } from 'react';
import { ReactElement, useState } from 'react';
import { useLocation } from 'react-router';
import { useMeasure } from 'react-use';
import { DataFrameJSON, GrafanaTheme2, IconName, TimeRange } from '@grafana/data';
import { GrafanaTheme2, IconName, TimeRange } from '@grafana/data';
import {
CustomVariable,
SceneComponentProps,
@ -25,18 +25,17 @@ import {
import { trackUseCentralHistoryFilterByClicking, trackUseCentralHistoryMaxEventsReached } from '../../../Analytics';
import { stateHistoryApi } from '../../../api/stateHistoryApi';
import { usePagination } from '../../../hooks/usePagination';
import { combineMatcherStrings, labelsMatchMatchers } from '../../../utils/alertmanager';
import { combineMatcherStrings } from '../../../utils/alertmanager';
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
import { parsePromQLStyleMatcherLooseSafe } from '../../../utils/matchers';
import { createRelativeUrl } from '../../../utils/url';
import { AlertLabels } from '../../AlertLabels';
import { CollapseToggle } from '../../CollapseToggle';
import { LogRecord } from '../state-history/common';
import { isLine, isNumbers } from '../state-history/useRuleHistoryRecords';
import { LABELS_FILTER, STATE_FILTER_FROM, STATE_FILTER_TO, StateFilterValues } from './CentralAlertHistoryScene';
import { LABELS_FILTER, STATE_FILTER_FROM, STATE_FILTER_TO } from './CentralAlertHistoryScene';
import { EventDetails } from './EventDetails';
import { HistoryErrorMessage } from './HistoryErrorMessage';
import { useRuleHistoryRecords } from './useRuleHistoryRecords';
export const LIMIT_EVENTS = 5000; // limit is hard-capped at 5000 at the BE level.
const PAGE_SIZE = 100;
@ -75,12 +74,11 @@ export const HistoryEventsList = ({
limit: LIMIT_EVENTS,
});
const { historyRecords: historyRecordsNotSorted } = useRuleHistoryRecords(
valueInLabelFilter.toString(),
valueInStateToFilter.toString(),
valueInStateFromFilter.toString(),
stateHistory
);
const { historyRecords: historyRecordsNotSorted } = useRuleHistoryRecords(stateHistory, {
labels: valueInLabelFilter.toString(),
stateFrom: valueInStateFromFilter.toString(),
stateTo: valueInStateToFilter.toString(),
});
const historyRecords = historyRecordsNotSorted.sort((a, b) => b.timestamp - a.timestamp);
@ -542,54 +540,3 @@ export function HistoryEventsListObjectRenderer({ model }: SceneComponentProps<H
/>
);
}
/**
* This hook filters the history records based on the label, stateTo and stateFrom filters.
* @param filterInLabel
* @param filterInStateTo
* @param filterInStateFrom
* @param stateHistory the original history records
* @returns the filtered history records
*/
function useRuleHistoryRecords(
filterInLabel: string,
filterInStateTo: string,
filterInStateFrom: string,
stateHistory?: DataFrameJSON
) {
return useMemo(() => {
if (!stateHistory?.data) {
return { historyRecords: [] };
}
const filterMatchers = filterInLabel ? parsePromQLStyleMatcherLooseSafe(filterInLabel) : [];
const [tsValues, lines] = stateHistory.data.values;
const timestamps = isNumbers(tsValues) ? tsValues : [];
// merge timestamp with "line"
const logRecords = timestamps.reduce((acc: LogRecord[], timestamp: number, index: number) => {
const line = lines[index];
if (!isLine(line)) {
return acc;
}
// values property can be undefined for some instance states (e.g. NoData)
const filterMatch = line.labels && labelsMatchMatchers(line.labels, filterMatchers);
if (!isGrafanaAlertState(line.current) || !isGrafanaAlertState(line.previous)) {
return acc;
}
const baseStateTo = mapStateWithReasonToBaseState(line.current);
const baseStateFrom = mapStateWithReasonToBaseState(line.previous);
const stateToMatch = filterInStateTo !== StateFilterValues.all ? filterInStateTo === baseStateTo : true;
const stateFromMatch = filterInStateFrom !== StateFilterValues.all ? filterInStateFrom === baseStateFrom : true;
if (filterMatch && stateToMatch && stateFromMatch) {
acc.push({ timestamp, line });
}
return acc;
}, []);
return {
historyRecords: logRecords,
};
}, [stateHistory, filterInLabel, filterInStateTo, filterInStateFrom]);
}

View File

@ -0,0 +1,896 @@
import { DataFrameJSON } from '@grafana/data';
const data: DataFrameJSON = {
data: {
values: [
[
1727189670000, 1727189670000, 1727189670000, 1727189670000, 1727189670000, 1727189670000, 1727189670000,
1727189670000, 1727189670000, 1727189670000, 1727189680000, 1727189700000, 1727189690000, 1727189690000,
1727189690000, 1727189690000, 1727189690000, 1727189690000, 1727189690000, 1727189690000, 1727189680000,
1727189670000, 1727189700000, 1727189710000, 1727189710000, 1727189710000, 1727189710000, 1727189710000,
1727189710000, 1727189710000, 1727189710000, 1727189710000,
],
[
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: '-W9yw_X7k',
panelID: 3,
fingerprint: '009794b4d3074732',
ruleTitle: 'CPU Usage 6',
ruleID: 10605,
ruleUID: '-rRg_HcVz',
labels: {
alertname: 'CPU Usage 6',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Demonstrations',
ref_id: 'A',
team: 'operations',
type: 'test',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: 'stzZvVw7k',
panelID: 8,
fingerprint: '186e7d0c9173ddf4',
ruleTitle: 'CPU Usage 4',
ruleID: 150,
ruleUID: 's984p7n4k',
labels: {
alertname: 'CPU Usage 4',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Demonstrations',
ref_id: 'A',
region: 'EMEA',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Alerting',
current: 'Normal',
values: {
B: -6.886811320670644,
C: 0,
},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'bcf38efbb616d8d2',
ruleTitle: 'direct to contact point',
ruleID: 10656,
ruleUID: 'ddc5zx4l3zls0a',
labels: {
alertname: 'direct to contact point',
grafana_folder: 'Testing and reproducing',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'D',
dashboardUID: 'iYSJkozVk',
panelID: 13,
fingerprint: 'd3f3ec7ad90a37fd',
ruleTitle: 'With Disabled Query',
ruleID: 10631,
ruleUID: 'ab2ac850-1669-4dac-b566-c91728425f39',
labels: {
alertname: 'With Disabled Query',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Testing and reproducing',
ref_id: 'A,B',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'f4c073dd4c60e897',
ruleTitle: 'Alert State History Random',
ruleID: 10614,
ruleUID: 'e4d7252b-c66f-4f5c-b7db-28b9936150bd',
labels: {
alertname: 'Alert State History Random',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Testing and reproducing',
ref_id: 'A',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
B: 54.137611900622574,
C: 1,
},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'e11b0ff29886e8f2',
ruleTitle: 'node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate4',
ruleID: 10662,
ruleUID: 'ddgfq7c57fqpsc',
labels: {
alertname: 'node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate4',
grafana_folder: 'Testing and reproducing',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'B',
dashboardUID: '',
panelID: 0,
fingerprint: 'd6d7e256298c8ea8',
ruleTitle: 'delete-ds',
ruleID: 144,
ruleUID: 'wXS0SnWVz',
labels: {
alertname: 'delete-ds',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Testing and reproducing',
ref_id: 'A',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'bf1b309577b4fc0c',
ruleTitle: 'Threshold Test',
ruleID: 148,
ruleUID: 'u0QVOqMVz',
labels: {
alertname: 'Threshold Test',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Testing and reproducing',
ref_id: 'A',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'd6b1cde6ab63bfca',
ruleTitle: 'Alert History fingerprint',
ruleID: 10619,
ruleUID: 'c7a7989f-f12c-4aa5-8fb3-27f4509a5809',
labels: {
alertname: 'Alert History fingerprint',
datasource_uid: 'PDDA8E780A17E7EF1',
grafana_folder: 'Testing and reproducing',
ref_id: 'A',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
B: 0.0020875,
C: 1,
},
condition: 'C',
dashboardUID: 'd4c61dfe-24d8-433e-984e-701a2f14faab',
panelID: 1,
fingerprint: '40ddb0f6e97426e9',
ruleTitle: 'UniFi CPU Usage',
ruleID: 10638,
ruleUID: 'd10fc550-3552-4083-a3aa-f6b68058bc7f',
labels: {
alertname: 'UniFi CPU Usage',
grafana_folder: 'UniFi',
instance: 'unpoller:9130',
job: 'unifipoller',
name: 'Dream Router',
site_name: 'Default (default)',
source: 'https://192.168.1.1',
type: 'udm',
},
},
{
schemaVersion: 1,
previous: 'Pending',
current: 'Alerting',
values: {
B0: 36.956598435022215,
},
condition: 'B',
dashboardUID: '',
panelID: 0,
fingerprint: '10716534bbf8086b',
ruleTitle: 'XSS attack vector',
ruleID: 37,
ruleUID: 'p8TBxnq7k',
labels: {
alertname: 'XSS attack vector',
grafana_folder: 'gdev dashboards',
},
},
{
schemaVersion: 1,
previous: 'NoData',
current: 'Normal (MissingSeries)',
values: {},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '4a5519a42c382438',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Demonstrations',
ref_id: 'A',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.067575,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: 'cc4aceb3018da2e8',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '7',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.06216900000000001,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '20dfd648881e698f',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '2',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.07027800000000001,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '234db8cd1e160f6a',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '1',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.06727466666666668,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '4e1f85b7efc3ed75',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '0',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.05315900000000001,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '50bf9f17b9534593',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '6',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.046551666666666686,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '2fb0af95df9b2bfe',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '5',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.05466066666666668,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: 'd0303e26f6c376e9',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '4',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Alerting',
values: {
B: 0.059165666666666665,
C: 1,
},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: 'af82d1220e70c3b4',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
cpu: '3',
grafana_folder: 'Demonstrations',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Error',
current: 'Normal (MissingSeries)',
values: {},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '4a5519a42c382438',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Demonstrations',
ref_id: 'A',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'NoData',
values: {},
condition: 'C',
dashboardUID: 'iYSJkozVk',
panelID: 5,
fingerprint: '4a5519a42c382438',
ruleTitle: 'CPU Usage',
ruleID: 7635,
ruleUID: '8nEmeE44k',
labels: {
alertname: 'CPU Usage',
datasource_uid: 'gdev-prometheus',
grafana_folder: 'Demonstrations',
ref_id: 'A',
team: 'operations',
type: 'cpu',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
C0: 9.319781010143206,
},
condition: 'C',
dashboardUID: '',
panelID: 0,
fingerprint: 'abeb2444057d7f01',
ruleTitle: 'test-read-only-threshold-indicators',
ruleID: 10606,
ruleUID: 'Wq5jJlc4k',
labels: {
alertname: 'test-read-only-threshold-indicators',
grafana_folder: 'Testing and reproducing',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.07305751032920166,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '2e7f5e6f5a5f2902',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '6',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.06820108623217379,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '1c1b21f738468ea5',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '5',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.07685819005731041,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '23ee5f02850e38f8',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '4',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.08614874050379848,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '2a810fa152d6407b',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '3',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.0926943555910969,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '48d127e8826c6fb6',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '2',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.1097974143675863,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: 'c9582e3d28402fe9',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '1',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.12985655737704918,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: 'fb3e32509acec7ec',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '0',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
B0: 8.406488484275167,
},
condition: 'B',
dashboardUID: '',
panelID: 0,
fingerprint: '91a8126f41689d98',
ruleTitle: 'Random Values',
ruleID: 146,
ruleUID: 'I1M_iCWVk',
labels: {
alertname: 'Random Values',
grafana_folder: 'Demonstrations',
},
},
{
schemaVersion: 1,
previous: 'Normal',
current: 'Pending',
values: {
reducer: 0.08973827135812343,
threshold: 1,
},
condition: 'threshold',
dashboardUID: '',
panelID: 0,
fingerprint: '6cd2ab200de1cf77',
ruleTitle: 'CPU Usage 5',
ruleID: 10583,
ruleUID: 'LvMu_IHVz',
labels: {
alertname: 'CPU Usage 5',
cpu: '7',
grafana_folder: 'Demonstrations',
team: 'operations',
},
},
],
[
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'system-metrics',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default 2',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'Qh4ctRZVz',
from: 'state-history',
group: 'system',
orgID: '1',
},
{
folderUID: 'pPyg37Qnk',
from: 'state-history',
group: 'security',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'usage',
orgID: '1',
},
{
folderUID: 'a3eyrfqnk',
from: 'state-history',
group: 'thresholds',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
{
folderUID: 'lG5pfeRVk',
from: 'state-history',
group: 'default',
orgID: '1',
},
],
],
},
};
export default data;

View File

@ -0,0 +1,822 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ruleHistoryToRecords should be empty with no matches 1`] = `
{
"historyRecords": [],
}
`;
exports[`ruleHistoryToRecords should convert rule history JSON response to log records 1`] = `
{
"historyRecords": [
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "-W9yw_X7k",
"fingerprint": "009794b4d3074732",
"labels": {
"alertname": "CPU Usage 6",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Demonstrations",
"ref_id": "A",
"team": "operations",
"type": "test",
},
"panelID": 3,
"previous": "Normal",
"ruleID": 10605,
"ruleTitle": "CPU Usage 6",
"ruleUID": "-rRg_HcVz",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "stzZvVw7k",
"fingerprint": "186e7d0c9173ddf4",
"labels": {
"alertname": "CPU Usage 4",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Demonstrations",
"ref_id": "A",
"region": "EMEA",
"team": "operations",
},
"panelID": 8,
"previous": "Normal",
"ruleID": 150,
"ruleTitle": "CPU Usage 4",
"ruleUID": "s984p7n4k",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "Normal",
"dashboardUID": "",
"fingerprint": "bcf38efbb616d8d2",
"labels": {
"alertname": "direct to contact point",
"grafana_folder": "Testing and reproducing",
},
"panelID": 0,
"previous": "Alerting",
"ruleID": 10656,
"ruleTitle": "direct to contact point",
"ruleUID": "ddc5zx4l3zls0a",
"schemaVersion": 1,
"values": {
"B": -6.886811320670644,
"C": 0,
},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "D",
"current": "NoData",
"dashboardUID": "iYSJkozVk",
"fingerprint": "d3f3ec7ad90a37fd",
"labels": {
"alertname": "With Disabled Query",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Testing and reproducing",
"ref_id": "A,B",
},
"panelID": 13,
"previous": "Normal",
"ruleID": 10631,
"ruleTitle": "With Disabled Query",
"ruleUID": "ab2ac850-1669-4dac-b566-c91728425f39",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "",
"fingerprint": "f4c073dd4c60e897",
"labels": {
"alertname": "Alert State History Random",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Testing and reproducing",
"ref_id": "A",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10614,
"ruleTitle": "Alert State History Random",
"ruleUID": "e4d7252b-c66f-4f5c-b7db-28b9936150bd",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "e11b0ff29886e8f2",
"labels": {
"alertname": "node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate4",
"grafana_folder": "Testing and reproducing",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10662,
"ruleTitle": "node_namespace_pod_container:container_cpu_usage_seconds_total:sum_irate4",
"ruleUID": "ddgfq7c57fqpsc",
"schemaVersion": 1,
"values": {
"B": 54.137611900622574,
"C": 1,
},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "B",
"current": "NoData",
"dashboardUID": "",
"fingerprint": "d6d7e256298c8ea8",
"labels": {
"alertname": "delete-ds",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Testing and reproducing",
"ref_id": "A",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 144,
"ruleTitle": "delete-ds",
"ruleUID": "wXS0SnWVz",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "",
"fingerprint": "bf1b309577b4fc0c",
"labels": {
"alertname": "Threshold Test",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Testing and reproducing",
"ref_id": "A",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 148,
"ruleTitle": "Threshold Test",
"ruleUID": "u0QVOqMVz",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "",
"fingerprint": "d6b1cde6ab63bfca",
"labels": {
"alertname": "Alert History fingerprint",
"datasource_uid": "PDDA8E780A17E7EF1",
"grafana_folder": "Testing and reproducing",
"ref_id": "A",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10619,
"ruleTitle": "Alert History fingerprint",
"ruleUID": "c7a7989f-f12c-4aa5-8fb3-27f4509a5809",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "Pending",
"dashboardUID": "d4c61dfe-24d8-433e-984e-701a2f14faab",
"fingerprint": "40ddb0f6e97426e9",
"labels": {
"alertname": "UniFi CPU Usage",
"grafana_folder": "UniFi",
"instance": "unpoller:9130",
"job": "unifipoller",
"name": "Dream Router",
"site_name": "Default (default)",
"source": "https://192.168.1.1",
"type": "udm",
},
"panelID": 1,
"previous": "Normal",
"ruleID": 10638,
"ruleTitle": "UniFi CPU Usage",
"ruleUID": "d10fc550-3552-4083-a3aa-f6b68058bc7f",
"schemaVersion": 1,
"values": {
"B": 0.0020875,
"C": 1,
},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "B",
"current": "Alerting",
"dashboardUID": "",
"fingerprint": "10716534bbf8086b",
"labels": {
"alertname": "XSS attack vector",
"grafana_folder": "gdev dashboards",
},
"panelID": 0,
"previous": "Pending",
"ruleID": 37,
"ruleTitle": "XSS attack vector",
"ruleUID": "p8TBxnq7k",
"schemaVersion": 1,
"values": {
"B0": 36.956598435022215,
},
},
"timestamp": 1727189680000,
},
{
"line": {
"condition": "C",
"current": "Normal (MissingSeries)",
"dashboardUID": "iYSJkozVk",
"fingerprint": "4a5519a42c382438",
"labels": {
"alertname": "CPU Usage",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Demonstrations",
"ref_id": "A",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "NoData",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189700000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "cc4aceb3018da2e8",
"labels": {
"alertname": "CPU Usage",
"cpu": "7",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.067575,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "20dfd648881e698f",
"labels": {
"alertname": "CPU Usage",
"cpu": "2",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.06216900000000001,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "234db8cd1e160f6a",
"labels": {
"alertname": "CPU Usage",
"cpu": "1",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.07027800000000001,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "4e1f85b7efc3ed75",
"labels": {
"alertname": "CPU Usage",
"cpu": "0",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.06727466666666668,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "50bf9f17b9534593",
"labels": {
"alertname": "CPU Usage",
"cpu": "6",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.05315900000000001,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "2fb0af95df9b2bfe",
"labels": {
"alertname": "CPU Usage",
"cpu": "5",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.046551666666666686,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "d0303e26f6c376e9",
"labels": {
"alertname": "CPU Usage",
"cpu": "4",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.05466066666666668,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Alerting",
"dashboardUID": "iYSJkozVk",
"fingerprint": "af82d1220e70c3b4",
"labels": {
"alertname": "CPU Usage",
"cpu": "3",
"grafana_folder": "Demonstrations",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {
"B": 0.059165666666666665,
"C": 1,
},
},
"timestamp": 1727189690000,
},
{
"line": {
"condition": "C",
"current": "Normal (MissingSeries)",
"dashboardUID": "iYSJkozVk",
"fingerprint": "4a5519a42c382438",
"labels": {
"alertname": "CPU Usage",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Demonstrations",
"ref_id": "A",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Error",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189680000,
},
{
"line": {
"condition": "C",
"current": "NoData",
"dashboardUID": "iYSJkozVk",
"fingerprint": "4a5519a42c382438",
"labels": {
"alertname": "CPU Usage",
"datasource_uid": "gdev-prometheus",
"grafana_folder": "Demonstrations",
"ref_id": "A",
"team": "operations",
"type": "cpu",
},
"panelID": 5,
"previous": "Normal",
"ruleID": 7635,
"ruleTitle": "CPU Usage",
"ruleUID": "8nEmeE44k",
"schemaVersion": 1,
"values": {},
},
"timestamp": 1727189670000,
},
{
"line": {
"condition": "C",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "abeb2444057d7f01",
"labels": {
"alertname": "test-read-only-threshold-indicators",
"grafana_folder": "Testing and reproducing",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10606,
"ruleTitle": "test-read-only-threshold-indicators",
"ruleUID": "Wq5jJlc4k",
"schemaVersion": 1,
"values": {
"C0": 9.319781010143206,
},
},
"timestamp": 1727189700000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "2e7f5e6f5a5f2902",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "6",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.07305751032920166,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "1c1b21f738468ea5",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "5",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.06820108623217379,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "23ee5f02850e38f8",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "4",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.07685819005731041,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "2a810fa152d6407b",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "3",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.08614874050379848,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "48d127e8826c6fb6",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "2",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.0926943555910969,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "c9582e3d28402fe9",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "1",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.1097974143675863,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "fb3e32509acec7ec",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "0",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.12985655737704918,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "B",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "91a8126f41689d98",
"labels": {
"alertname": "Random Values",
"grafana_folder": "Demonstrations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 146,
"ruleTitle": "Random Values",
"ruleUID": "I1M_iCWVk",
"schemaVersion": 1,
"values": {
"B0": 8.406488484275167,
},
},
"timestamp": 1727189710000,
},
{
"line": {
"condition": "threshold",
"current": "Pending",
"dashboardUID": "",
"fingerprint": "6cd2ab200de1cf77",
"labels": {
"alertname": "CPU Usage 5",
"cpu": "7",
"grafana_folder": "Demonstrations",
"team": "operations",
},
"panelID": 0,
"previous": "Normal",
"ruleID": 10583,
"ruleTitle": "CPU Usage 5",
"ruleUID": "LvMu_IHVz",
"schemaVersion": 1,
"values": {
"reducer": 0.08973827135812343,
"threshold": 1,
},
},
"timestamp": 1727189710000,
},
],
}
`;
exports[`ruleHistoryToRecords should convert rule history JSON response with filters 1`] = `
{
"historyRecords": [
{
"line": {
"condition": "B",
"current": "Alerting",
"dashboardUID": "",
"fingerprint": "10716534bbf8086b",
"labels": {
"alertname": "XSS attack vector",
"grafana_folder": "gdev dashboards",
},
"panelID": 0,
"previous": "Pending",
"ruleID": 37,
"ruleTitle": "XSS attack vector",
"ruleUID": "p8TBxnq7k",
"schemaVersion": 1,
"values": {
"B0": 36.956598435022215,
},
},
"timestamp": 1727189680000,
},
],
}
`;

View File

@ -0,0 +1,71 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`historyResultToDataFrame should decode 1`] = `
[
{
"fields": [
{
"config": {
"custom": {
"fillOpacity": 100,
},
"displayName": "Time",
},
"name": "time",
"type": "time",
"values": [
1727189670000,
1727189680000,
1727189700000,
1727189690000,
1727189710000,
],
},
{
"config": {},
"name": "value",
"type": "number",
"values": [
11,
2,
2,
8,
9,
],
},
],
"length": 5,
},
]
`;
exports[`historyResultToDataFrame should decode and filter 1`] = `
[
{
"fields": [
{
"config": {
"custom": {
"fillOpacity": 100,
},
"displayName": "Time",
},
"name": "time",
"type": "time",
"values": [
1727189680000,
],
},
{
"config": {},
"name": "value",
"type": "number",
"values": [
1,
],
},
],
"length": 1,
},
]
`;

View File

@ -0,0 +1,20 @@
import fixtureData from './__fixtures__/alert-state-history';
import { ruleHistoryToRecords } from './useRuleHistoryRecords';
describe('ruleHistoryToRecords', () => {
it('should convert rule history JSON response to log records', () => {
expect(ruleHistoryToRecords(fixtureData)).toMatchSnapshot();
});
it('should convert rule history JSON response with filters', () => {
expect(
ruleHistoryToRecords(fixtureData, { stateFrom: 'Pending', stateTo: 'Alerting', labels: '' })
).toMatchSnapshot();
});
it('should be empty with no matches', () => {
expect(
ruleHistoryToRecords(fixtureData, { stateFrom: 'Pending', stateTo: 'Alerting', labels: 'doesNot=exist' })
).toMatchSnapshot();
});
});

View File

@ -0,0 +1,65 @@
import { useMemo } from 'react';
import { DataFrameJSON } from '@grafana/data';
import { mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
import { labelsMatchMatchers } from '../../../utils/alertmanager';
import { parsePromQLStyleMatcherLooseSafe } from '../../../utils/matchers';
import { LogRecord } from '../state-history/common';
import { isLine, isNumbers } from '../state-history/useRuleHistoryRecords';
import { StateFilterValues } from './CentralAlertHistoryScene';
const emptyFilters = {
labels: '',
stateFrom: 'all',
stateTo: 'all',
};
/**
* This hook filters the history records based on the label, stateTo and stateFrom filters.
* @param filterInLabel
* @param filterInStateTo
* @param filterInStateFrom
* @param stateHistory the original history records
* @returns the filtered history records
*/
export function useRuleHistoryRecords(stateHistory?: DataFrameJSON, filters = emptyFilters) {
return useMemo(() => ruleHistoryToRecords(stateHistory, filters), [filters, stateHistory]);
}
export function ruleHistoryToRecords(stateHistory?: DataFrameJSON, filters = emptyFilters) {
const { labels, stateFrom, stateTo } = filters;
if (!stateHistory?.data) {
return { historyRecords: [] };
}
const filterMatchers = labels ? parsePromQLStyleMatcherLooseSafe(labels) : [];
const [tsValues, lines] = stateHistory.data.values;
const timestamps = isNumbers(tsValues) ? tsValues : [];
// merge timestamp with "line"
const logRecords = timestamps.reduce((acc: LogRecord[], timestamp: number, index: number) => {
const line = lines[index];
if (!isLine(line)) {
return acc;
}
// values property can be undefined for some instance states (e.g. NoData)
const filterMatch = line.labels && labelsMatchMatchers(line.labels, filterMatchers);
const baseStateTo = mapStateWithReasonToBaseState(line.current);
const baseStateFrom = mapStateWithReasonToBaseState(line.previous);
const stateToMatch = stateTo !== StateFilterValues.all ? stateTo === baseStateTo : true;
const stateFromMatch = stateFrom !== StateFilterValues.all ? stateFrom === baseStateFrom : true;
if (filterMatch && stateToMatch && stateFromMatch) {
acc.push({ timestamp, line });
}
return acc;
}, []);
return {
historyRecords: logRecords,
};
}

View File

@ -0,0 +1,12 @@
import fixtureData from './__fixtures__/alert-state-history';
import { historyResultToDataFrame } from './utils';
describe('historyResultToDataFrame', () => {
it('should decode', () => {
expect(historyResultToDataFrame(fixtureData)).toMatchSnapshot();
});
it('should decode and filter', () => {
expect(historyResultToDataFrame(fixtureData, { stateFrom: 'Pending', stateTo: 'Alerting' })).toMatchSnapshot();
});
});

View File

@ -12,7 +12,7 @@ import {
getDisplayProcessor,
} from '@grafana/data';
import { fieldIndexComparer } from '@grafana/data/src/field/fieldComparers';
import { isGrafanaAlertState, mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
import { mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
import { labelsMatchMatchers } from '../../../utils/alertmanager';
import { parsePromQLStyleMatcherLooseSafe } from '../../../utils/matchers';
@ -23,43 +23,43 @@ import { LABELS_FILTER, STATE_FILTER_FROM, STATE_FILTER_TO, StateFilterValues }
const GROUPING_INTERVAL = 10 * 1000; // 10 seconds
const QUERY_PARAM_PREFIX = 'var-'; // Prefix used by Grafana to sync variables in the URL
const emptyFilters = {
stateTo: 'all',
stateFrom: 'all',
};
/*
* This function is used to convert the history response to a DataFrame list and filter the data by labels and states
* The response is a list of log records, each log record has a timestamp and a line.
* We group all records by alert instance (unique set of labels) and create a DataFrame for each group (instance).
* This allows us to be able to filter by labels and states in the groupDataFramesByTime function.
*/
export function historyResultToDataFrame(data: DataFrameJSON): DataFrame[] {
// Get the labels and states filters from the URL
const stateToInQueryParams = getStateFilterToInQueryParams();
const stateFromInQueryParams = getStateFilterFromInQueryParams();
const stateToFilterValue = stateToInQueryParams === '' ? StateFilterValues.all : stateToInQueryParams;
const stateFromFilterValue = stateFromInQueryParams === '' ? StateFilterValues.all : stateFromInQueryParams;
export function historyResultToDataFrame({ data }: DataFrameJSON, filters = emptyFilters): DataFrame[] {
const { stateTo, stateFrom } = filters;
// Extract timestamps and lines from the response
const tsValues = data?.data?.values[0] ?? [];
const timestamps: number[] = isNumbers(tsValues) ? tsValues : [];
const lines = data?.data?.values[1] ?? [];
const [tsValues = [], lines = []] = data?.values ?? [];
const timestamps = isNumbers(tsValues) ? tsValues : [];
// Filter log records by state and create a list of log records with the timestamp and line
const logRecords = timestamps.reduce((acc: LogRecord[], timestamp: number, index: number) => {
const logRecords = timestamps.reduce<LogRecord[]>((acc, timestamp: number, index: number) => {
const line = lines[index];
// values property can be undefined for some instance states (e.g. NoData)
if (isLine(line)) {
if (!isGrafanaAlertState(line.current)) {
return acc;
}
// we have to filter out by state at that point , because we are going to group by timestamp and these states are going to be lost
const baseStateTo = mapStateWithReasonToBaseState(line.current);
const baseStateFrom = mapStateWithReasonToBaseState(line.previous);
const stateToMatch = stateToFilterValue !== StateFilterValues.all ? stateToFilterValue === baseStateTo : true;
const stateFromMatch =
stateFromFilterValue !== StateFilterValues.all ? stateFromFilterValue === baseStateFrom : true;
// filter by state
if (stateToMatch && stateFromMatch) {
acc.push({ timestamp, line });
}
if (!isLine(line)) {
return acc;
}
// we have to filter out by state at that point , because we are going to group by timestamp and these states are going to be lost
const baseStateTo = mapStateWithReasonToBaseState(line.current);
const baseStateFrom = mapStateWithReasonToBaseState(line.previous);
const stateToMatch = stateTo !== StateFilterValues.all ? stateTo === baseStateTo : true;
const stateFromMatch = stateFrom !== StateFilterValues.all ? stateFrom === baseStateFrom : true;
// filter by state
if (stateToMatch && stateFromMatch) {
acc.push({ timestamp, line });
}
return acc;
}, []);
@ -79,19 +79,21 @@ export function historyResultToDataFrame(data: DataFrameJSON): DataFrame[] {
}
// Scenes sync variables in the URL adding a prefix to the variable name.
function getLabelsFilterInQueryParams() {
export function getLabelsFilterInQueryParams() {
const queryParams = new URLSearchParams(window.location.search);
return queryParams.get(`${QUERY_PARAM_PREFIX}${LABELS_FILTER}`) ?? '';
}
function getStateFilterToInQueryParams() {
export function getStateFilterToInQueryParams() {
const queryParams = new URLSearchParams(window.location.search);
return queryParams.get(`${QUERY_PARAM_PREFIX}${STATE_FILTER_TO}`) ?? '';
return queryParams.get(`${QUERY_PARAM_PREFIX}${STATE_FILTER_TO}`) ?? StateFilterValues.all;
}
function getStateFilterFromInQueryParams() {
export function getStateFilterFromInQueryParams() {
const queryParams = new URLSearchParams(window.location.search);
return queryParams.get(`${QUERY_PARAM_PREFIX}${STATE_FILTER_FROM}`) ?? '';
return queryParams.get(`${QUERY_PARAM_PREFIX}${STATE_FILTER_FROM}`) ?? StateFilterValues.all;
}
/*
* This function groups the data frames by time and filters them by labels.
* The interval is set to 10 seconds.