Skip to content

Commit

Permalink
[7.x] [Monitoring][Alerting] CCR read exceptions alert (#85908) (#86583)
Browse files Browse the repository at this point in the history
* [Monitoring][Alerting] CCR read exceptions alert (#85908)

* CCR read exceptions all branches

* cleanup

* CR feedback

* Added UI/UX to ccr/shards listing and details

* Fixed snaps

* Added reason for the exception

* Added setup mode funtionality and alert status
# Conflicts:
#	x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js

* Update ccr.js

* Update ccr.test.js.snap
  • Loading branch information
igoristic authored Dec 19, 2020
1 parent 68791e8 commit dcc7393
Show file tree
Hide file tree
Showing 24 changed files with 835 additions and 134 deletions.
22 changes: 22 additions & 0 deletions x-pack/plugins/monitoring/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export const ALERT_MEMORY_USAGE = `${ALERT_PREFIX}alert_jvm_memory_usage`;
export const ALERT_MISSING_MONITORING_DATA = `${ALERT_PREFIX}alert_missing_monitoring_data`;
export const ALERT_THREAD_POOL_SEARCH_REJECTIONS = `${ALERT_PREFIX}alert_thread_pool_search_rejections`;
export const ALERT_THREAD_POOL_WRITE_REJECTIONS = `${ALERT_PREFIX}alert_thread_pool_write_rejections`;
export const ALERT_CCR_READ_EXCEPTIONS = `${ALERT_PREFIX}ccr_read_exceptions`;

/**
* Legacy alerts details/label for server and public use
Expand Down Expand Up @@ -451,6 +452,25 @@ export const ALERT_DETAILS = {
'Alert when the number of rejections in the write thread pool exceeds the threshold.',
}),
},
[ALERT_CCR_READ_EXCEPTIONS]: {
paramDetails: {
duration: {
label: i18n.translate(
'xpack.monitoring.alerts.ccrReadExceptions.paramDetails.duration.label',
{
defaultMessage: `In the last`,
}
),
type: AlertParamType.Duration,
},
},
label: i18n.translate('xpack.monitoring.alerts.ccrReadExceptions.label', {
defaultMessage: 'CCR read exceptions',
}),
description: i18n.translate('xpack.monitoring.alerts.ccrReadExceptions.description', {
defaultMessage: 'Alert if any CCR read exceptions have been detected.',
}),
},
};

export const ALERT_PANEL_MENU = [
Expand Down Expand Up @@ -485,6 +505,7 @@ export const ALERT_PANEL_MENU = [
{ alertName: ALERT_LICENSE_EXPIRATION },
{ alertName: ALERT_THREAD_POOL_SEARCH_REJECTIONS },
{ alertName: ALERT_THREAD_POOL_WRITE_REJECTIONS },
{ alertName: ALERT_CCR_READ_EXCEPTIONS },
],
},
];
Expand All @@ -505,6 +526,7 @@ export const ALERTS = [
ALERT_MISSING_MONITORING_DATA,
ALERT_THREAD_POOL_SEARCH_REJECTIONS,
ALERT_THREAD_POOL_WRITE_REJECTIONS,
ALERT_CCR_READ_EXCEPTIONS,
];

/**
Expand Down
16 changes: 16 additions & 0 deletions x-pack/plugins/monitoring/common/types/alerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface CommonAlertState {

export interface CommonAlertFilter {
nodeUuid?: string;
shardId?: string;
}

export interface CommonAlertParamDetail {
Expand Down Expand Up @@ -103,6 +104,7 @@ export interface AlertUiState {

export interface AlertMessage {
text: string; // Do this. #link this is a link #link
code?: string;
nextSteps?: AlertMessage[];
tokens?: AlertMessageToken[];
}
Expand Down Expand Up @@ -165,6 +167,20 @@ export interface AlertMemoryUsageNodeStats extends AlertNodeStats {
export interface AlertMissingData extends AlertNodeStats {
gapDuration: number;
}
export interface CCRReadExceptionsStats {
remoteCluster: string;
followerIndex: string;
shardId: number;
leaderIndex: string;
lastReadException: { type: string; reason: string };
clusterUuid: string;
ccs: string;
}

export interface CCRReadExceptionsUIMeta extends CCRReadExceptionsStats {
instanceId: string;
itemLabel: string;
}

export interface AlertData {
nodeName?: string;
Expand Down
29 changes: 25 additions & 4 deletions x-pack/plugins/monitoring/public/alerts/callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiIcon,
EuiCodeBlock,
} from '@elastic/eui';
import { replaceTokens } from './lib/replace_tokens';
import { AlertMessage } from '../../common/types/alerts';
Expand Down Expand Up @@ -66,12 +67,24 @@ export const AlertsCallout: React.FC<Props> = (props: Props) => {
</div>
);

const { code } = status.state.state.ui.message;
const accordion = (
<EuiAccordion
id={`monitoringAlertCallout_${index}`}
buttonContent={buttonContent}
paddingSize="s"
>
{code?.length ? (
<EuiCodeBlock
fontSize="s"
paddingSize="s"
language="json"
isCopyable={true}
overflowHeight={300}
>
{code}
</EuiCodeBlock>
) : null}
<EuiListGroup
flush={true}
bordered={true}
Expand All @@ -84,11 +97,19 @@ export const AlertsCallout: React.FC<Props> = (props: Props) => {
paddingLeft: `0.5rem`,
}}
>
{(status.state.state.ui.message.nextSteps || []).map((step: AlertMessage) => {
return <EuiListGroupItem onClick={() => {}} label={replaceTokens(step)} />;
})}
{(status.state.state.ui.message.nextSteps || []).map(
(step: AlertMessage, stepIndex: number) => {
return (
<EuiListGroupItem
onClick={() => {}}
label={replaceTokens(step)}
key={index + stepIndex}
/>
);
}
)}
<EuiListGroupItem
label={<AlertConfiguration alert={status.alert.rawAlert} compressed />}
label={<AlertConfiguration alert={status.alert.rawAlert} key={index} compressed />}
/>
</EuiListGroup>
</EuiAccordion>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import { i18n } from '@kbn/i18n';
import { Expression, Props } from '../components/duration/expression';
import { AlertTypeModel, ValidationResult } from '../../../../triggers_actions_ui/public';
import { ALERT_CCR_READ_EXCEPTIONS, ALERT_DETAILS } from '../../../common/constants';

interface ValidateOptions {
duration: string;
}

const validate = (inputValues: ValidateOptions): ValidationResult => {
const validationResult = { errors: {} };
const errors: { [key: string]: string[] } = {
duration: [],
};
if (!inputValues.duration) {
errors.duration.push(
i18n.translate('xpack.monitoring.alerts.validation.duration', {
defaultMessage: 'A valid duration is required.',
})
);
}
validationResult.errors = errors;
return validationResult;
};

export function createCCRReadExceptionsAlertType(): AlertTypeModel {
return {
id: ALERT_CCR_READ_EXCEPTIONS,
name: ALERT_DETAILS[ALERT_CCR_READ_EXCEPTIONS].label,
description: ALERT_DETAILS[ALERT_CCR_READ_EXCEPTIONS].description,
iconClass: 'bell',
documentationUrl(docLinks) {
return `${docLinks.ELASTIC_WEBSITE_URL}guide/en/kibana/${docLinks.DOC_LINK_VERSION}/kibana-alerts.html`;
},
alertParamsExpression: (props: Props) => (
<Expression {...props} paramDetails={ALERT_DETAILS[ALERT_CCR_READ_EXCEPTIONS].paramDetails} />
),
validate,
defaultActionMessage: '{{context.internalFullMessage}}',
requiresAppContext: true,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export function getAlertPanelsByCategory(
for (const { alert, states } of category.alerts) {
const items = [];
for (const alertState of states.filter(({ state }) => stateFilter(state))) {
const { nodeName, itemLabel } = alertState.state;
items.push({
name: (
<Fragment>
Expand All @@ -188,7 +189,7 @@ export function getAlertPanelsByCategory(
)}
</EuiText>
</EuiToolTip>
<EuiText size="s">{alertState.state.nodeName}</EuiText>
<EuiText size="s">{nodeName || itemLabel}</EuiText>
</Fragment>
),
panel: ++tertiaryPanelIndex,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ export function getAlertPanelsByNode(
const states = (statesByNodes[nodeUuid] as CommonAlertState[]).filter(({ state }) =>
stateFilter(state)
);
const { nodeName, itemLabel } = states[0].state;
return {
name: (
<EuiText>
{states[0].state.nodeName} ({states.length})
{nodeName || itemLabel} ({states.length})
</EuiText>
),
panel: index + 1,
Expand All @@ -86,7 +87,8 @@ export function getAlertPanelsByNode(
let title = '';
for (const { alert, states } of alertsForNode) {
for (const alertState of states) {
title = alertState.state.nodeName;
const { nodeName, itemLabel } = alertState.state;
title = nodeName || itemLabel;
panelItems.push({
name: (
<Fragment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export function replaceTokens(alertMessage: AlertMessage): JSX.Element | string
}

const url = linkToken.partialUrl
.replace('{basePath}', Legacy.shims.getBasePath())
.replace('{elasticWebsiteUrl}', Legacy.shims.docLinks.ELASTIC_WEBSITE_URL)
.replace('{docLinkVersion}', Legacy.shims.docLinks.DOC_LINK_VERSION);
const index = text.indexOf(linkPart[0]);
Expand Down
13 changes: 13 additions & 0 deletions x-pack/plugins/monitoring/public/alerts/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
EuiHorizontalRule,
EuiListGroup,
EuiListGroupItem,
EuiCodeBlock,
} from '@elastic/eui';

import { CommonAlert, CommonAlertState, AlertMessage } from '../../common/types/alerts';
Expand Down Expand Up @@ -47,12 +48,24 @@ export const AlertPanel: React.FC<Props> = (props: Props) => {
</EuiListGroup>
) : null;

const { code } = alertState.state.ui.message;
return (
<Fragment>
<div style={{ padding: '1rem' }}>
<EuiTitle size="xs">
<h5>{replaceTokens(alertState.state.ui.message)}</h5>
</EuiTitle>
{code?.length ? (
<EuiCodeBlock
fontSize="s"
paddingSize="s"
language="json"
isCopyable={true}
overflowHeight={150}
>
{code}
</EuiCodeBlock>
) : null}
{nextStepsUi ? <EuiSpacer size="s" /> : null}
{nextStepsUi}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import {
ALERT_NODES_CHANGED,
ALERT_ELASTICSEARCH_VERSION_MISMATCH,
ALERT_MISSING_MONITORING_DATA,
ALERT_CCR_READ_EXCEPTIONS,
} from '../../../../common/constants';
import { AlertsBadge } from '../../../alerts/badge';
import { shouldShowAlertBadge } from '../../../alerts/lib/should_show_alert_badge';
Expand Down Expand Up @@ -159,7 +160,11 @@ function renderLog(log) {
);
}

const OVERVIEW_PANEL_ALERTS = [ALERT_CLUSTER_HEALTH, ALERT_LICENSE_EXPIRATION];
const OVERVIEW_PANEL_ALERTS = [
ALERT_CLUSTER_HEALTH,
ALERT_LICENSE_EXPIRATION,
ALERT_CCR_READ_EXCEPTIONS,
];

const NODES_PANEL_ALERTS = [
ALERT_CPU_USAGE,
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit dcc7393

Please sign in to comment.