Skip to content

Commit

Permalink
Show anomaly annotation on timeline
Browse files Browse the repository at this point in the history
  • Loading branch information
phillipb committed Sep 28, 2020
1 parent 9786073 commit 9128aa6
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { useMemo, useCallback, useState, useEffect } from 'react';
import React, { useMemo, useCallback, useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import moment from 'moment';
import { first, last } from 'lodash';
import { EuiLoadingChart, EuiText, EuiEmptyPrompt, EuiButton } from '@elastic/eui';
import { EuiLoadingChart, EuiText, EuiEmptyPrompt, EuiButton, EuiIcon } from '@elastic/eui';
import {
Axis,
Chart,
Expand All @@ -18,6 +18,9 @@ import {
TooltipValue,
niceTimeFormatter,
ElementClickListener,
LineAnnotation,
AnnotationDomainTypes,
LineAnnotationDatum,
} from '@elastic/charts';
import { useUiSetting } from '../../../../../../../../../src/plugins/kibana_react/public';
import { toMetricOpt } from '../../../../../../common/snapshot_metric_i18n';
Expand Down Expand Up @@ -49,18 +52,8 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
const { metric, nodeType, accountId, region } = useWaffleOptionsContext();
const { currentTime, jumpToTime, stopAutoReload } = useWaffleTimeContext();
const { filterQueryAsJson } = useWaffleFiltersContext();
const [start] = useState(moment().toDate().getTime());

const SORT_DEFAULTS = {
direction: 'desc' as const,
field: 'anomalyScore' as const,
};

const PAGINATION_DEFAULTS = {
pageSize: 100,
};

const { loading, error, timeseries, reload } = useTimeline(
const { loading, error, startTime, endTime, timeseries, reload } = useTimeline(
filterQueryAsJson,
[metric],
nodeType,
Expand All @@ -72,21 +65,23 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
isVisible
);

const { metricsHostsAnomalies, getMetricsHostsAnomalies } = useMetricsHostsAnomaliesResults({
const anomalyParams = {
sourceId: 'default',
startTime: moment(new Date(start)).subtract(10, 'd').toDate().getTime(),
endTime: start,
defaultSortOptions: SORT_DEFAULTS,
defaultPaginationOptions: PAGINATION_DEFAULTS,
});
startTime,
endTime,
defaultSortOptions: {
direction: 'desc' as const,
field: 'anomalyScore' as const,
},
defaultPaginationOptions: { pageSize: 100 },
};

const { metricsK8sAnomalies, getMetricsK8sAnomalies } = useMetricsK8sAnomaliesResults({
sourceId: 'default',
startTime: moment(new Date(start)).subtract(10, 'd').toDate().getTime(),
endTime: start,
defaultSortOptions: SORT_DEFAULTS,
defaultPaginationOptions: PAGINATION_DEFAULTS,
});
const { metricsHostsAnomalies, getMetricsHostsAnomalies } = useMetricsHostsAnomaliesResults(
anomalyParams
);
const { metricsK8sAnomalies, getMetricsK8sAnomalies } = useMetricsK8sAnomaliesResults(
anomalyParams
);

const getAnomalies = useMemo(() => {
if (nodeType === 'host') {
Expand All @@ -96,13 +91,13 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
}
}, [nodeType, getMetricsK8sAnomalies, getMetricsHostsAnomalies]);

// const anomalies = useMemo(() => {
// if (nodeType === 'host') {
// return metricsHostsAnomalies;
// } else if (nodeType === 'pod') {
// return metricsK8sAnomalies;
// }
// }, [nodeType, metricsHostsAnomalies, metricsK8sAnomalies]);
const anomalies = useMemo(() => {
if (nodeType === 'host') {
return metricsHostsAnomalies;
} else if (nodeType === 'pod') {
return metricsK8sAnomalies;
}
}, [nodeType, metricsHostsAnomalies, metricsK8sAnomalies]);

const metricLabel = toMetricOpt(metric.type)?.textLC;

Expand Down Expand Up @@ -194,6 +189,10 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
);
}

function generateAnnotationData(values: any[]): LineAnnotationDatum[] {
return values.map((value, index) => ({ dataValue: value, details: `detail-${index}` }));
}

return (
<TimelineContainer>
<TimelineHeader>
Expand All @@ -209,6 +208,19 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
</TimelineHeader>
<TimelineChartContainer>
<Chart>
{(anomalies || []).map((a) => {
return (
<LineAnnotation
key={a.id}
id={a.id}
domainType={AnnotationDomainTypes.XDomain}
dataValues={generateAnnotationData([a.startTime, 0])}
style={annotationStyle}
marker={<EuiIcon onClick={() => alert('clicked')} iconType="alert" />}
markerPosition={'bottom'}
/>
);
})}
<MetricExplorerSeriesChart
type={MetricsExplorerChartType.area}
metric={chartMetric}
Expand Down Expand Up @@ -241,6 +253,21 @@ export const Timeline: React.FC<Props> = ({ interval, yAxisFormatter, isVisible
);
};

const annotationStyle = {
line: {
strokeWidth: 3,
stroke: '#f00',
opacity: 1,
},
details: {
fontSize: 12,
fontFamily: 'Arial',
fontStyle: 'bold',
fill: 'gray',
padding: 0,
},
};

const TimelineContainer = euiStyled.div`
background-color: ${(props) => props.theme.eui.euiPageBackgroundColor};
border-top: 1px solid ${(props) => props.theme.eui.euiColorLightShade};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ export function useTimeline(
]);
const { timeLength, intervalInSeconds } = timeLengthResult;

const endTime = currentTime + intervalInSeconds * 1000;
const startTime = currentTime - timeLength * 1000;
const timerange: InfraTimerangeInput = {
interval: displayInterval ?? '',
to: currentTime + intervalInSeconds * 1000,
from: currentTime - timeLength * 1000,
to: endTime,
from: startTime,
ignoreLookback: true,
forceInterval: true,
};
Expand Down Expand Up @@ -127,6 +129,8 @@ export function useTimeline(
error: (error && error.message) || null,
loading: !interval ? true : loading,
timeseries,
startTime,
endTime,
reload: makeRequest,
};
}

0 comments on commit 9128aa6

Please sign in to comment.