Skip to content
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

[ML] AIOps: Adds dip support to log rate analysis in ML AIOps Labs #163100

Merged
merged 21 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions x-pack/packages/ml/aiops_components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,9 @@

export { DualBrush, DualBrushAnnotation } from './src/dual_brush';
export { ProgressControls } from './src/progress_controls';
export { DocumentCountChart } from './src/document_count_chart';
export type { DocumentCountChartPoint, DocumentCountChartProps } from './src/document_count_chart';
export {
DocumentCountChart,
type BrushSettings,
type BrushSelectionUpdateHandler,
} from './src/document_count_chart';
export type { DocumentCountChartProps } from './src/document_count_chart';
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,21 @@ import {

import { i18n } from '@kbn/i18n';
import { IUiSettingsClient } from '@kbn/core/public';
import { getSnappedWindowParameters, getWindowParameters } from '@kbn/aiops-utils';
import type { WindowParameters } from '@kbn/aiops-utils';
import {
getLogRateAnalysisType,
getSnappedWindowParameters,
getWindowParameters,
type LogRateAnalysisType,
type LogRateHistogramItem,
type WindowParameters,
} from '@kbn/aiops-utils';
import { MULTILAYER_TIME_AXIS_STYLE } from '@kbn/charts-plugin/common';

import type { DataPublicPluginStart } from '@kbn/data-plugin/public';
import type { ChartsPluginStart } from '@kbn/charts-plugin/public';
import type { FieldFormatsStart } from '@kbn/field-formats-plugin/public';

import { DualBrush, DualBrushAnnotation } from '../..';

import { BrushBadge } from './brush_badge';

declare global {
Expand All @@ -51,20 +58,6 @@ interface TimeFilterRange {
to: number;
}

/**
* Datum for the bar chart
*/
export interface DocumentCountChartPoint {
/**
* Time of bucket
*/
time: number | string;
/**
* Number of doc count for that time bucket
*/
value: number;
}

/**
* Brush settings
*/
Expand All @@ -83,6 +76,19 @@ export interface BrushSettings {
badgeWidth?: number;
}

/**
* Callback function which gets called when the brush selection has changed
*
* @param windowParameters Baseline and deviation time ranges.
* @param force Force update
* @param logRateAnalysisType `spike` or `dip` based on median log rate bucket size
*/
export type BrushSelectionUpdateHandler = (
windowParameters: WindowParameters,
force: boolean,
logRateAnalysisType: LogRateAnalysisType
) => void;

/**
* Props for document count chart
*/
Expand All @@ -94,14 +100,14 @@ export interface DocumentCountChartProps {
fieldFormats: FieldFormatsStart;
uiSettings: IUiSettingsClient;
};
/** Optional callback function which gets called the brush selection has changed */
brushSelectionUpdateHandler?: (windowParameters: WindowParameters, force: boolean) => void;
/** Optional callback for handling brush selection updates */
brushSelectionUpdateHandler?: BrushSelectionUpdateHandler;
/** Optional width */
width?: number;
/** Data chart points */
chartPoints: DocumentCountChartPoint[];
chartPoints: LogRateHistogramItem[];
/** Data chart points split */
chartPointsSplit?: DocumentCountChartPoint[];
chartPointsSplit?: LogRateHistogramItem[];
/** Start time range for the chart */
timeRangeEarliest: number;
/** Ending time range for the chart */
Expand Down Expand Up @@ -162,42 +168,30 @@ function getBaselineBadgeOverflow(
/**
* Document count chart with draggable brushes to select time ranges
* by default use `Baseline` and `Deviation` for the badge names
* @param dependencies - List of Kibana services that are required as dependencies
* @param brushSelectionUpdateHandler - Optional callback function which gets called the brush selection has changed
* @param width - Optional width
* @param chartPoints - Data chart points
* @param chartPointsSplit - Data chart points split
* @param timeRangeEarliest - Start time range for the chart
* @param timeRangeLatest - Ending time range for the chart
* @param interval - Time interval for the document count buckets
* @param chartPointsSplitLabel - Label to name the adjustedChartPointsSplit histogram
* @param isBrushCleared - Whether or not brush has been reset
* @param autoAnalysisStart - Timestamp for start of initial analysis
* @param barColorOverride - Optional color override for the default bar color for charts
* @param barStyleAccessor - Optional style to override bar chart
* @param barHighlightColorOverride - Optional color override for the highlighted bar color for charts
* @param deviationBrush - Optional settings override for the 'deviation' brush
* @param baselineBrush - Optional settings override for the 'baseline' brush
* @constructor
*
* @param props DocumentCountChart component props
* @returns The DocumentCountChart component.
*/
export const DocumentCountChart: FC<DocumentCountChartProps> = ({
dependencies,
brushSelectionUpdateHandler,
width,
chartPoints,
chartPointsSplit,
timeRangeEarliest,
timeRangeLatest,
interval,
chartPointsSplitLabel,
isBrushCleared,
autoAnalysisStart,
barColorOverride,
barStyleAccessor,
barHighlightColorOverride,
deviationBrush = {},
baselineBrush = {},
}) => {
export const DocumentCountChart: FC<DocumentCountChartProps> = (props) => {
const {
dependencies,
brushSelectionUpdateHandler,
width,
chartPoints,
chartPointsSplit,
timeRangeEarliest,
timeRangeLatest,
interval,
chartPointsSplitLabel,
isBrushCleared,
autoAnalysisStart,
barColorOverride,
barStyleAccessor,
barHighlightColorOverride,
deviationBrush = {},
baselineBrush = {},
} = props;

const { data, uiSettings, fieldFormats, charts } = dependencies;

const chartTheme = charts.theme.useChartsTheme();
Expand Down Expand Up @@ -333,8 +327,13 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = ({
const wpSnap = getSnappedWindowParameters(wp, snapTimestamps);
setOriginalWindowParameters(wpSnap);
setWindowParameters(wpSnap);

if (brushSelectionUpdateHandler !== undefined) {
brushSelectionUpdateHandler(wpSnap, true);
brushSelectionUpdateHandler(
wpSnap,
true,
getLogRateAnalysisType(adjustedChartPoints, wpSnap)
);
}
}
}
Expand Down Expand Up @@ -385,7 +384,7 @@ export const DocumentCountChart: FC<DocumentCountChartProps> = ({
}
setWindowParameters(wp);
setWindowParametersAsPixels(wpPx);
brushSelectionUpdateHandler(wp, false);
brushSelectionUpdateHandler(wp, false, getLogRateAnalysisType(adjustedChartPoints, wp));
}

const [mlBrushWidth, setMlBrushWidth] = useState<number>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
*/

export { DocumentCountChart } from './document_count_chart';
export type { DocumentCountChartPoint, DocumentCountChartProps } from './document_count_chart';
export type {
BrushSelectionUpdateHandler,
BrushSettings,
DocumentCountChartProps,
} from './document_count_chart';
45 changes: 10 additions & 35 deletions x-pack/packages/ml/aiops_components/src/dual_brush/dual_brush.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import { isEqual } from 'lodash';
import React, { useEffect, useRef } from 'react';
import React, { useEffect, useRef, type FC } from 'react';

import * as d3Brush from 'd3-brush';
import * as d3Scale from 'd3-scale';
Expand Down Expand Up @@ -54,6 +54,9 @@ const BRUSH_MARGIN = 4;
const BRUSH_HANDLE_SIZE = 4;
const BRUSH_HANDLE_ROUNDED_CORNER = 2;

/**
* Props for the DualBrush React Component
*/
interface DualBrushProps {
/**
* Min and max numeric timestamps for the two brushes
Expand Down Expand Up @@ -88,40 +91,12 @@ interface DualBrushProps {
/**
* DualBrush React Component
* Dual brush component that overlays the document count chart
* @type {FC<DualBrushProps>}
* @param props - `DualBrushProps` component props
* @returns {React.ReactElement} The DualBrush component.
*
* @param props DualBrushProps component props
* @returns The DualBrush component.
*/
export function DualBrush({
/**
* Min and max numeric timestamps for the two brushes
*/
windowParameters,
/**
* Min timestamp for x domain
*/
min,
/**
* Max timestamp for x domain
*/
max,
/**
* Callback function whenever the brush changes
*/
onChange,
/**
* Margin left
*/
marginLeft,
/**
* Nearest timestamps to snap to the brushes to
*/
snapTimestamps,
/**
* Width
*/
width,
}: DualBrushProps) {
export const DualBrush: FC<DualBrushProps> = (props) => {
const { windowParameters, min, max, onChange, marginLeft, snapTimestamps, width } = props;
const d3BrushContainer = useRef(null);
const brushes = useRef<DualBrush[]>([]);

Expand Down Expand Up @@ -383,4 +358,4 @@ export function DualBrush({
)}
</>
);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ interface BrushAnnotationProps {
/**
* DualBrushAnnotation React Component
* Dual brush annotation component that overlays the document count chart
* @type {FC<BrushAnnotationProps>}
* @param props - `BrushAnnotationProps` component props
* @returns {React.ReactElement} The DualBrushAnnotation component.
*
* @param props BrushAnnotationProps component props
* @returns The DualBrushAnnotation component.
*/
export const DualBrushAnnotation: FC<BrushAnnotationProps> = ({ id, min, max, style }) => {
export const DualBrushAnnotation: FC<BrushAnnotationProps> = (props) => {
const { id, min, max, style } = props;
const { euiTheme } = useEuiTheme();
const { colors } = euiTheme;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,38 +44,25 @@ interface ProgressControlProps {
/**
* ProgressControls React Component
* Component with ability to Run & cancel analysis
* by default use `Baseline` and `Deviation` for the badge name
* @type {FC<ProgressControlProps>}
* @param children - List of Kibana services that are required as dependencies
* @param brushSelectionUpdateHandler - Optional callback function which gets called the brush selection has changed
* @param width - Optional width
* @param chartPoints - Data chart points
* @param chartPointsSplit - Data chart points split
* @param timeRangeEarliest - Start time range for the chart
* @param timeRangeLatest - Ending time range for the chart
* @param interval - Time interval for the document count buckets
* @param chartPointsSplitLabel - Label to name the adjustedChartPointsSplit histogram
* @param isBrushCleared - Whether or not brush has been reset
* @param autoAnalysisStart - Timestamp for start of initial analysis
* @param barColorOverride - Optional color override for the default bar color for charts
* @param barStyleAccessor - Optional style to override bar chart
* @param barHighlightColorOverride - Optional color override for the highlighted bar color for charts
* @param deviationBrush - Optional settings override for the 'deviation' brush
* @param baselineBrush - Optional settings override for the 'baseline' brush
* @returns {React.ReactElement} The ProgressControls component.
* by default uses `Baseline` and `Deviation` for the badge name
*
* @param props ProgressControls component props
* @returns The ProgressControls component.
*/
export const ProgressControls: FC<ProgressControlProps> = ({
children,
isBrushCleared,
progress,
progressMessage,
onRefresh,
onCancel,
onReset,
isRunning,
shouldRerunAnalysis,
runAnalysisDisabled = false,
}) => {
export const ProgressControls: FC<ProgressControlProps> = (props) => {
const {
children,
isBrushCleared,
progress,
progressMessage,
onRefresh,
onCancel,
onReset,
isRunning,
shouldRerunAnalysis,
runAnalysisDisabled = false,
} = props;

const { euiTheme } = useEuiTheme();
const runningProgressBarStyles = useAnimatedProgressBarBackground(euiTheme.colors.success);
const analysisCompleteStyle = { display: 'none' };
Expand Down
57 changes: 57 additions & 0 deletions x-pack/packages/ml/aiops_utils/get_log_rate_analysis_type.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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 type { LogRateHistogramItem } from './log_rate_histogram_item';
import { getLogRateAnalysisType } from './get_log_rate_analysis_type';

describe('getLogRateAnalysisType', () => {
const LogRateHistogramMock: LogRateHistogramItem[] = [
{ time: 0, value: 10 },
{ time: 1, value: 10 },
{ time: 2, value: 10 },
{ time: 3, value: 5 },
{ time: 4, value: 10 },
{ time: 5, value: 10 },
{ time: 6, value: 10 },
{ time: 7, value: 20 },
{ time: 8, value: 10 },
{ time: 9, value: 10 },
];

test('returns "spike" for the given parameters', () => {
expect(
getLogRateAnalysisType(LogRateHistogramMock, {
baselineMin: 4,
baselineMax: 6,
deviationMin: 7,
deviationMax: 8,
})
).toBe('spike');
});

test('returns "dip" for the given parameters', () => {
expect(
getLogRateAnalysisType(LogRateHistogramMock, {
baselineMin: 0,
baselineMax: 2,
deviationMin: 3,
deviationMax: 4,
})
).toBe('dip');
});

test('falls back to "spike" if both time range have the same median', () => {
expect(
getLogRateAnalysisType(LogRateHistogramMock, {
baselineMin: 0,
baselineMax: 2,
deviationMin: 4,
deviationMax: 6,
})
).toBe('spike');
});
});
Loading