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

[Monitoring] Fix issues displaying alerts #72891

Merged
merged 5 commits into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
36 changes: 24 additions & 12 deletions x-pack/plugins/monitoring/public/alerts/badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,25 @@ import { AlertPanel } from './panel';
import { Legacy } from '../legacy_shims';
import { isInSetupMode } from '../lib/setup_mode';

function getDateFromState(states: CommonAlertState[]) {
const timestamp = states[0].state.ui.triggeredMS;
function getDateFromState(state: CommonAlertState) {
const timestamp = state.state.ui.triggeredMS;
const tz = Legacy.shims.uiSettings.get('dateFormat:tz');
return formatDateTimeLocal(timestamp, false, tz === 'Browser' ? null : tz);
}

export const numberOfAlertsLabel = (count: number) => `${count} alert${count > 1 ? 's' : ''}`;

interface AlertInPanel {
alert: CommonAlertStatus;
alertState: CommonAlertState;
}

interface Props {
alerts: { [alertTypeId: string]: CommonAlertStatus };
stateFilter: (state: AlertState) => boolean;
}
export const AlertsBadge: React.FC<Props> = (props: Props) => {
const { stateFilter = () => true } = props;
const [showPopover, setShowPopover] = React.useState<AlertSeverity | boolean | null>(null);
const inSetupMode = isInSetupMode();
const alerts = Object.values(props.alerts).filter(Boolean);
Expand Down Expand Up @@ -93,15 +100,20 @@ export const AlertsBadge: React.FC<Props> = (props: Props) => {
);
} else {
const byType = {
[AlertSeverity.Danger]: [] as CommonAlertStatus[],
[AlertSeverity.Warning]: [] as CommonAlertStatus[],
[AlertSeverity.Success]: [] as CommonAlertStatus[],
[AlertSeverity.Danger]: [] as AlertInPanel[],
[AlertSeverity.Warning]: [] as AlertInPanel[],
[AlertSeverity.Success]: [] as AlertInPanel[],
};

for (const alert of alerts) {
for (const alertState of alert.states) {
const state = alertState.state as AlertState;
byType[state.ui.severity].push(alert);
if (alertState.firing && stateFilter(alertState.state)) {
const state = alertState.state as AlertState;
byType[state.ui.severity].push({
alertState,
alert,
});
}
}
}

Expand All @@ -127,14 +139,14 @@ export const AlertsBadge: React.FC<Props> = (props: Props) => {
{
id: 0,
title: `Alerts`,
items: list.map(({ alert, states }, index) => {
items: list.map(({ alert, alertState }, index) => {
return {
name: (
<Fragment>
<EuiText size="s">
<h4>{getDateFromState(states)}</h4>
<h4>{getDateFromState(alertState)}</h4>
</EuiText>
<EuiText>{alert.label}</EuiText>
<EuiText>{alert.alert.label}</EuiText>
</Fragment>
),
panel: index + 1,
Expand All @@ -144,9 +156,9 @@ export const AlertsBadge: React.FC<Props> = (props: Props) => {
...list.map((alertStatus, index) => {
return {
id: index + 1,
title: getDateFromState(alertStatus.states),
title: getDateFromState(alertStatus.alertState),
width: 400,
content: <AlertPanel alert={alertStatus} />,
content: <AlertPanel alert={alertStatus.alert} alertState={alertStatus.alertState} />,
};
}),
];
Expand Down
9 changes: 5 additions & 4 deletions x-pack/plugins/monitoring/public/alerts/callout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { EuiCallOut, EuiSpacer } from '@elastic/eui';
import { CommonAlertStatus } from '../../common/types';
import { AlertSeverity } from '../../common/enums';
import { replaceTokens } from './lib/replace_tokens';
import { AlertMessage } from '../../server/alerts/types';
import { AlertMessage, AlertState } from '../../server/alerts/types';

const TYPES = [
{
Expand All @@ -31,16 +31,17 @@ const TYPES = [

interface Props {
alerts: { [alertTypeId: string]: CommonAlertStatus };
stateFilter: (state: AlertState) => boolean;
}
export const AlertsCallout: React.FC<Props> = (props: Props) => {
const { alerts } = props;
const { alerts, stateFilter = () => true } = props;

const callouts = TYPES.map((type) => {
const list = [];
for (const alertTypeId of Object.keys(alerts)) {
const alertInstance = alerts[alertTypeId];
for (const { state } of alertInstance.states) {
if (state.ui.severity === type.severity) {
for (const { firing, state } of alertInstance.states) {
if (firing && stateFilter(state) && state.ui.severity === type.severity) {
list.push(state);
}
}
Expand Down
20 changes: 8 additions & 12 deletions x-pack/plugins/monitoring/public/alerts/panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
EuiListGroupItem,
} from '@elastic/eui';

import { CommonAlertStatus } from '../../common/types';
import { CommonAlertStatus, CommonAlertState } from '../../common/types';
import { AlertMessage } from '../../server/alerts/types';
import { Legacy } from '../legacy_shims';
import { replaceTokens } from './lib/replace_tokens';
Expand All @@ -30,10 +30,12 @@ import { BASE_ALERT_API_PATH } from '../../../alerts/common';

interface Props {
alert: CommonAlertStatus;
alertState?: CommonAlertState;
}
export const AlertPanel: React.FC<Props> = (props: Props) => {
const {
alert: { states, alert },
alert: { alert },
alertState,
} = props;
const [showFlyout, setShowFlyout] = React.useState(false);
const [isEnabled, setIsEnabled] = React.useState(alert.rawAlert.enabled);
Expand Down Expand Up @@ -190,20 +192,14 @@ export const AlertPanel: React.FC<Props> = (props: Props) => {
</Fragment>
);

if (inSetupMode) {
if (inSetupMode || !alertState) {
return <div style={{ padding: '1rem' }}>{configurationUi}</div>;
}

const firingStates = states.filter((state) => state.firing);
if (!firingStates.length) {
return <div style={{ padding: '1rem' }}>{configurationUi}</div>;
}

const firingState = firingStates[0];
const nextStepsUi =
firingState.state.ui.message.nextSteps && firingState.state.ui.message.nextSteps.length ? (
alertState.state.ui.message.nextSteps && alertState.state.ui.message.nextSteps.length ? (
<EuiListGroup>
{firingState.state.ui.message.nextSteps.map((step: AlertMessage, index: number) => (
{alertState.state.ui.message.nextSteps.map((step: AlertMessage, index: number) => (
<EuiListGroupItem size="s" key={index} label={replaceTokens(step)} />
))}
</EuiListGroup>
Expand All @@ -213,7 +209,7 @@ export const AlertPanel: React.FC<Props> = (props: Props) => {
<Fragment>
<div style={{ padding: '1rem' }}>
<EuiTitle size="xs">
<h5>{replaceTokens(firingState.state.ui.message)}</h5>
<h5>{replaceTokens(alertState.state.ui.message)}</h5>
</EuiTitle>
{nextStepsUi ? <EuiSpacer size="s" /> : null}
{nextStepsUi}
Expand Down
22 changes: 15 additions & 7 deletions x-pack/plugins/monitoring/public/alerts/status.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,44 @@ import { CommonAlertStatus } from '../../common/types';
import { AlertSeverity } from '../../common/enums';
import { AlertState } from '../../server/alerts/types';
import { AlertsBadge } from './badge';
import { isInSetupMode } from '../lib/setup_mode';

interface Props {
alerts: { [alertTypeId: string]: CommonAlertStatus };
showBadge: boolean;
showOnlyCount: boolean;
stateFilter: (state: AlertState) => boolean;
}
export const AlertsStatus: React.FC<Props> = (props: Props) => {
const { alerts, showBadge = false, showOnlyCount = false } = props;
const { alerts, showBadge = false, showOnlyCount = false, stateFilter = () => true } = props;
const inSetupMode = isInSetupMode();

if (!alerts) {
return null;
}

let atLeastOneDanger = false;
const count = Object.values(alerts).reduce((cnt, alertStatus) => {
if (alertStatus.states.length) {
const firingStates = alertStatus.states.filter((state) => state.firing);
const firingAndFilterStates = firingStates.filter((state) => stateFilter(state.state));
cnt += firingAndFilterStates.length;
if (firingStates.length) {
if (!atLeastOneDanger) {
for (const state of alertStatus.states) {
if ((state.state as AlertState).ui.severity === AlertSeverity.Danger) {
if (
stateFilter(state.state) &&
(state.state as AlertState).ui.severity === AlertSeverity.Danger
) {
atLeastOneDanger = true;
break;
}
}
}
cnt++;
}
return cnt;
}, 0);

if (count === 0) {
if (count === 0 && (!inSetupMode || showOnlyCount)) {
return (
<EuiToolTip
content={i18n.translate('xpack.monitoring.alerts.status.clearToolip', {
Expand All @@ -62,8 +70,8 @@ export const AlertsStatus: React.FC<Props> = (props: Props) => {
);
}

if (showBadge) {
return <AlertsBadge alerts={alerts} />;
if (showBadge || inSetupMode) {
return <AlertsBadge alerts={alerts} stateFilter={stateFilter} />;
}

const severity = atLeastOneDanger ? AlertSeverity.Danger : AlertSeverity.Warning;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,14 @@ export const Node = ({
</h1>
</EuiScreenReaderOnly>
<EuiPanel>
<NodeDetailStatus stats={nodeSummary} alerts={alerts} />
<NodeDetailStatus
stats={nodeSummary}
alerts={alerts}
alertsStateFilter={(state) => state.nodeId === nodeId}
/>
</EuiPanel>
<EuiSpacer size="m" />
<AlertsCallout alerts={alerts} />
<AlertsCallout alerts={alerts} stateFilter={(state) => state.nodeId === nodeId} />
<EuiPageContent>
<EuiFlexGrid columns={2} gutterSize="s">
{metricsToShow.map((metric, index) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { formatMetric } from '../../../lib/format_number';
import { i18n } from '@kbn/i18n';
import { AlertsStatus } from '../../../alerts/status';

export function NodeDetailStatus({ stats, alerts = {} }) {
export function NodeDetailStatus({ stats, alerts = {}, alertsStateFilter = () => true }) {
const {
transport_address: transportAddress,
usedHeap,
Expand All @@ -33,7 +33,7 @@ export function NodeDetailStatus({ stats, alerts = {} }) {
label: i18n.translate('xpack.monitoring.elasticsearch.nodeDetailStatus.alerts', {
defaultMessage: 'Alerts',
}),
value: <AlertsStatus alerts={alerts} showOnlyCount={true} />,
value: <AlertsStatus alerts={alerts} showOnlyCount={true} stateFilter={alertsStateFilter} />,
},
{
label: i18n.translate('xpack.monitoring.elasticsearch.nodeDetailStatus.transportAddress', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,14 @@ const getColumns = (showCgroupMetricsElasticsearch, setupMode, clusterUuid, aler
field: 'alerts',
width: '175px',
sortable: true,
render: () => {
return <AlertsStatus showBadge={true} alerts={alerts} />;
render: (_field, node) => {
return (
<AlertsStatus
showBadge={true}
alerts={alerts}
stateFilter={(state) => state.nodeId === node.resolver}
/>
);
},
});

Expand Down
Loading