Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add detector state page #65

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
55 changes: 54 additions & 1 deletion public/pages/DetectorDetail/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,57 @@
export enum DETECTOR_DETAIL_TABS {
RESULTS = 'results',
CONFIGURATIONS = 'configurations',
};
}

export const DEFAULT_ACTION_ITEM = 'Please restart this detector to retry.';
// Known causes:
// https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L174-L185
export const DETECTOR_INIT_FAILURES = Object.freeze({
NO_TRAINING_DATA: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L801
keyword: 'Cannot get training data',
cause: 'lack of data ingestion',
actionItem:
'Please make sure your data ingestion is working. Or increase your detector time interval if data source has infrequent ingestion.',
},
COLD_START_ERROR: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L811
keyword: 'Error while cold start',
cause: 'error is found while model initialization',
actionItem: DEFAULT_ACTION_ITEM,
},
AD_MODEL_MEMORY_REACH_LIMIT: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/ml/ModelManager.java#L272
keyword: 'AD models memory usage exceeds our limit',
cause: 'lack of memory for detector models',
actionItem:
'Model of this detector is too large, please reduce the number of features in this detector.',
},
DETECTOR_MEMORY_REACH_LIMIT: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/ml/ModelManager.java#L783
keyword: 'Exceeded memory limit',
cause: 'lack of memory',
actionItem:
"Try deleting or stop other detectors that you don't actively use, increase your cluster size, or reduce the number of features in this detector.",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another action item: scale up with an instance type of more memory

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

},
DATA_INDEX_NOT_FOUND: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L366
keyword: 'Having trouble querying data: ',
cause: 'data index not found',
actionItem: 'Please make sure your data index does exist.',
},
ALL_FEATURES_DISABLED: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L368
keyword:
'Having trouble querying data because all of your features have been disabled',
cause: 'all features in this detector are disabled',
actionItem:
'Please enable some of your features and re-start your detector.',
},
DETECTOR_UNDEFINED: {
//https://github.com/opendistro-for-elasticsearch/anomaly-detection/blob/development/src/main/java/com/amazon/opendistroforelasticsearch/ad/transport/AnomalyResultTransportAction.java#L230
keyword: 'AnomalyDetector is not available',
cause: 'your detector is not defined',
actionItem: 'Please make sure your detector is defined.',
},
});
30 changes: 30 additions & 0 deletions public/pages/DetectorDetail/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import { DETECTOR_INIT_FAILURES, DEFAULT_ACTION_ITEM } from './constants';

export const getInitFailureMessageAndActionItem = (error: string): object => {
const failureDetails = Object.values(DETECTOR_INIT_FAILURES);
const failureDetail = failureDetails.find(failure =>
error.includes(failure.keyword)
);
if (!failureDetail) {
return {
cause: 'unknown error',
actionItem: DEFAULT_ACTION_ITEM,
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this the case where the detector has an unexpected failure (DETECTOR_STATE.UNEXPECTED_FAILURE)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could maybe add this as a DETECTOR_UNEXPECTED_FAILURE const in the constants file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add 'We might have bugs' case to the DETECTOR_INIT_FAILURES, but may keep this piece of code just in case of not handled exception from AD backend.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, sounds good

return failureDetail;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import React from 'react';
import { EuiButton, EuiEmptyPrompt, EuiIcon } from '@elastic/eui';
import { Fragment } from 'react';
import { Detector } from '../../../../models/interfaces';

export interface DetectorInitializationFailureProps {
detector: Detector;
onStartDetector(): void;
failureDetail: any;
onSwitchToConfiguration(): void;
}

export const DetectorInitializationFailure = (
props: DetectorInitializationFailureProps
) => {
return (
<EuiEmptyPrompt
style={{ maxWidth: '75%' }}
title={
<div>
<EuiIcon type="alert" size="l" color="danger" />

<h2>
{`The detector cannot be initialized due to ${props.failureDetail.cause}`}
</h2>
</div>
}
body={
<Fragment>
<p>{`${props.failureDetail.actionItem}`}</p>
</Fragment>
}
actions={[
<EuiButton
onClick={props.onSwitchToConfiguration}
style={{ width: '250px' }}
>
View detector configuration
</EuiButton>,
<EuiButton
onClick={props.onStartDetector}
iconType={'play'}
style={{ width: '250px' }}
>
Restart detector
</EuiButton>,
]}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
import React from 'react';
import { EuiButton, EuiEmptyPrompt, EuiLoadingSpinner } from '@elastic/eui';
import { Fragment } from 'react';
import { Detector } from '../../../../models/interfaces';

export interface DetectorInitializingProps {
detector: Detector;
onSwitchToConfiguration(): void;
}

export const DetectorInitializing = (props: DetectorInitializingProps) => {
return (
<EuiEmptyPrompt
style={{ maxWidth: '75%' }}
title={
<div>
<EuiLoadingSpinner size="l" />
<h2>The detector is initializing...</h2>
</div>
}
body={
<Fragment>
<p>
Based on your latest update to the detector configuration, the
detector is collecting sufficient data to generate accurate
real-time anomalies.
</p>
<p>
The longer the detector interval is, the longer the initialization
will take.
</p>
</Fragment>
}
actions={
<EuiButton
onClick={props.onSwitchToConfiguration}
style={{ width: '250px' }}
>
View detector configuration
</EuiButton>
}
/>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

import React from 'react';
import { EuiButton, EuiEmptyPrompt } from '@elastic/eui';
import { Fragment } from 'react';
import { Detector } from '../../../../models/interfaces';

export interface DetectorStoppedProps {
detector: Detector;
onStartDetector(): void;
onSwitchToConfiguration(): void;
}

export const DetectorStopped = (props: DetectorStoppedProps) => {
return (
<EuiEmptyPrompt
style={{ maxWidth: '75%' }}
title={<h2>The detector is stopped</h2>}
body={
<Fragment>
{props.detector.enabledTime ? (
<p>
The detector is stopped due to your latest update to the detector
configuration. Run the detector to see anomalies.
</p>
) : (
<p>
The detector is never started. Please start the detector to see
anomalies.
</p>
)}
</Fragment>
}
actions={[
<EuiButton
onClick={props.onSwitchToConfiguration}
style={{ width: '250px' }}
>
View detector configuration
</EuiButton>,
<EuiButton
fill={!props.detector.enabledTime}
onClick={props.onStartDetector}
iconType={'play'}
style={{ width: '250px' }}
>
{props.detector.enabledTime ? 'Restart detector' : 'Start detector'}
</EuiButton>,
]}
/>
);
};
20 changes: 14 additions & 6 deletions public/pages/DetectorResults/containers/AnomalyResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ import { RouteComponentProps } from 'react-router';
//@ts-ignore
import chrome from 'ui/chrome';
import { AppState } from '../../../redux/reducers';
import { BREADCRUMBS } from '../../../utils/constants';
import { BREADCRUMBS, DETECTOR_STATE } from '../../../utils/constants';
import { AnomalyResultsLiveChart } from './AnomalyResultsLiveChart';
import { AnomalyHistory } from './AnomalyHistory';
import { DetectorStateDetails } from './DetectorStateDetails';

interface AnomalyResultsProps extends RouteComponentProps {
detectorId: string;
onStartDetector(): void;
onSwitchToConfiguration(): void;
}

Expand All @@ -60,7 +62,7 @@ export function AnomalyResults(props: AnomalyResultsProps) {
<EuiPage style={{ marginTop: '16px', paddingTop: '0px' }}>
<EuiPageBody>
<EuiSpacer size="l" />
{detector && isEmpty(detector.featureAttributes) ? (
{detector && detector.curState === DETECTOR_STATE.FEATURE_REQUIRED ? (
<EuiEmptyPrompt
title={<h2>Features are required to run a detector</h2>}
body={
Expand All @@ -84,7 +86,7 @@ export function AnomalyResults(props: AnomalyResultsProps) {
/>
) : (
<Fragment>
{detector ? (
{detector && detector.curState === DETECTOR_STATE.RUNNING ? (
<Fragment>
{!detector.enabled &&
detector.disabledTime &&
Expand All @@ -106,9 +108,7 @@ export function AnomalyResults(props: AnomalyResultsProps) {
</EuiButton>
</EuiCallOut>
) : null}
<AnomalyResultsLiveChart
detector={detector}
/>
<AnomalyResultsLiveChart detector={detector} />
<EuiSpacer size="l" />
<AnomalyHistory
detector={detector}
Expand All @@ -118,6 +118,14 @@ export function AnomalyResults(props: AnomalyResultsProps) {
}
/>
</Fragment>
) : detector && detector.curState !== DETECTOR_STATE.RUNNING ? (
<Fragment>
<DetectorStateDetails
detector={detector}
onStartDetector={props.onStartDetector}
onSwitchToConfiguration={props.onSwitchToConfiguration}
/>
</Fragment>
) : null}
</Fragment>
)}
Expand Down
Loading