From 938b3cdc05b96f0038921b671c92a4b820931198 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Tue, 26 May 2020 09:27:24 +0300 Subject: [PATCH] fix annotations, closes #964 --- src/datasource-zabbix/datasource.ts | 91 +++++++++---------- src/datasource-zabbix/problemsHandler.ts | 52 ++++++++++- src/datasource-zabbix/types.ts | 5 +- .../zabbix_api/zabbixAPIConnector.ts | 6 +- src/datasource-zabbix/zabbix/zabbix.ts | 9 +- 5 files changed, 107 insertions(+), 56 deletions(-) diff --git a/src/datasource-zabbix/datasource.ts b/src/datasource-zabbix/datasource.ts index 4695e104e..cb5bbda36 100644 --- a/src/datasource-zabbix/datasource.ts +++ b/src/datasource-zabbix/datasource.ts @@ -576,71 +576,62 @@ export class ZabbixDatasource { const timeFrom = Math.ceil(dateMath.parse(timeRange.from) / 1000); const timeTo = Math.ceil(dateMath.parse(timeRange.to) / 1000); const annotation = options.annotation; - const showOkEvents = annotation.showOkEvents ? c.SHOW_ALL_EVENTS : c.SHOW_OK_EVENTS; // Show all triggers - const triggersOptions = { - showTriggers: c.SHOW_ALL_TRIGGERS, - hideHostsInMaintenance: false + const problemsOptions: any = { + value: annotation.showOkEvents ? ['0', '1'] : '1', + valueFromEvent: true, + timeFrom, + timeTo, }; + if (annotation.minseverity) { + const severities = [0, 1, 2, 3, 4, 5].filter(v => v >= Number(annotation.minseverity)); + problemsOptions.severities = severities; + } + const groupFilter = this.replaceTemplateVars(annotation.group, {}); const hostFilter = this.replaceTemplateVars(annotation.host, {}); const appFilter = this.replaceTemplateVars(annotation.application, {}); const proxyFilter = undefined; - return this.zabbix.getProblems(groupFilter, hostFilter, appFilter, proxyFilter, triggersOptions) - .then(triggers => { + return this.zabbix.getProblemsHistory(groupFilter, hostFilter, appFilter, proxyFilter, problemsOptions) + .then(problems => { // Filter triggers by description - const triggerName = this.replaceTemplateVars(annotation.trigger, {}); - if (utils.isRegex(triggerName)) { - triggers = _.filter(triggers, trigger => { - return utils.buildRegex(triggerName).test(trigger.description); + const problemName = this.replaceTemplateVars(annotation.trigger, {}); + if (utils.isRegex(problemName)) { + problems = _.filter(problems, p => { + return utils.buildRegex(problemName).test(p.description); }); - } else if (triggerName) { - triggers = _.filter(triggers, trigger => { - return trigger.description === triggerName; + } else if (problemName) { + problems = _.filter(problems, p => { + return p.description === problemName; }); } - // Remove events below the chose severity - triggers = _.filter(triggers, trigger => { - return Number(trigger.priority) >= Number(annotation.minseverity); - }); - - const objectids = _.map(triggers, 'triggerid'); - return this.zabbix - .getEvents(objectids, timeFrom, timeTo, showOkEvents) - .then(events => { - const indexedTriggers = _.keyBy(triggers, 'triggerid'); - - // Hide acknowledged events if option enabled - if (annotation.hideAcknowledged) { - events = _.filter(events, event => { - return !event.acknowledges.length; - }); - } - - return _.map(events, event => { - let tags; - if (annotation.showHostname) { - tags = _.map(event.hosts, 'name'); - } - - // Show event type (OK or Problem) - const title = Number(event.value) ? 'Problem' : 'OK'; - - const formattedAcknowledges = utils.formatAcknowledges(event.acknowledges); - const eventName = event.name || indexedTriggers[event.objectid].description; - return { - annotation: annotation, - time: event.clock * 1000, - title: title, - tags: tags, - text: eventName + formattedAcknowledges - }; - }); + // Hide acknowledged events if option enabled + if (annotation.hideAcknowledged) { + problems = _.filter(problems, p => { + return !p.acknowledges?.length; }); + } + + return _.map(problems, p => { + const formattedAcknowledges = utils.formatAcknowledges(p.acknowledges); + + let annotationTags: string[] = []; + if (annotation.showHostname) { + annotationTags = _.map(p.hosts, 'name'); + } + + return { + title: p.value === '1' ? 'Problem' : 'OK', + time: p.timestamp * 1000, + annotation: annotation, + text: p.name + formattedAcknowledges, + tags: annotationTags, + }; + }); }); } diff --git a/src/datasource-zabbix/problemsHandler.ts b/src/datasource-zabbix/problemsHandler.ts index c6c1c24ae..c1ecf8cb6 100644 --- a/src/datasource-zabbix/problemsHandler.ts +++ b/src/datasource-zabbix/problemsHandler.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; import * as utils from '../datasource-zabbix/utils'; import { DataFrame, Field, FieldType, ArrayVector } from '@grafana/data'; -import { ZBXProblem, ZBXTrigger, ProblemDTO } from './types'; +import { ZBXProblem, ZBXTrigger, ProblemDTO, ZBXEvent } from './types'; export function joinTriggersWithProblems(problems: ZBXProblem[], triggers: ZBXTrigger[]): ProblemDTO[] { const problemDTOList: ProblemDTO[] = []; @@ -46,6 +46,54 @@ export function joinTriggersWithProblems(problems: ZBXProblem[], triggers: ZBXTr return problemDTOList; } +interface JoinOptions { + valueFromEvent?: boolean; +} + +export function joinTriggersWithEvents(events: ZBXEvent[], triggers: ZBXTrigger[], options?: JoinOptions): ProblemDTO[] { + const { valueFromEvent } = options; + + const problemDTOList: ProblemDTO[] = []; + for (let i = 0; i < events.length; i++) { + const e = events[i]; + const triggerId = Number(e.objectid); + const t = triggers[triggerId]; + + if (t) { + const problemDTO: ProblemDTO = { + value: valueFromEvent ? e.value : t.value, + timestamp: Number(e.clock), + triggerid: e.objectid, + eventid: e.eventid, + name: e.name, + severity: e.severity, + acknowledged: e.acknowledged, + acknowledges: e.acknowledges, + tags: e.tags, + suppressed: e.suppressed, + description: t.description, + comments: t.comments, + groups: t.groups, + hosts: t.hosts, + items: t.items, + alerts: t.alerts, + url: t.url, + expression: t.expression, + correlation_mode: t.correlation_mode, + correlation_tag: t.correlation_tag, + manual_close: t.manual_close, + state: t.state, + error: t.error, + }; + + problemDTOList.push(problemDTO); + } + + } + + return problemDTOList; +} + export function setMaintenanceStatus(triggers) { _.each(triggers, (trigger) => { const maintenance_status = _.some(trigger.hosts, (host) => host.maintenance_status === '1'); @@ -145,6 +193,8 @@ const problemsHandler = { setAckButtonStatus, filterTriggersPre, toDataFrame, + joinTriggersWithProblems, + joinTriggersWithEvents, }; export default problemsHandler; diff --git a/src/datasource-zabbix/types.ts b/src/datasource-zabbix/types.ts index 6f8c9e8dc..2068a289d 100644 --- a/src/datasource-zabbix/types.ts +++ b/src/datasource-zabbix/types.ts @@ -170,13 +170,16 @@ export interface ZBXEvent { clock: string; ns?: string; value?: string; + name?: string; source?: string; object?: string; objectid?: string; - acknowledged?: string; severity?: string; hosts?: ZBXHost[]; + acknowledged?: '1' | '0'; acknowledges?: ZBXAcknowledge[]; + tags?: ZBXTag[]; + suppressed?: string; } export interface ZBXTag { diff --git a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts index f5d4968ef..5fe2cf517 100644 --- a/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts +++ b/src/datasource-zabbix/zabbix/connectors/zabbix_api/zabbixAPIConnector.ts @@ -511,7 +511,7 @@ export class ZabbixAPIConnector { } getEventsHistory(groupids, hostids, applicationids, options) { - const { timeFrom, timeTo, severities, limit } = options; + const { timeFrom, timeTo, severities, limit, value } = options; const params: any = { output: 'extend', @@ -539,6 +539,10 @@ export class ZabbixAPIConnector { params.severities = severities; } + if (value) { + params.value = value; + } + return this.request('event.get', params); } diff --git a/src/datasource-zabbix/zabbix/zabbix.ts b/src/datasource-zabbix/zabbix/zabbix.ts index 8d9fa2ac6..557a085d3 100644 --- a/src/datasource-zabbix/zabbix/zabbix.ts +++ b/src/datasource-zabbix/zabbix/zabbix.ts @@ -9,7 +9,8 @@ import { ZabbixAPIConnector } from './connectors/zabbix_api/zabbixAPIConnector'; import { SQLConnector } from './connectors/sql/sqlConnector'; import { InfluxDBConnector } from './connectors/influxdb/influxdbConnector'; import { ZabbixConnector } from './types'; -import { joinTriggersWithProblems } from '../problemsHandler'; +import { joinTriggersWithProblems, joinTriggersWithEvents } from '../problemsHandler'; +import { ProblemDTO } from '../types'; interface AppsResponse extends Array { appFilterEmpty?: boolean; @@ -346,7 +347,9 @@ export class Zabbix implements ZabbixConnector { .then(triggers => this.expandUserMacro.bind(this)(triggers, true)); } - getProblemsHistory(groupFilter, hostFilter, appFilter, proxyFilter?, options?) { + getProblemsHistory(groupFilter, hostFilter, appFilter, proxyFilter?, options?): Promise { + const { valueFromEvent } = options; + const promises = [ this.getGroups(groupFilter), this.getHosts(groupFilter, hostFilter), @@ -375,7 +378,7 @@ export class Zabbix implements ZabbixConnector { const triggerids = problems?.map(problem => problem.objectid); return Promise.all([Promise.resolve(problems), this.zabbixAPI.getTriggersByIds(triggerids)]); }) - .then(([problems, triggers]) => joinTriggersWithProblems(problems, triggers)) + .then(([problems, triggers]) => joinTriggersWithEvents(problems, triggers, { valueFromEvent })) .then(triggers => this.filterTriggersByProxy(triggers, proxyFilter)) .then(triggers => this.expandUserMacro.bind(this)(triggers, true)); }