Skip to content

Commit

Permalink
[Synthetics] Fix active error state (elastic#160818)
Browse files Browse the repository at this point in the history
Co-authored-by: Shahzad <shahzad31comp@gmail.com>
  • Loading branch information
2 people authored and pull[bot] committed Nov 15, 2023
1 parent c7a8ee4 commit 8bc4251
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import moment from 'moment';
import { useTimeZone } from '@kbn/observability-shared-plugin/public';
import { useParams } from 'react-router-dom';
import { useMemo } from 'react';
Expand Down Expand Up @@ -49,11 +48,6 @@ export function useMonitorErrors(monitorIdArg?: string) {
},
},
},
{
term: {
'state.up': 0,
},
},
{
term: {
config_id: monitorIdArg ?? monitorId,
Expand All @@ -69,7 +63,7 @@ export function useMonitorErrors(monitorIdArg?: string) {
},
sort: [{ 'state.started_at': 'desc' }],
aggs: {
errorStates: {
states: {
terms: {
field: 'state.id',
size: 10000,
Expand All @@ -84,6 +78,13 @@ export function useMonitorErrors(monitorIdArg?: string) {
},
},
},
latest: {
top_hits: {
size: 1,
_source: ['monitor.status'],
sort: [{ '@timestamp': 'desc' }],
},
},
},
},
},
Expand All @@ -95,27 +96,35 @@ export function useMonitorErrors(monitorIdArg?: string) {
);

return useMemo(() => {
const errorStates = data?.aggregations?.errorStates.buckets?.map((loc) => {
return loc.summary.hits.hits?.[0]._source as PingState;
});
const defaultValues = { upStates: [], errorStates: [] };
// re-bucket states into error/up
// including the `up` states is useful for determining error duration
const { errorStates, upStates } =
data?.aggregations?.states.buckets.reduce<{
upStates: PingState[];
errorStates: PingState[];
}>((prev, cur) => {
const source = cur.summary.hits.hits?.[0]._source as PingState | undefined;
if (source?.state.up === 0) {
prev.errorStates.push(source as PingState);
} else if (!!source?.state.up && source.state.up >= 1) {
prev.upStates.push(source as PingState);
}
return prev;
}, defaultValues) ?? defaultValues;

const hasActiveError: boolean =
errorStates?.some((errorState) => isActiveState(errorState)) || false;
data?.aggregations?.latest.hits.hits.length === 1 &&
(data?.aggregations?.latest.hits.hits[0]._source as { monitor: { status: string } }).monitor
.status === 'down' &&
!!errorStates?.length;

return {
errorStates,
upStates,
loading,
data,
hasActiveError,
};
}, [data, loading]);
}

export const isActiveState = (item: PingState) => {
const timestamp = item['@timestamp'];
const interval = moment(item.monitor.timespan?.lt).diff(
moment(item.monitor.timespan?.gte),
'milliseconds'
);
return moment().diff(moment(timestamp), 'milliseconds') < interval;
};

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,31 @@ import { Ping, PingState } from '../../../../../../common/runtime_types';
import { useErrorFailedStep } from '../hooks/use_error_failed_step';
import { formatTestDuration } from '../../../utils/monitor_test_result/test_time_formats';
import { useDateFormat } from '../../../../../hooks/use_date_format';
import { isActiveState } from '../hooks/use_monitor_errors';
import { useMonitorLatestPing } from '../hooks/use_monitor_latest_ping';

export function isErrorActive(item: PingState, lastErrorId?: string, latestPingStatus?: string) {
// if the error is the most recent, `isActiveState`, and the monitor
// is not yet back up, label the error as active
return isActiveState(item) && lastErrorId === item.state.id && latestPingStatus !== 'up';
function isErrorActive(lastError: PingState, currentError: PingState, latestPing?: Ping) {
return (
latestPing?.monitor.status === 'down' &&
lastError['@timestamp'] === currentError['@timestamp'] &&
typeof currentError['@timestamp'] !== undefined
);
}

function getNextUpStateForResolvedError(errorState: PingState, upStates: PingState[]) {
for (const upState of upStates) {
if (moment(upState.state.started_at).valueOf() > moment(errorState['@timestamp']).valueOf())
return upState;
}
}

export const ErrorsList = ({
errorStates,
upStates,
loading,
location,
}: {
errorStates: PingState[];
upStates: PingState[];
loading: boolean;
location: ReturnType<typeof useSelectedLocation>;
}) => {
Expand All @@ -64,7 +74,6 @@ export const ErrorsList = ({
const lastErrorTestRun = errorStates?.sort((a, b) => {
return moment(b.state.started_at).valueOf() - moment(a.state.started_at).valueOf();
})?.[0];

const isTabletOrGreater = useIsWithinMinBreakpoint('s');

const columns = [
Expand All @@ -83,7 +92,8 @@ export const ErrorsList = ({
locationId={location?.id}
/>
);
if (isErrorActive(item, lastErrorTestRun?.state.id, latestPing?.monitor.status)) {

if (isErrorActive(lastErrorTestRun, item, latestPing)) {
return (
<EuiFlexGroup gutterSize="m" alignItems="center" wrap={true}>
<EuiFlexItem grow={false} className="eui-textNoWrap">
Expand Down Expand Up @@ -118,7 +128,7 @@ export const ErrorsList = ({
}
return failedStep.synthetics?.step?.name;
},
render: (value: string, item: PingState) => {
render: (value: string) => {
const failedStep = failedSteps.find((step) => step.monitor.check_group === value);
if (!failedStep) {
return <>--</>;
Expand All @@ -142,19 +152,20 @@ export const ErrorsList = ({
align: 'right' as const,
sortable: true,
render: (value: string, item: PingState) => {
const isActive = isActiveState(item);
let activeDuration = 0;
if (item.monitor.timespan) {
const diff = moment(item.monitor.timespan.lt).diff(
moment(item.monitor.timespan.gte),
'millisecond'
);
if (isActive) {
if (isErrorActive(lastErrorTestRun, item, latestPing)) {
const currentDiff = moment().diff(item['@timestamp']);

activeDuration = currentDiff < diff ? currentDiff : diff;
} else {
activeDuration = diff;
const resolvedState = getNextUpStateForResolvedError(item, upStates);

activeDuration = moment(resolvedState?.state.started_at).diff(item['@timestamp']) ?? 0;
}
}
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ export const ErrorsTabContent = ({
errorStates,
loading,
location,
upStates,
}: {
errorStates: PingState[];
upStates: PingState[];
loading: boolean;
location: ReturnType<typeof useSelectedLocation>;
}) => {
Expand Down Expand Up @@ -69,7 +71,12 @@ export const ErrorsTabContent = ({
<EuiFlexGroup gutterSize="m" wrap={true}>
<EuiFlexItem grow={2} css={{ minWidth: 260 }}>
<PanelWithTitle title={ERRORS_LABEL}>
<ErrorsList location={location} errorStates={errorStates} loading={loading} />
<ErrorsList
location={location}
errorStates={errorStates}
upStates={upStates}
loading={loading}
/>
</PanelWithTitle>
</EuiFlexItem>
<FailedTestsByStep time={time} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { MonitorPendingWrapper } from '../monitor_pending_wrapper';
import { useSelectedLocation } from '../hooks/use_selected_location';

export const MonitorErrors = () => {
const { errorStates, loading, data } = useMonitorErrors();
const { errorStates, upStates, loading, data } = useMonitorErrors();
const location = useSelectedLocation();

const initialLoading = !data;
Expand All @@ -42,7 +42,12 @@ export const MonitorErrors = () => {
{initialLoading && <LoadingErrors />}
{emptyState && <EmptyErrors />}
<div style={{ visibility: initialLoading || emptyState ? 'collapse' : 'initial' }}>
<ErrorsTabContent location={location} errorStates={errorStates ?? []} loading={loading} />
<ErrorsTabContent
location={location}
errorStates={errorStates}
upStates={upStates}
loading={loading}
/>
</div>
</MonitorPendingWrapper>
);
Expand Down

0 comments on commit 8bc4251

Please sign in to comment.