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:
Alexander Zobnin
2019-04-22 12:29:05 +03:00
committed by GitHub
parent e3c5d44345
commit bc889ffe30
6 changed files with 47 additions and 27 deletions

View File

@@ -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,
}; };

View File

@@ -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"

View File

@@ -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 || ''}`}>

View File

@@ -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}
/> />

View File

@@ -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) => {

View File

@@ -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;