Fix problems fetching performance and memory issues (#724)
* request only alert message when invoking alert.get * fetch problem alerts on demand * problems panel: refactor
This commit is contained in:
@@ -421,7 +421,12 @@ export class ZabbixAPIConnector {
|
|||||||
getEventAlerts(eventids) {
|
getEventAlerts(eventids) {
|
||||||
const params = {
|
const params = {
|
||||||
eventids: eventids,
|
eventids: eventids,
|
||||||
output: 'extend',
|
output: [
|
||||||
|
'eventid',
|
||||||
|
'message',
|
||||||
|
'clock',
|
||||||
|
'error'
|
||||||
|
],
|
||||||
selectUsers: true,
|
selectUsers: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import * as utils from '../../../datasource-zabbix/utils';
|
import * as utils from '../../../datasource-zabbix/utils';
|
||||||
import { ZBXTrigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup, ZBXEvent, GFTimeRange, RTRow, ZBXTag } from '../../types';
|
import { ZBXTrigger, ZBXItem, ZBXAcknowledge, ZBXHost, ZBXGroup, ZBXEvent, GFTimeRange, RTRow, ZBXTag, ZBXAlert } from '../../types';
|
||||||
import { Modal, AckProblemData } from '../Modal';
|
import { Modal, AckProblemData } from '../Modal';
|
||||||
import EventTag from '../EventTag';
|
import EventTag from '../EventTag';
|
||||||
import Tooltip from '../Tooltip/Tooltip';
|
import Tooltip from '../Tooltip/Tooltip';
|
||||||
@@ -15,12 +15,14 @@ interface ProblemDetailsProps extends RTRow<ZBXTrigger> {
|
|||||||
timeRange: GFTimeRange;
|
timeRange: GFTimeRange;
|
||||||
showTimeline?: boolean;
|
showTimeline?: boolean;
|
||||||
getProblemEvents: (problem: ZBXTrigger) => Promise<ZBXEvent[]>;
|
getProblemEvents: (problem: ZBXTrigger) => Promise<ZBXEvent[]>;
|
||||||
|
getProblemAlerts: (problem: ZBXTrigger) => Promise<ZBXAlert[]>;
|
||||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise<any> | any;
|
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => Promise<any> | any;
|
||||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProblemDetailsState {
|
interface ProblemDetailsState {
|
||||||
events: ZBXEvent[];
|
events: ZBXEvent[];
|
||||||
|
alerts: ZBXAlert[];
|
||||||
show: boolean;
|
show: boolean;
|
||||||
showAckDialog: boolean;
|
showAckDialog: boolean;
|
||||||
}
|
}
|
||||||
@@ -30,6 +32,7 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
events: [],
|
events: [],
|
||||||
|
alerts: [],
|
||||||
show: false,
|
show: false,
|
||||||
showAckDialog: false,
|
showAckDialog: false,
|
||||||
};
|
};
|
||||||
@@ -39,6 +42,7 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
if (this.props.showTimeline) {
|
if (this.props.showTimeline) {
|
||||||
this.fetchProblemEvents();
|
this.fetchProblemEvents();
|
||||||
}
|
}
|
||||||
|
this.fetchProblemAlerts();
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.setState({ show: true });
|
this.setState({ show: true });
|
||||||
});
|
});
|
||||||
@@ -58,6 +62,14 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchProblemAlerts() {
|
||||||
|
const problem = this.props.original;
|
||||||
|
this.props.getProblemAlerts(problem)
|
||||||
|
.then(alerts => {
|
||||||
|
this.setState({ alerts });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ackProblem = (data: AckProblemData) => {
|
ackProblem = (data: AckProblemData) => {
|
||||||
const problem = this.props.original as ZBXTrigger;
|
const problem = this.props.original as ZBXTrigger;
|
||||||
return this.props.onProblemAck(problem, data).then(result => {
|
return this.props.onProblemAck(problem, data).then(result => {
|
||||||
@@ -78,6 +90,7 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const problem = this.props.original as ZBXTrigger;
|
const problem = this.props.original as ZBXTrigger;
|
||||||
|
const alerts = this.state.alerts;
|
||||||
const rootWidth = this.props.rootWidth;
|
const rootWidth = this.props.rootWidth;
|
||||||
const displayClass = this.state.show ? 'show' : '';
|
const displayClass = this.state.show ? 'show' : '';
|
||||||
const wideLayout = rootWidth > 1200;
|
const wideLayout = rootWidth > 1200;
|
||||||
@@ -96,7 +109,7 @@ export default class ProblemDetails extends PureComponent<ProblemDetailsProps, P
|
|||||||
</div>
|
</div>
|
||||||
{problem.items && <ProblemItems items={problem.items} />}
|
{problem.items && <ProblemItems items={problem.items} />}
|
||||||
</div>
|
</div>
|
||||||
<ProblemStatusBar problem={problem} className={compactStatusBar && 'compact'} />
|
<ProblemStatusBar problem={problem} alerts={alerts} className={compactStatusBar && 'compact'} />
|
||||||
<div className="problem-actions">
|
<div className="problem-actions">
|
||||||
<ProblemActionButton className="navbar-button navbar-button--settings"
|
<ProblemActionButton className="navbar-button navbar-button--settings"
|
||||||
icon="reply-all"
|
icon="reply-all"
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FAIcon from '../FAIcon';
|
import FAIcon from '../FAIcon';
|
||||||
import Tooltip from '../Tooltip/Tooltip';
|
import Tooltip from '../Tooltip/Tooltip';
|
||||||
import { ZBXTrigger } from '../../types';
|
import { ZBXTrigger, ZBXAlert } from '../../types';
|
||||||
|
|
||||||
export interface ProblemStatusBarProps {
|
export interface ProblemStatusBarProps {
|
||||||
problem: ZBXTrigger;
|
problem: ZBXTrigger;
|
||||||
|
alerts?: ZBXAlert[];
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ProblemStatusBar(props: ProblemStatusBarProps) {
|
export default function ProblemStatusBar(props: ProblemStatusBarProps) {
|
||||||
const { problem, className } = props;
|
const { problem, alerts, className } = props;
|
||||||
const multiEvent = problem.type === '1';
|
const multiEvent = problem.type === '1';
|
||||||
const link = problem.url && problem.url !== '';
|
const link = problem.url && problem.url !== '';
|
||||||
const maintenance = problem.maintenance;
|
const maintenance = problem.maintenance;
|
||||||
@@ -17,8 +18,8 @@ export default function ProblemStatusBar(props: ProblemStatusBarProps) {
|
|||||||
const error = problem.error && problem.error !== '';
|
const error = problem.error && problem.error !== '';
|
||||||
const stateUnknown = problem.state === '1';
|
const stateUnknown = problem.state === '1';
|
||||||
const closeByTag = problem.correlation_mode === '1';
|
const closeByTag = problem.correlation_mode === '1';
|
||||||
const actions = problem.alerts && problem.alerts.length !== 0;
|
const actions = alerts && alerts.length !== 0;
|
||||||
const actionMessage = problem.alerts ? problem.alerts[0].message : '';
|
const actionMessage = actions ? alerts[0].message : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`problem-statusbar ${className || ''}`}>
|
<div className={`problem-statusbar ${className || ''}`}>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import _ from 'lodash';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import * as utils from '../../../datasource-zabbix/utils';
|
import * as utils from '../../../datasource-zabbix/utils';
|
||||||
import { isNewProblem } from '../../utils';
|
import { isNewProblem } from '../../utils';
|
||||||
import { ProblemsPanelOptions, ZBXTrigger, ZBXEvent, GFTimeRange, RTCell, ZBXTag, TriggerSeverity, RTResized } from '../../types';
|
import { ProblemsPanelOptions, ZBXTrigger, ZBXEvent, GFTimeRange, RTCell, ZBXTag, TriggerSeverity, RTResized, ZBXAlert } from '../../types';
|
||||||
import EventTag from '../EventTag';
|
import EventTag from '../EventTag';
|
||||||
import ProblemDetails from './ProblemDetails';
|
import ProblemDetails from './ProblemDetails';
|
||||||
import { AckProblemData } from '../Modal';
|
import { AckProblemData } from '../Modal';
|
||||||
@@ -18,7 +18,8 @@ export interface ProblemListProps {
|
|||||||
timeRange?: GFTimeRange;
|
timeRange?: GFTimeRange;
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
getProblemEvents: (ids: string[]) => ZBXEvent[];
|
getProblemEvents: (problem: ZBXTrigger) => ZBXEvent[];
|
||||||
|
getProblemAlerts: (problem: ZBXTrigger) => ZBXAlert[];
|
||||||
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void;
|
onProblemAck?: (problem: ZBXTrigger, data: AckProblemData) => void;
|
||||||
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
onTagClick?: (tag: ZBXTag, datasource: string, ctrlKey?: boolean, shiftKey?: boolean) => void;
|
||||||
onPageSizeChange?: (pageSize: number, pageIndex: number) => void;
|
onPageSizeChange?: (pageSize: number, pageIndex: number) => void;
|
||||||
@@ -159,6 +160,7 @@ export default class ProblemList extends PureComponent<ProblemListProps, Problem
|
|||||||
timeRange={this.props.timeRange}
|
timeRange={this.props.timeRange}
|
||||||
showTimeline={panelOptions.problemTimeline}
|
showTimeline={panelOptions.problemTimeline}
|
||||||
getProblemEvents={this.props.getProblemEvents}
|
getProblemEvents={this.props.getProblemEvents}
|
||||||
|
getProblemAlerts={this.props.getProblemAlerts}
|
||||||
onProblemAck={this.handleProblemAck}
|
onProblemAck={this.handleProblemAck}
|
||||||
onTagClick={this.handleTagClick}
|
onTagClick={this.handleTagClick}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -271,14 +271,12 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
}));
|
}));
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.datasources[ds].zabbix.getExtendedEventData(eventids),
|
this.datasources[ds].zabbix.getExtendedEventData(eventids),
|
||||||
this.datasources[ds].zabbix.getEventAlerts(eventids),
|
|
||||||
Promise.resolve(triggers)
|
Promise.resolve(triggers)
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
.then(([events, alerts, triggers]) => {
|
.then(([events, triggers]) => {
|
||||||
this.addEventTags(events, triggers);
|
this.addEventTags(events, triggers);
|
||||||
this.addAcknowledges(events, triggers);
|
this.addAcknowledges(events, triggers);
|
||||||
this.addEventAlerts(alerts, triggers);
|
|
||||||
return triggers;
|
return triggers;
|
||||||
})
|
})
|
||||||
.then(triggers => this.setMaintenanceStatus(triggers))
|
.then(triggers => this.setMaintenanceStatus(triggers))
|
||||||
@@ -337,18 +335,6 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
return triggers;
|
return triggers;
|
||||||
}
|
}
|
||||||
|
|
||||||
addEventAlerts(alerts, triggers) {
|
|
||||||
alerts.forEach(alert => {
|
|
||||||
const trigger = _.find(triggers, t => {
|
|
||||||
return t.lastEvent && alert.eventid === t.lastEvent.eventid;
|
|
||||||
});
|
|
||||||
if (trigger) {
|
|
||||||
trigger.alerts = trigger.alerts ? trigger.alerts.concat(alert) : [alert];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return triggers;
|
|
||||||
}
|
|
||||||
|
|
||||||
filterTriggersPre(triggerList, ds) {
|
filterTriggersPre(triggerList, ds) {
|
||||||
// Filter triggers by description
|
// Filter triggers by description
|
||||||
let triggerFilter = this.panel.targets[ds].trigger.filter;
|
let triggerFilter = this.panel.targets[ds].trigger.filter;
|
||||||
@@ -503,16 +489,27 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
this.refresh();
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
getProblemEvents(trigger) {
|
getProblemEvents(problem) {
|
||||||
const triggerids = [trigger.triggerid];
|
const triggerids = [problem.triggerid];
|
||||||
const timeFrom = Math.ceil(dateMath.parse(this.range.from) / 1000);
|
const timeFrom = Math.ceil(dateMath.parse(this.range.from) / 1000);
|
||||||
const timeTo = Math.ceil(dateMath.parse(this.range.to) / 1000);
|
const timeTo = Math.ceil(dateMath.parse(this.range.to) / 1000);
|
||||||
return this.datasourceSrv.get(trigger.datasource)
|
return this.datasourceSrv.get(problem.datasource)
|
||||||
.then(datasource => {
|
.then(datasource => {
|
||||||
return datasource.zabbix.getEvents(triggerids, timeFrom, timeTo, [0, 1], PROBLEM_EVENTS_LIMIT);
|
return datasource.zabbix.getEvents(triggerids, timeFrom, timeTo, [0, 1], PROBLEM_EVENTS_LIMIT);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getProblemAlerts(problem) {
|
||||||
|
if (!problem.lastEvent || problem.lastEvent.length === 0) {
|
||||||
|
return Promise.resolve([]);
|
||||||
|
}
|
||||||
|
const eventids = [problem.lastEvent.eventid];
|
||||||
|
return this.datasourceSrv.get(problem.datasource)
|
||||||
|
.then(datasource => {
|
||||||
|
return datasource.zabbix.getEventAlerts(eventids);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
formatHostName(trigger) {
|
formatHostName(trigger) {
|
||||||
let host = "";
|
let host = "";
|
||||||
if (this.panel.hostField && this.panel.hostTechNameField) {
|
if (this.panel.hostField && this.panel.hostTechNameField) {
|
||||||
@@ -663,6 +660,7 @@ export class TriggerPanelCtrl extends PanelCtrl {
|
|||||||
pageSize,
|
pageSize,
|
||||||
fontSize: fontSizeProp,
|
fontSize: fontSizeProp,
|
||||||
getProblemEvents: ctrl.getProblemEvents.bind(ctrl),
|
getProblemEvents: ctrl.getProblemEvents.bind(ctrl),
|
||||||
|
getProblemAlerts: ctrl.getProblemAlerts.bind(ctrl),
|
||||||
onPageSizeChange: ctrl.handlePageSizeChange.bind(ctrl),
|
onPageSizeChange: ctrl.handlePageSizeChange.bind(ctrl),
|
||||||
onColumnResize: ctrl.handleColumnResize.bind(ctrl),
|
onColumnResize: ctrl.handleColumnResize.bind(ctrl),
|
||||||
onProblemAck: (trigger, data) => {
|
onProblemAck: (trigger, data) => {
|
||||||
|
|||||||
@@ -162,6 +162,7 @@ export interface ZBXAcknowledge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface ZBXAlert {
|
export interface ZBXAlert {
|
||||||
|
eventid: string;
|
||||||
clock: string;
|
clock: string;
|
||||||
message: string;
|
message: string;
|
||||||
error: string;
|
error: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user