[ML] AIOps: Consolidate code related to retrieving log rate analysis parameters from alert metadata. (#188012)

## Summary

Part of #178613.

Consolidates code related to retrieving log rate analysis parameters
from alert metadata.
This commit is contained in:
Walter Rafelsberger 2024-07-15 14:35:42 +02:00 committed by GitHub
parent 73b6a98b47
commit a87d6ccb1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 82 additions and 133 deletions

View file

@ -5,19 +5,51 @@
* 2.0.
*/
import moment, { Moment } from 'moment';
import moment, { type Moment } from 'moment';
export interface GetInitialAnalysisStartArgs {
export interface GetLogRateAnalysisParametersFromAlertArgs {
alertStartedAt: string;
alertEndedAt?: string;
timeSize?: number;
timeUnit?: moment.unitOfTime.DurationConstructor;
}
export const getLogRateAnalysisParametersFromAlert = ({
alertStartedAt,
alertEndedAt,
timeSize,
timeUnit,
}: GetLogRateAnalysisParametersFromAlertArgs) => {
// Identify `intervalFactor` to adjust time ranges based on alert settings.
// The default time ranges for `initialAnalysisStart` are suitable for a `1m` lookback.
// If an alert would have a `5m` lookback, this would result in a factor of `5`.
const lookbackDuration =
timeSize && timeUnit ? moment.duration(timeSize, timeUnit) : moment.duration(1, 'm');
const intervalFactor = Math.max(1, lookbackDuration.asSeconds() / 60);
const alertStart = moment(alertStartedAt);
const alertEnd = alertEndedAt ? moment(alertEndedAt) : undefined;
const helperArgs = { alertStart, alertEnd, intervalFactor };
const timeRange = {
min: alertStart.clone().subtract(15 * intervalFactor, 'minutes'),
max: getTimeRangeEnd(helperArgs),
};
return {
timeRange,
windowParameters: getWindowParameters(helperArgs),
};
};
interface GetParameterHelperArgs {
alertStart: Moment;
intervalFactor: number;
alertEnd?: Moment;
}
export const getTimeRangeEnd = ({
alertStart,
intervalFactor,
alertEnd,
}: GetInitialAnalysisStartArgs) => {
function getTimeRangeEnd({ alertStart, alertEnd, intervalFactor }: GetParameterHelperArgs) {
if (alertEnd) {
if (
alertStart
@ -39,13 +71,9 @@ export const getTimeRangeEnd = ({
} else {
return alertStart.clone().add(15 * intervalFactor, 'minutes');
}
};
}
export const getDeviationMax = ({
alertStart,
intervalFactor,
alertEnd,
}: GetInitialAnalysisStartArgs) => {
function getDeviationMax({ alertStart, alertEnd, intervalFactor }: GetParameterHelperArgs) {
if (alertEnd) {
if (
alertStart
@ -76,9 +104,9 @@ export const getDeviationMax = ({
.add(10 * intervalFactor, 'minutes')
.valueOf();
}
};
}
export const getInitialAnalysisStart = (args: GetInitialAnalysisStartArgs) => {
function getWindowParameters(args: GetParameterHelperArgs) {
const { alertStart, intervalFactor } = args;
return {
baselineMin: alertStart
@ -95,4 +123,4 @@ export const getInitialAnalysisStart = (args: GetInitialAnalysisStartArgs) => {
.valueOf(),
deviationMax: getDeviationMax(args),
};
};
}

View file

@ -16,13 +16,14 @@ import {
LOG_RATE_ANALYSIS_TYPE,
type LogRateAnalysisType,
} from '@kbn/aiops-log-rate-analysis/log_rate_analysis_type';
import { getLogRateAnalysisParametersFromAlert } from '@kbn/aiops-log-rate-analysis/get_log_rate_analysis_parameters_from_alert';
import { LogRateAnalysisContent, type LogRateAnalysisResultsData } from '@kbn/aiops-plugin/public';
import { Rule } from '@kbn/alerting-plugin/common';
import { TopAlert } from '@kbn/observability-plugin/public';
import { ALERT_END } from '@kbn/rule-data-utils';
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { i18n } from '@kbn/i18n';
import { ALERT_END } from '@kbn/rule-data-utils';
import { pick, orderBy } from 'lodash';
import { Color, colorTransformer } from '../../../../../../common/color_palette';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
@ -89,100 +90,23 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
}
}, [validatedParams, alert, dataViews, logsShared]);
// Identify `intervalFactor` to adjust time ranges based on alert settings.
// The default time ranges for `initialAnalysisStart` are suitable for a `1m` lookback.
// If an alert would have a `5m` lookback, this would result in a factor of `5`.
const lookbackDuration =
alert.fields['kibana.alert.rule.parameters'] &&
alert.fields['kibana.alert.rule.parameters'].timeSize &&
alert.fields['kibana.alert.rule.parameters'].timeUnit
? moment.duration(
alert.fields['kibana.alert.rule.parameters'].timeSize as number,
alert.fields['kibana.alert.rule.parameters'].timeUnit as any
)
: moment.duration(1, 'm');
const intervalFactor = Math.max(1, lookbackDuration.asSeconds() / 60);
const { timeRange, windowParameters } = useMemo(() => {
const alertStartedAt = moment(alert.start).toISOString();
const alertEndedAt = alert.fields[ALERT_END]
? moment(alert.fields[ALERT_END]).toISOString()
: undefined;
const timeSize = alert.fields['kibana.alert.rule.parameters']?.timeSize as number | undefined;
const timeUnit = alert.fields['kibana.alert.rule.parameters']?.timeUnit as
| moment.unitOfTime.DurationConstructor
| undefined;
const alertStart = moment(alert.start);
const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]) : undefined;
const timeRange = {
min: alertStart.clone().subtract(15 * intervalFactor, 'minutes'),
max: getTimeRangeEnd(),
};
function getTimeRangeEnd() {
if (alertEnd) {
if (
alertStart
.clone()
.add(15 * intervalFactor, 'minutes')
.isAfter(alertEnd)
)
return alertEnd.clone().add(1 * intervalFactor, 'minutes');
else {
return alertStart.clone().add(15 * intervalFactor, 'minutes');
}
} else if (
alertStart
.clone()
.add(15 * intervalFactor, 'minutes')
.isAfter(moment(new Date()))
) {
return moment(new Date());
} else {
return alertStart.clone().add(15 * intervalFactor, 'minutes');
}
}
function getDeviationMax() {
if (alertEnd) {
if (
alertStart
.clone()
.add(10 * intervalFactor, 'minutes')
.isAfter(alertEnd)
)
return alertEnd
.clone()
.subtract(1 * intervalFactor, 'minutes')
.valueOf();
else {
return alertStart
.clone()
.add(10 * intervalFactor, 'minutes')
.valueOf();
}
} else if (
alertStart
.clone()
.add(10 * intervalFactor, 'minutes')
.isAfter(moment(new Date()))
) {
return moment(new Date()).valueOf();
} else {
return alertStart
.clone()
.add(10 * intervalFactor, 'minutes')
.valueOf();
}
}
const initialAnalysisStart = {
baselineMin: alertStart
.clone()
.subtract(13 * intervalFactor, 'minutes')
.valueOf(),
baselineMax: alertStart
.clone()
.subtract(2 * intervalFactor, 'minutes')
.valueOf(),
deviationMin: alertStart
.clone()
.subtract(1 * intervalFactor, 'minutes')
.valueOf(),
deviationMax: getDeviationMax(),
};
return getLogRateAnalysisParametersFromAlert({
alertStartedAt,
alertEndedAt,
timeSize,
timeUnit,
});
}, [alert]);
const logRateAnalysisTitle = i18n.translate(
'xpack.infra.logs.alertDetails.logRateAnalysisTitle',
@ -287,7 +211,7 @@ export const LogRateAnalysis: FC<AlertDetailsLogRateAnalysisSectionProps> = ({ r
dataView={dataView}
timeRange={timeRange}
esSearchQuery={esSearchQuery}
initialAnalysisStart={initialAnalysisStart}
initialAnalysisStart={windowParameters}
barColorOverride={colorTransformer(Color.color0)}
barHighlightColorOverride={colorTransformer(Color.color1)}
onAnalysisCompleted={onAnalysisCompleted}

View file

@ -13,18 +13,18 @@ import {
LOG_RATE_ANALYSIS_TYPE,
type LogRateAnalysisType,
} from '@kbn/aiops-log-rate-analysis/log_rate_analysis_type';
import { getLogRateAnalysisParametersFromAlert } from '@kbn/aiops-log-rate-analysis/get_log_rate_analysis_parameters_from_alert';
import { LogRateAnalysisContent, type LogRateAnalysisResultsData } from '@kbn/aiops-plugin/public';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
import type { Message } from '@kbn/observability-ai-assistant-plugin/public';
import { ALERT_END } from '@kbn/rule-data-utils';
import { Rule } from '@kbn/triggers-actions-ui-plugin/public';
import { ALERT_END } from '@kbn/rule-data-utils';
import { CustomThresholdRuleTypeParams } from '../../types';
import { TopAlert } from '../../../..';
import { Color, colorTransformer } from '../../../../../common/custom_threshold_rule/color_palette';
import { getLogRateAnalysisEQQuery } from './helpers/log_rate_analysis_query';
import { getInitialAnalysisStart, getTimeRangeEnd } from './helpers/get_initial_analysis_start';
export interface AlertDetailsLogRateAnalysisProps {
alert: TopAlert<Record<string, any>>;
@ -66,22 +66,23 @@ export function LogRateAnalysis({
}
}, [alert, rule.params]);
// Identify `intervalFactor` to adjust time ranges based on alert settings.
// The default time ranges for `initialAnalysisStart` are suitable for a `1m` lookback.
// If an alert would have a `5m` lookback, this would result in a factor of `5`.
const lookbackDuration =
rule.params.criteria[0]?.timeSize && rule.params.criteria[0]?.timeUnit
? moment.duration(rule.params.criteria[0].timeSize, rule.params.criteria[0].timeUnit)
: moment.duration(1, 'm');
const intervalFactor = Math.max(1, lookbackDuration.asSeconds() / 60);
const { timeRange, windowParameters } = useMemo(() => {
const alertStartedAt = moment(alert.start).toISOString();
const alertEndedAt = alert.fields[ALERT_END]
? moment(alert.fields[ALERT_END]).toISOString()
: undefined;
const timeSize = rule.params.criteria[0]?.timeSize as number | undefined;
const timeUnit = rule.params.criteria[0]?.timeUnit as
| moment.unitOfTime.DurationConstructor
| undefined;
const alertStart = moment(alert.start);
const alertEnd = alert.fields[ALERT_END] ? moment(alert.fields[ALERT_END]) : undefined;
const timeRange = {
min: alertStart.clone().subtract(15 * intervalFactor, 'minutes'),
max: getTimeRangeEnd({ alertStart, intervalFactor, alertEnd }),
};
return getLogRateAnalysisParametersFromAlert({
alertStartedAt,
alertEndedAt,
timeSize,
timeUnit,
});
}, [alert, rule]);
const logRateAnalysisTitle = i18n.translate(
'xpack.observability.customThreshold.alertDetails.logRateAnalysisTitle',
@ -188,11 +189,7 @@ export function LogRateAnalysis({
dataView={dataView}
timeRange={timeRange}
esSearchQuery={esSearchQuery}
initialAnalysisStart={getInitialAnalysisStart({
alertStart,
intervalFactor,
alertEnd,
})}
initialAnalysisStart={windowParameters}
barColorOverride={colorTransformer(Color.color0)}
barHighlightColorOverride={colorTransformer(Color.color1)}
onAnalysisCompleted={onAnalysisCompleted}