Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'create/src/data.tmpl')
-rw-r--r--create/src/data.tmpl4
1 files changed, 3 insertions, 1 deletions
diff --git a/create/src/data.tmpl b/create/src/data.tmpl
index 34acca43016..e29aacc607f 100644
--- a/create/src/data.tmpl
+++ b/create/src/data.tmpl
@@ -55,7 +55,7 @@ ROW |1 |0 |Email |mail.example.com|example.com|za
ROW |3 |2 |SMS | | | | |/dev/ttyS0| | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 | |30s |0 |0 | | | |
ROW |4 |0 |Email (HTML) |mail.example.com|example.com|zabbix@example.com| | | | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 | |30s |0 |0 | | | |
ROW |5 |4 |Mattermost | | | | | | | |0 |25 |0 |0 |0 |0 | |1 |1 |10s |1 |var SEVERITY_COLORS = [&eol; '#97AAB3', '#7499FF', '#FFC859',&eol; '#FFA059', '#E97659', '#E45959'&eol;];&eol;&eol;var RESOLVE_COLOR = '#009900';&eol;&eol;var SEND_MODE_HANDLERS = {&eol; alarm: handlerAlarm,&eol; event: handlerEvent&eol;};&eol;&eol;if (!String.prototype.format) {&eol; String.prototype.format = function() {&eol; var args = arguments;&eol;&eol; return this.replace(/{(\d+)}/g, function(match, number) {&eol; return number in args&eol; ? args[number]&eol; : match&eol; ;&eol; });&eol; };&eol;}&eol;&eol;function isEventProblem(params) {&eol; return params.event_value == 1&eol; && params.event_update_status == 0&eol; ;&eol;}&eol;&eol;function isEventUpdate(params) {&eol; return params.event_value == 1&eol; && params.event_update_status == 1&eol; ;&eol;}&eol;&eol;function isEventResolve(params) {&eol; return params.event_value == 0;&eol;}&eol;&eol;function getPermalink(mattermost_url, team_name, postid) {&eol; return '{0}/{1}/pl/{2}'.format(&eol; mattermost_url.replace(/\/+$/, ''),&eol; team_name,&eol; postid&eol; );&eol;}&eol;&eol;function getChannel(send_to) {&eol; switch (true) {&eol; case /.+\/#.+/.test(send_to):&eol; return getChannelByName(send_to);&eol;&eol; case /@.+/.test(send_to):&eol; return getDirectChannel(send_to);&eol;&eol; default:&eol; return getChannelByID(send_to);&eol; }&eol;}&eol;&eol;function getChannelByName(send_to) {&eol; var team_chan = send_to&eol; .trim()&eol; .split('/#');&eol;&eol; var resp = JSON.parse(req.Get(&eol; Mattermost.channel_byname.format(team_chan[0], team_chan[1]),&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; return resp;&eol;}&eol;&eol;function getDirectChannel(send_to) {&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(&eol; arguments.callee.name,&eol; JSON.stringify(arguments)&eol; ));&eol;&eol; var teamUser = send_to&eol; .trim()&eol; .split('/@'),&eol; bot = getBotUser(),&eol; user = getUserByName(teamUser[1]);&eol;&eol; var resp = JSON.parse(req.Post(&eol; Mattermost.direct_channel,&eol; JSON.stringify([bot.id, user.id])&eol; )&eol; );&eol;&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(&eol; arguments.callee.name,&eol; JSON.stringify(resp)&eol; ));&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; resp.team_name = teamUser[0];&eol;&eol; return resp;&eol;}&eol;&eol;function getChannelByID(channelID) {&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(&eol; arguments.callee.name,&eol; JSON.stringify(arguments)&eol; ));&eol;&eol; var resp = JSON.parse(req.Get(&eol; Mattermost.get_channel.format(channelID),&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(&eol; arguments.callee.name,&eol; JSON.stringify(resp)&eol; ));&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; return resp;&eol;}&eol;&eol;function getBotUser() {&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(&eol; arguments.callee.name,&eol; JSON.stringify(arguments)&eol; ));&eol;&eol; var resp = JSON.parse(req.Get(&eol; Mattermost.bot_user,&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(&eol; arguments.callee.name,&eol; JSON.stringify(resp)&eol; ));&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; return resp;&eol;}&eol;&eol;function getUserByName(userName) {&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(&eol; arguments.callee.name,&eol; JSON.stringify(arguments)&eol; ));&eol;&eol; var resp = JSON.parse(req.Get(&eol; Mattermost.user_byname.format(userName),&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(&eol; arguments.callee.name,&eol; JSON.stringify(resp)&eol; ));&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; return resp;&eol;}&eol;&eol;function getTeamByID(teamID) {&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Call {0}({1})'.format(&eol; arguments.callee.name,&eol; JSON.stringify(arguments)&eol; ));&eol;&eol; var resp = JSON.parse(req.Get(&eol; Mattermost.get_team.format(teamID),&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; Zabbix.Log(5, '[ Mattermost Webhook ] Result {0}: {1}'.format(&eol; arguments.callee.name,&eol; JSON.stringify(resp)&eol; ));&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; return resp;&eol;}&eol;&eol;function createProblemURL(zabbix_url, triggerid, eventid, event_source) {&eol; var problem_url = '';&eol; if (event_source === '0') {&eol; problem_url = '{0}/tr_events.php?triggerid={1}&eventid={2}'&eol; .format(&eol; zabbix_url,&eol; triggerid,&eol; eventid&eol; );&eol; }&eol; else {&eol; problem_url = zabbix_url;&eol; }&eol;&eol; return problem_url;&eol;}&eol;&eol;function getTagValue(event_tags, key) {&eol; var pattern = new RegExp('(' + key + ':.+)');&eol; var tagValue = event_tags&eol; .split(',')&eol; .filter(function (v) {&eol; return v.match(pattern);&eol; })&eol; .map(function (v) {&eol; return v.split(':')[1];&eol; })[0]&eol; &pipe;&pipe; 0;&eol;&eol; return tagValue;&eol;}&eol;&eol;function handlerAlarm(req, params) {&eol; var channel = getChannel(params.send_to);&eol; var fields = {&eol; channel_id: channel.id,&eol; props: {}&eol; };&eol;&eol; if (isEventProblem(params)) {&eol; var team_name = channel.team_name&eol; ? channel.team_name&eol; : getTeamByID(channel.team_id).name;&eol;&eol; fields.props.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; var resp = JSON.parse(req.Post(&eol; Mattermost.post_message,&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; result.tags.__mattermost_post_id = resp.id;&eol; result.tags.__mattermost_channel_id = channel.id;&eol; result.tags.__mattermost_channel_name = channel.name;&eol; result.tags.__mattermost_message_link = getPermalink(&eol; params.mattermost_url,&eol; team_name,&eol; resp.id&eol; );&eol;&eol; }&eol; else if (isEventUpdate(params)) {&eol; fields.root_id = getTagValue(params.event_tags, 'mattermost_post_id');&eol;&eol; if (params.event_source === '0') {}&eol; fields.props.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_update_date,&eol; params.event_update_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&eol; true&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(&eol; Mattermost.post_message, JSON.stringify(fields)&eol; )&eol; );&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; }&eol; else if (isEventResolve(params)) {&eol; fields.channel_id = getTagValue(params.event_tags, 'mattermost_channel_id');&eol; fields.id = getTagValue(params.event_tags, 'mattermost_post_id');&eol; fields.props.attachments = [&eol; createMessage(&eol; RESOLVE_COLOR,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; var post_id = getTagValue(params.event_tags, 'mattermost_post_id');&eol;&eol; resp = JSON.parse(req.Put(&eol; Mattermost.chat_update.format(post_id),&eol; JSON.stringify(fields)&eol; )&eol; );&eol;&eol; if (req.Status() != 200) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol; }&eol;}&eol;&eol;function handlerEvent(req, params) {&eol; var channel = getChannel(params.send_to);&eol; var fields = {&eol; channel_id: channel.id,&eol; props: {}&eol; };&eol;&eol; if (isEventProblem(params)) {&eol; var team_name = channel.team_name&eol; ? channel.team_name&eol; : getTeamByID(channel.team_id).name;&eol;&eol; fields.props.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; var resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; result.tags.__mattermost_channel_name = channel.name;&eol; result.tags.__mattermost_message_link = getPermalink(&eol; params.mattermost_url,&eol; team_name,&eol; resp.id&eol; );&eol;&eol; }&eol; else if (isEventUpdate(params)) {&eol; fields.props.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_update_date,&eol; params.event_update_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&eol; false&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol;&eol; }&eol; else if (isEventResolve(params)) {&eol; fields.props.attachments = [&eol; createMessage(&eol; RESOLVE_COLOR,&eol; params.event_recovery_date,&eol; params.event_recovery_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Mattermost.post_message, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 201) {&eol; throw '[{0}] {1}'.format(resp.status_code, resp.message);&eol; }&eol; }&eol;}&eol;&eol;function createMessage(&eol; event_severity_color,&eol; event_date,&eol; event_time,&eol; problem_url,&eol; isShort&eol;) {&eol; var message = {&eol; fallbac: params.alert_subject,&eol; title: params.alert_subject,&eol; color: event_severity_color,&eol; title_link: problem_url,&eol; footer: problem_url,&eol;&eol; fields: [&eol; {&eol; title: 'Host',&eol; value: '{0} [{1}]'.format(params.host_name, params.host_ip),&eol; short: true&eol; },&eol; {&eol; title: 'Event time',&eol; value: '{0} {1}'.format(event_date, event_time),&eol; short: true&eol; }&eol; ],&eol; };&eol;&eol; &eol; if (params.event_source === '0') {&eol; message.fields.push(&eol; {&eol; title: 'Severity',&eol; value: params.event_severity,&eol; short: true&eol; },&eol; {&eol; title: 'Opdata',&eol; value: params.event_opdata,&eol; short: true&eol; }&eol; );&eol; }&eol;&eol; if (!isShort && params.event_source === '0') {&eol; message.fields.push(&eol; {&eol; title: 'Event tags',&eol; value: '`{0}`'.format(params.event_tags.replace(/__.+?:(.+?,&pipe;.+)/g, '') &pipe;&pipe; 'None'),&eol; short: true&eol; },&eol; {&eol; title: 'Trigger description',&eol; value: params.trigger_description,&eol; short: true&eol; }&eol; );&eol; }&eol;&eol; if (params.event_source !== '0' &pipe;&pipe; params.event_update_status === '1') {&eol; message.fields.push(&eol; {&eol; title: 'Details',&eol; value: params.alert_message,&eol; short: false&eol; }&eol; );&eol; }&eol;&eol; return message;&eol;}&eol;&eol;function validateParams(params) {&eol; if (typeof params.bot_token !== 'string' &pipe;&pipe; params.bot_token.trim() === '') {&eol; throw 'Field "bot_token" cannot be empty';&eol; }&eol;&eol; if (isNaN(params.event_id)) {&eol; throw 'Field "event_id" is not a number';&eol; }&eol;&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol;&eol; if (params.event_source !== '0') {&eol; params.event_nseverity = '0';&eol; params.event_severity = 'Not classified';&eol; params.event_update_status = '0';&eol; params.send_mode = 'event';&eol; }&eol;&eol; if (params.event_source === '1' &pipe;&pipe; params.event_source === '2') {&eol; params.event_value = '1';&eol; }&eol;&eol; if (params.event_source === '1') {&eol; params.host_name = params.discovery_host_dns;&eol; params.host_ip = params.discovery_host_ip;&eol; }&eol;&eol; if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {&eol; throw 'Incorrect "event_nseverity" parameter given: ' + params.event_nseverity + '\nMust be 0-5.';&eol; }&eol;&eol; if (typeof params.event_severity !== 'string' &pipe;&pipe; params.event_severity.trim() === '') {&eol; throw 'Field "event_severity" cannot be empty';&eol; }&eol;&eol; if (params.event_update_status !== '0' && params.event_update_status !== '1') {&eol; throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';&eol; }&eol;&eol; if (params.event_value !== '0' && params.event_value !== '1') {&eol; throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';&eol; }&eol;&eol; if (typeof params.host_ip !== 'string' &pipe;&pipe; params.host_ip.trim() === '') {&eol; throw 'Field "host_ip" cannot be empty';&eol; }&eol;&eol; if (typeof params.host_name !== 'string' &pipe;&pipe; params.host_name.trim() === '') {&eol; throw 'Field "host_name" cannot be empty';&eol; }&eol;&eol; if (typeof params.mattermost_url !== 'string' &pipe;&pipe; params.mattermost_url.trim() === '') {&eol; throw 'Field "mattermost_url" cannot be empty';&eol; }&eol;&eol; if (!/^(http&pipe;https):\/\/.+/.test(params.mattermost_url)) {&eol; throw 'Field "mattermost_url" must contain a schema';&eol; }&eol;&eol; if (['alarm', 'event'].indexOf(params.send_mode) === -1) {&eol; throw 'Incorrect "send_mode" parameter given: ' + params.send_mode + '\nMust be "alarm" or "event".';&eol; }&eol;&eol; if (typeof params.send_to !== 'string' &pipe;&pipe; params.send_to.trim() === '') {&eol; throw 'Field "send_to" cannot be empty';&eol; }&eol;&eol; if (isNaN(params.trigger_id) && params.event_source === '0') {&eol; throw 'field "trigger_id" is not a number';&eol; }&eol;&eol; if (typeof params.zabbix_url !== 'string' &pipe;&pipe; params.zabbix_url.trim() === '') {&eol; throw 'Field "zabbix_url" cannot be empty';&eol; }&eol;&eol; if (!/^(http&pipe;https):\/\/.+/.test(params.zabbix_url)) {&eol; throw 'Field "zabbix_url" must contain a schema';&eol; }&eol;&eol;}&eol;&eol;try {&eol; var params = JSON.parse(value);&eol;&eol; validateParams(params);&eol;&eol; var req = new CurlHttpRequest(),&eol; fields = {},&eol; result = {tags: {}};&eol;&eol; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {&eol; req.SetProxy(params.HTTPProxy);&eol; }&eol;&eol; req.AddHeader('Content-Type: application/json; charset=utf-8');&eol; req.AddHeader('Authorization: Bearer ' + params.bot_token);&eol;&eol; params.mattermost_url = params.mattermost_url.replace(/\/+$/, '');&eol; params.zabbix_url = params.zabbix_url.replace(/\/+$/, '');&eol;&eol; var APIEndpoint = params.mattermost_url + '/api/v4/';&eol;&eol; var Mattermost = {&eol; post_message: APIEndpoint + 'posts',&eol; get_channel: APIEndpoint + 'channels/{0}',&eol; get_team: APIEndpoint + 'teams/{0}',&eol; chat_update: APIEndpoint + 'posts/{0}',&eol; direct_channel: APIEndpoint + 'channels/direct',&eol; channel_byname: APIEndpoint + 'teams/name/{0}/channels/name/{1}',&eol; user_byname: APIEndpoint + 'users/username/{0}',&eol; bot_user: APIEndpoint + 'users/me'&eol;&eol; };&eol;&eol; params.send_mode = params.send_mode.toLowerCase();&eol; params.send_mode = params.send_mode in SEND_MODE_HANDLERS&eol; ? params.send_mode&eol; : 'alarm';&eol;&eol; SEND_MODE_HANDLERS[params.send_mode](req, params);&eol;&eol; if (params.event_source === '0') {&eol; return JSON.stringify(result);&eol; }&eol; else {&eol; return 'OK';&eol; }&eol;}&eol;catch (error) {&eol; Zabbix.Log(4, '[ Mattermost Webhook ] Mattermost notification failed: ' + error);&eol; throw 'Mattermost notification failed: ' + error;&eol;}|30s |1 |1 |{EVENT.TAGS.__mattermost_message_link}|Open in Mattermost: {EVENT.TAGS.__mattermost_channel_name} | |
-ROW |6 |4 |Opsgenie | | | | | | | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 |var Media = {&eol; params: {},&eol; name: '',&eol; labels: [],&eol; HTTPProxy: '',&eol;&eol; setParams: function (params) {&eol; if (typeof params !== 'object') {&eol; return;&eol; }&eol;&eol; Media.params = params;&eol; Media.params.api += Media.params.api.endsWith('/') ? '' : '/';&eol; Media.params.web += Media.params.web.endsWith('/') ? '' : '/';&eol; },&eol;&eol; setProxy: function (HTTPProxy) {&eol; if (typeof HTTPProxy !== 'undefined' && HTTPProxy.trim() !== '') {&eol; Media.HTTPProxy = HTTPProxy;&eol; }&eol; },&eol;&eol; setTags: function(event_tags_json) {&eol; if (typeof event_tags_json !== 'undefined' && event_tags_json !== ''&eol; && event_tags_json !== '{EVENT.TAGSJSON}') {&eol;&eol; try {&eol; var tags = JSON.parse(event_tags_json),&eol; label;&eol;&eol; tags.forEach(function (tag) {&eol; if (typeof tag.tag === 'string') {&eol; label = (tag.tag + (typeof tag.value !== 'undefined'&eol; && tag.value !== '' ? (':' + tag.value) : '')).replace(/\s/g, '_');&eol; Media.labels.push(label);&eol; }&eol; });&eol; }&eol; catch (error) {&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Failed to parse "event_tags_json" param');&eol; }&eol; }&eol; },&eol;&eol; request: function (method, query, data, allow_404) {&eol; if (typeof(allow_404) === 'undefined') {&eol; allow_404 = false;&eol; }&eol;&eol; ['api', 'token'].forEach(function (field) {&eol; if (typeof Media.params !== 'object' &pipe;&pipe; typeof Media.params[field] === 'undefined'&eol; &pipe;&pipe; Media.params[field] === '') {&eol; throw 'Required ' + Media.name + ' param is not set: "' + field + '".';&eol; }&eol; });&eol;&eol; var response,&eol; url = Media.params.api + query,&eol; request = new CurlHttpRequest();&eol;&eol; request.AddHeader('Content-Type: application/json');&eol; request.AddHeader('Authorization: ' + Media.params.token);&eol; request.SetProxy(Media.HTTPProxy);&eol;&eol; if (typeof data !== 'undefined') {&eol; data = JSON.stringify(data);&eol; }&eol;&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Sending request: ' +&eol; url + ((typeof data === 'string') ? ('\n' + data) : ''));&eol;&eol; switch (method) {&eol; case 'get':&eol; response = request.Get(url, data);&eol; break;&eol;&eol; case 'post':&eol; response = request.Post(url, data);&eol; break;&eol;&eol; case 'put':&eol; response = request.Put(url, data);&eol; break;&eol;&eol; default:&eol; throw 'Unsupported HTTP request method: ' + method;&eol; }&eol;&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Received response with status code ' +&eol; request.Status() + '\n' + response);&eol;&eol; if (response !== null) {&eol; try {&eol; response = JSON.parse(response);&eol; }&eol; catch (error) {&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Failed to parse response.');&eol; response = null;&eol; }&eol; }&eol;&eol; if ((request.Status() < 200 &pipe;&pipe; request.Status() >= 300)&eol; && (!allow_404 &pipe;&pipe; request.Status() !== 404)) {&eol; var message = 'Request failed with status code ' + request.Status();&eol;&eol; if (response !== null) {&eol; if (typeof response.errors === 'object' && Object.keys(response.errors).length > 0) {&eol; message += ': ' + JSON.stringify(response.errors);&eol; }&eol; else if (typeof response.errorMessages === 'object' && Object.keys(response.errorMessages).length > 0) {&eol; message += ': ' + JSON.stringify(response.errorMessages);&eol; }&eol; else if (typeof response.message === 'string') {&eol; message += ': ' + response.message;&eol; }&eol; }&eol;&eol; throw message + ' Check debug log for more information.';&eol; }&eol;&eol; return {&eol; status: request.Status(),&eol; response: response&eol; };&eol; },&eol;&eol; getAlertId: function (requestId) {&eol; do {&eol; resp = Media.request('get', 'requests/' + requestId, undefined, true);&eol; }&eol; while (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.data === 'undefined'&eol; &pipe;&pipe; resp.response.data.success === false);&eol;&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.data === 'undefined') {&eol; throw 'Cannot get ' + Media.name + ' issue ID. Check debug log for more information.';&eol; }&eol;&eol; return resp;&eol; }&eol;};&eol;&eol;try {&eol; var result = {tags: {}},&eol; params = JSON.parse(value),&eol; media = {},&eol; fields = {},&eol; resp = {},&eol; responders = [],&eol; tags = [],&eol; required_params = [&eol; 'alert_subject',&eol; 'alert_message',&eol; 'event_id',&eol; 'event_source',&eol; 'event_value',&eol; 'event_update_status',&eol; 'opsgenie_api',&eol; 'opsgenie_web',&eol; 'opsgenie_token'&eol; ],&eol; severities = [&eol; 'not_classified',&eol; 'information',&eol; 'warning',&eol; 'average',&eol; 'high',&eol; 'disaster',&eol; 'resolved',&eol; 'default'&eol; ],&eol; priority;&eol;&eol; Object.keys(params)&eol; .forEach(function (key) {&eol; if (required_params.indexOf(key) !== -1 && params[key].trim() === '') {&eol; throw 'Parameter "' + key + '" cannot be empty.';&eol; }&eol; if (key.startsWith('opsgenie_')) {&eol; media[key.substring(9)] = params[key];&eol; }&eol; });&eol;&eol; // Possible values of event_source:&eol; // 0 - Trigger, 1 - Discovery, 2 - Autoregistration, 3 - Internal.&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol;&eol; // Check event_value for trigger-based and internal events.&eol; // Possible values: 1 for problem, 0 for recovering&eol; if (params.event_value !== '0' && params.event_value !== '1'&eol; && (params.event_source === '0' &pipe;&pipe; params.event_source === '3')) {&eol; throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';&eol; }&eol;&eol; // Check event_update_status only for trigger-based events.&eol; // Possible values: 0 - Webhook was called because of problem/recovery event, 1 - Update operation.&eol; if (params.event_source === '0' && params.event_update_status !== '0' && params.event_update_status !== '1') {&eol; throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';&eol; }&eol;&eol; // Check event_id for a numeric value.&eol; if (isNaN(parseInt(params.event_id)) &pipe;&pipe; params.event_id < 1) {&eol; throw 'Incorrect "event_id" parameter given: ' + params.event_id + '\nMust be a positive number.';&eol; }&eol;&eol; if ((params.event_source === '1' &pipe;&pipe; params.event_source === '2') && params.event_value === '0') {&eol; throw 'Recovery operations are supported only for Trigger and Internal actions.';&eol; }&eol;&eol; if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {&eol; params.event_nseverity = '7';&eol; }&eol;&eol; if (params.event_value === '0') {&eol; params.event_nseverity = '6';&eol; }&eol;&eol; priority = params['severity_' + severities[params.event_nseverity]];&eol; params.zbxurl = params.zbxurl + (params.zbxurl.endsWith('/') ? '' : '/');&eol;&eol; Media.name = 'Opsgenie';&eol; Media.setParams(media);&eol; Media.params.token = 'GenieKey ' + Media.params.token;&eol; Media.setProxy(params.HTTPProxy);&eol; Media.setTags(params.event_tags_json); // Set Media.labels&eol;&eol; // Create an issue.&eol; // Numeric value of the event that triggered an action (1 for problem, 0 for recovering).&eol; // Numeric value of the problem update status. Possible values:&eol; // 0 - Webhook was called because of problem/recovery event, 1 - Update operation.&eol; if ((params.event_source == 0 && params.event_value == 1 && params.event_update_status == 0)&eol; &pipe;&pipe; (params.event_source == 3 && params.event_value == 1)&eol; &pipe;&pipe; params.event_source == 1 &pipe;&pipe; params.event_source == 2) {&eol; fields.message = params.alert_subject;&eol; fields.alias = params.event_id;&eol; fields.description = params.alert_message;&eol; fields.priority = priority;&eol; fields.source = 'Zabbix';&eol;&eol; if (params.event_source === '0') {&eol; fields.details = {&eol; 'Zabbix server': params.zbxurl,&eol; Problem: params.zbxurl + 'tr_events.php?triggerid=' + params.trigger_id + '&eventid=' + params.event_id&eol; };&eol; }&eol; else {&eol; fields.details = {'Zabbix server': params.zbxurl};&eol; }&eol;&eol; if (typeof params.opsgenie_teams === 'string') {&eol; responders = params.opsgenie_teams.split(',');&eol; fields.responders = responders.map(function(team) {&eol; return {type: 'team', name: team.trim()};&eol; });&eol; }&eol;&eol; fields.tags = Media.labels;&eol; if (typeof params.opsgenie_tags === 'string') {&eol; tags = params.opsgenie_tags.split(',');&eol; tags.forEach(function(item) {&eol; fields.tags.push(item.trim());&eol; });&eol; }&eol;&eol; resp = Media.request('post', '', fields);&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.result === 'undefined') {&eol; throw 'Cannot create ' + Media.name + ' issue. Check debug log for more information.';&eol; }&eol;&eol; if (resp.status === 202) {&eol; resp = Media.getAlertId(resp.response.requestId);&eol; if (params.event_source == 0 && params.event_value == 1 && params.event_update_status == 0) {&eol; result.tags.__zbx_ops_issuekey = resp.response.data.alertId;&eol; result.tags.__zbx_ops_issuelink = Media.params.web + 'alert/detail/' + resp.response.data.alertId;&eol; }&eol; }&eol; else {&eol; throw Media.name + ' response code is unexpected. Check debug log for more information.';&eol; }&eol; }&eol; // Update a created issue.&eol; else {&eol; fields.user = (params.event_value != 0) ? params.zbxuser : '';&eol; fields.note = params.alert_message;&eol;&eol; resp = Media.request('post', params.event_id + '/notes?identifierType=alias', fields);&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.result === 'undefined') {&eol; throw 'Cannot update ' + Media.name + ' issue. Check debug log for more information.';&eol; }&eol;&eol; if (resp.status === 202) {&eol; resp = Media.getAlertId(resp.response.requestId);&eol; }&eol; else {&eol; throw Media.name + ' response code is unexpected. Check debug log for more information.';&eol; }&eol; }&eol;&eol; return JSON.stringify(result);&eol;}&eol;catch (error) {&eol; Zabbix.Log(3, '[ ' + Media.name + ' Webhook ] ERROR: ' + error);&eol; throw 'Sending failed: ' + error;&eol;}|30s |1 |1 |{EVENT.TAGS.__zbx_ops_issuelink} |Opsgenie: {EVENT.TAGS.__zbx_ops_issuekey} |Please refer to https://docs.opsgenie.com/docs/alert-api and https://www.zabbix.com/documentation/5.0/manual/config/notifications/media/webhook#example_scripts.&eol; &eol;Set global macro {$ZABBIX.URL} with your Zabbix server URL.&eol;Add dedicated user with media type "Opsgenie".&eol;Change the values of the variables opsgenie_api (https://api.opsgenie.com/v2/alerts or https://api.eu.opsgenie.com/v2/alerts),&eol;opsgenie_web (for example, https://myzabbix.app.opsgenie.com), opsgenie_token. |
+ROW |6 |4 |Opsgenie | | | | | | | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 |var method,&eol; Media = {&eol; params: {},&eol; name: '',&eol; labels: [],&eol; HTTPProxy: '',&eol;&eol; setParams: function (params) {&eol; if (typeof params !== 'object') {&eol; return;&eol; }&eol;&eol; Media.params = params;&eol; Media.params.api += Media.params.api.endsWith('/') ? '' : '/';&eol; Media.params.web += Media.params.web.endsWith('/') ? '' : '/';&eol; },&eol;&eol; setProxy: function (HTTPProxy) {&eol; if (typeof HTTPProxy !== 'undefined' && HTTPProxy.trim() !== '') {&eol; Media.HTTPProxy = HTTPProxy;&eol; }&eol; },&eol;&eol; setTags: function(event_tags_json) {&eol; if (typeof event_tags_json !== 'undefined' && event_tags_json !== ''&eol; && event_tags_json !== '{EVENT.TAGSJSON}') {&eol;&eol; try {&eol; var tags = JSON.parse(event_tags_json),&eol; label;&eol;&eol; tags.forEach(function (tag) {&eol; if (typeof tag.tag === 'string') {&eol; label = (tag.tag + (typeof tag.value !== 'undefined'&eol; && tag.value !== '' ? (':' + tag.value) : '')).replace(/\s/g, '_');&eol; Media.labels.push(label);&eol; }&eol; });&eol; }&eol; catch (error) {&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Failed to parse "event_tags_json" param');&eol; }&eol; }&eol; },&eol;&eol; request: function (method, query, data, allow_404) {&eol; if (typeof(allow_404) === 'undefined') {&eol; allow_404 = false;&eol; }&eol;&eol; ['api', 'token'].forEach(function (field) {&eol; if (typeof Media.params !== 'object' &pipe;&pipe; typeof Media.params[field] === 'undefined'&eol; &pipe;&pipe; Media.params[field] === '') {&eol; throw 'Required ' + Media.name + ' param is not set: "' + field + '".';&eol; }&eol; });&eol;&eol; var response,&eol; url = Media.params.api + query,&eol; request = new CurlHttpRequest();&eol;&eol; request.AddHeader('Content-Type: application/json');&eol; request.AddHeader('Authorization: ' + Media.params.token);&eol; request.SetProxy(Media.HTTPProxy);&eol;&eol; if (typeof data !== 'undefined') {&eol; data = JSON.stringify(data);&eol; }&eol;&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Sending request: ' +&eol; url + ((typeof data === 'string') ? ('\n' + data) : ''));&eol;&eol; switch (method) {&eol; case 'get':&eol; response = request.Get(url, data);&eol; break;&eol;&eol; case 'post':&eol; response = request.Post(url, data);&eol; break;&eol;&eol; case 'put':&eol; response = request.Put(url, data);&eol; break;&eol;&eol; default:&eol; throw 'Unsupported HTTP request method: ' + method;&eol; }&eol;&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Received response with status code ' +&eol; request.Status() + '\n' + response);&eol;&eol; if (response !== null) {&eol; try {&eol; response = JSON.parse(response);&eol; }&eol; catch (error) {&eol; Zabbix.Log(4, '[ ' + Media.name + ' Webhook ] Failed to parse response.');&eol; response = null;&eol; }&eol; }&eol;&eol; if ((request.Status() < 200 &pipe;&pipe; request.Status() >= 300)&eol; && (!allow_404 &pipe;&pipe; request.Status() !== 404)) {&eol; var message = 'Request failed with status code ' + request.Status();&eol;&eol; if (response !== null) {&eol; if (typeof response.errors === 'object' && Object.keys(response.errors).length > 0) {&eol; message += ': ' + JSON.stringify(response.errors);&eol; }&eol; else if (typeof response.errorMessages === 'object' && Object.keys(response.errorMessages).length > 0) {&eol; message += ': ' + JSON.stringify(response.errorMessages);&eol; }&eol; else if (typeof response.message === 'string') {&eol; message += ': ' + response.message;&eol; }&eol; }&eol;&eol; throw message + ' Check debug log for more information.';&eol; }&eol;&eol; return {&eol; status: request.Status(),&eol; response: response&eol; };&eol; },&eol;&eol; getAlertId: function (requestId) {&eol; status_counter = params.status_counter &pipe;&pipe; 25; &eol; do {&eol; resp = Media.request('get', 'requests/' + requestId, undefined, true);&eol; status_counter -= 1;&eol; }&eol; while ( status_counter > 0 && &eol; ( &eol; typeof resp.response !== 'object' &pipe;&pipe; &eol; typeof resp.response.data === 'undefined' &pipe;&pipe;&eol; resp.response.data.success === false &&&eol; !resp.response.data.status.includes("There is no open alert") &&&eol; !resp.response.data.status.includes("Alert is already")&eol; ) &eol; );&eol;&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.data === 'undefined') {&eol; throw 'Cannot get ' + Media.name + ' issue ID. Check debug log for more information.';&eol; }&eol; else if (resp.response.data.success === false ) {&eol; throw Media.name + ': Operation status (' + resp.response.data.status + ')';&eol; }&eol;&eol; return resp;&eol; }&eol;};&eol;&eol;try {&eol; var result = {tags: {}},&eol; params = JSON.parse(value),&eol; media = {},&eol; fields = {},&eol; resp = {},&eol; responders = [],&eol; tags = [],&eol; required_params = [&eol; 'alert_subject',&eol; 'alert_message',&eol; 'event_id',&eol; 'event_source',&eol; 'event_value',&eol; 'event_update_status',&eol; 'opsgenie_api',&eol; 'opsgenie_web',&eol; 'opsgenie_token'&eol; ],&eol; severities = [&eol; 'not_classified',&eol; 'information',&eol; 'warning',&eol; 'average',&eol; 'high',&eol; 'disaster',&eol; 'resolved',&eol; 'default'&eol; ],&eol; priority;&eol;&eol; Object.keys(params)&eol; .forEach(function (key) {&eol; if (required_params.indexOf(key) !== -1 && params[key].trim() === '') {&eol; throw 'Parameter "' + key + '" cannot be empty.';&eol; }&eol; if (key.startsWith('opsgenie_')) {&eol; media[key.substring(9)] = params[key];&eol; }&eol; });&eol;&eol; // Possible values of event_source:&eol; // 0 - Trigger, 1 - Discovery, 2 - Autoregistration, 3 - Internal.&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol;&eol; // Check event_value for trigger-based and internal events.&eol; // Possible values: 1 for problem, 0 for recovering&eol; if (params.event_value !== '0' && params.event_value !== '1'&eol; && (params.event_source === '0' &pipe;&pipe; params.event_source === '3')) {&eol; throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';&eol; }&eol;&eol; // Check event_update_status only for trigger-based events.&eol; // Possible values: 0 - Webhook was called because of problem/recovery event, 1 - Update operation.&eol; if (params.event_source === '0' && params.event_update_status !== '0' && params.event_update_status !== '1') {&eol; throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';&eol; }&eol;&eol; // Check event_id for a numeric value.&eol; if (isNaN(parseInt(params.event_id)) &pipe;&pipe; params.event_id < 1) {&eol; throw 'Incorrect "event_id" parameter given: ' + params.event_id + '\nMust be a positive number.';&eol; }&eol;&eol; if ((params.event_source === '1' &pipe;&pipe; params.event_source === '2') && params.event_value === '0') {&eol; throw 'Recovery operations are supported only for Trigger and Internal actions.';&eol; }&eol;&eol; if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {&eol; params.event_nseverity = '7';&eol; }&eol;&eol; if (params.event_value === '0') {&eol; params.event_nseverity = '6';&eol; }&eol;&eol; priority = params['severity_' + severities[params.event_nseverity]];&eol; params.zbxurl = params.zbxurl + (params.zbxurl.endsWith('/') ? '' : '/');&eol;&eol; Media.name = 'Opsgenie';&eol; Media.setParams(media);&eol; Media.params.token = 'GenieKey ' + Media.params.token;&eol; Media.setProxy(params.HTTPProxy);&eol; Media.setTags(params.event_tags_json); // Set Media.labels&eol;&eol; // Create an issue.&eol; // Numeric value of the event that triggered an action (1 for problem, 0 for recovering).&eol; // Numeric value of the problem update status. Possible values:&eol; // 0 - Webhook was called because of problem/recovery event, 1 - Update operation.&eol; if ((params.event_source == 0 && params.event_value == 1 && params.event_update_status == 0)&eol; &pipe;&pipe; (params.event_source == 3 && params.event_value == 1)&eol; &pipe;&pipe; params.event_source == 1 &pipe;&pipe; params.event_source == 2) {&eol; fields.message = params.alert_subject;&eol; fields.alias = params.event_id;&eol; fields.description = params.alert_message;&eol; fields.priority = priority;&eol; fields.source = 'Zabbix';&eol;&eol; if (params.event_source === '0') {&eol; fields.details = {&eol; 'Zabbix server': params.zbxurl,&eol; Problem: params.zbxurl + 'tr_events.php?triggerid=' + params.trigger_id + '&eventid=' + params.event_id&eol; };&eol; }&eol; else {&eol; fields.details = {'Zabbix server': params.zbxurl};&eol; }&eol;&eol; if (typeof params.opsgenie_teams === 'string') {&eol; responders = params.opsgenie_teams.split(',');&eol; fields.responders = responders.map(function(team) {&eol; return {type: 'team', name: team.trim()};&eol; });&eol; }&eol;&eol; fields.tags = Media.labels;&eol; if (typeof params.opsgenie_tags === 'string') {&eol; tags = params.opsgenie_tags.split(',');&eol; tags.forEach(function(item) {&eol; fields.tags.push(item.trim());&eol; });&eol; }&eol;&eol; resp = Media.request('post', '', fields);&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.result === 'undefined') {&eol; throw 'Cannot create ' + Media.name + ' issue. Check debug log for more information.';&eol; }&eol;&eol; if (resp.status === 202) {&eol; resp = Media.getAlertId(resp.response.requestId);&eol; if (params.event_source == 0 && params.event_value == 1 && params.event_update_status == 0) {&eol; result.tags.__zbx_ops_issuekey = resp.response.data.alertId;&eol; result.tags.__zbx_ops_issuelink = Media.params.web + 'alert/detail/' + resp.response.data.alertId;&eol; }&eol; }&eol; else {&eol; throw Media.name + ' response code is unexpected. Check debug log for more information.';&eol; }&eol; }&eol; // Update or close the created issue.&eol; else {&eol; fields.user = (params.event_value != 0) ? params.zbxuser : '';&eol; fields.note = params.alert_message;&eol; if ( [0, 3].indexOf(parseInt(params.event_source)) > -1 && params.event_value == 0 ) {&eol; // skip sending of close request from update operation(mandatory when both update & recovery operations are defined in action) &eol; method = params.event_update_status == 0 ? "close" : "skip";&eol; }&eol; else if ( params.event_source == 0 && params.event_value == 1 && params.event_update_status == 1 && params.event_update_action.includes('acknowledged')) {&eol; method = params.event_update_action.includes('unacknowledged') ? "unacknowledge" : "acknowledge";&eol; }&eol; else {&eol; method = "notes";&eol; }&eol;&bsn; if (method !== "skip") {&eol; resp = Media.request('post', params.event_id + '/' + method +'?identifierType=alias', fields);&eol;&eol; if (typeof resp.response !== 'object' &pipe;&pipe; typeof resp.response.result === 'undefined') {&eol; throw 'Cannot update ' + Media.name + ' issue. Check debug log for more information.';&eol; }&eol;&eol; if (resp.status === 202) {&eol; resp = Media.getAlertId(resp.response.requestId);&eol; }&eol; else {&eol; throw Media.name + ' response code is unexpected. Check debug log for more information.';&eol; }&eol; }&eol; }&eol; return JSON.stringify(result);&eol;}&eol;catch (error) {&eol; Zabbix.Log(3, '[ ' + Media.name + ' Webhook ] ERROR: ' + error);&eol; throw 'Sending failed: ' + error;&eol;}|30s |1 |1 |{EVENT.TAGS.__zbx_ops_issuelink} |Opsgenie: {EVENT.TAGS.__zbx_ops_issuekey} |Please refer to https://docs.opsgenie.com/docs/alert-api and https://www.zabbix.com/documentation/5.0/manual/config/notifications/media/webhook#example_scripts.&eol; &eol;Set global macro {$ZABBIX.URL} with your Zabbix server URL.&eol;Add dedicated user with media type "Opsgenie".&eol;Change the values of the variables opsgenie_api (https://api.opsgenie.com/v2/alerts or https://api.eu.opsgenie.com/v2/alerts),&eol;opsgenie_web (for example, https://myzabbix.app.opsgenie.com), opsgenie_token. |
ROW |7 |4 |PagerDuty | | | | | | | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 |try {&eol;&eol; var params = JSON.parse(value),&eol; req = new CurlHttpRequest(),&eol; fields = {},&eol; resp = '';&eol;&eol; // Correspondence between the PagerDuty and Zabbix severity level&eol; var severityMapping = [&eol; 'info', // Not classified&eol; 'info', // Information&eol; 'warning', // Warning&eol; 'warning', // Average&eol; 'error', // High&eol; 'critical' // Disaster&eol; ];&eol;&eol; if (!severityMapping[params.severity]) {&eol; params.severity = '0';&eol; }&eol;&eol; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {&eol; req.SetProxy(params.HTTPProxy);&eol; }&eol;&eol; if (isNaN(parseInt(params.eventid)) &pipe;&pipe; params.eventid < 1) {&eol; throw 'incorrect value for variable "eventid". The value must be a positive number.';&eol; }&eol; if (params.eventname.length < 1) {&eol; throw 'incorrect value for variable "eventname". The value must be a non-empty string.';&eol; }&eol; if (isNaN(parseInt(params.severity)) &pipe;&pipe; (params.severity < 0 && params.severity > 5)) {&eol; throw 'incorrect value for variable "severity". The value must be a number 0..5.';&eol; }&eol;&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol; // Check {EVENT.VALUE} for trigger-based and internal events.&eol; if (params.eventvalue !== '0' && params.eventvalue !== '1'&eol; && (params.event_source === '0' &pipe;&pipe; params.event_source === '3')) {&eol; throw 'Incorrect "eventvalue" parameter given: "' + params.eventvalue + '".\nMust be 0 or 1.';&eol; }&eol;&eol; if (params.event_source === '0') {&eol; if (params.hostname.length < 1) {&eol; throw 'incorrect value for variable "hostname". The value must be a non-empty string.';&eol; }&eol; if (isNaN(parseInt(params.triggerid)) &pipe;&pipe; params.triggerid < 1) {&eol; throw 'incorrect value for variable "triggerid". The value must be a positive number.';&eol; }&eol; if (params.eventack != 'Yes' && params.eventack != 'No') {&eol; throw 'incorrect value for variable "eventack". The value must be Yes or No.';&eol; }&eol; if (isNaN(parseInt(params.eventupdate)) &pipe;&pipe; (params.eventupdate < 0 &pipe;&pipe; params.eventupdate > 1)) {&eol; throw 'incorrect value for variable "eventupdate". The value must be 0 or 1.';&eol; }&eol; }&eol;&eol;&eol;&eol; req.AddHeader('Content-Type: application/json');&eol;&eol; fields.routing_key = params.token;&eol; fields.dedup_key = params.eventid;&eol;&eol; if (((params.eventvalue == 1) && (params.eventupdate == 0)) &pipe;&pipe; params.event_source !== '0') {&eol; fields.event_action = 'trigger';&eol; fields.payload = {&eol; summary: params.eventname,&eol; source: (params.event_source === '1') ? 'Discovery' : params.hostname + ' : ' + params.hostip,&eol; severity: severityMapping[params.severity],&eol; };&eol; &eol; if (params.event_source === '0') {&eol; fields.payload.custom_details = {&eol; 'Event date': params.eventdate,&eol; 'Event time': params.eventtime,&eol; 'Trigger description': params.triggerdesc,&eol; 'Trigger opdata': params.triggeropdata,&eol; 'Event tags': params.eventtags,&eol; 'Event host': params.hostname,&eol; 'Event host ip': params.hostip&eol; };&eol; fields.links = [{&eol; href: params.url + '/tr_events.php?triggerid=' + params.triggerid + '&eventid=' + params.eventid,&eol; text: 'Event link'&eol; }];&eol; }&eol; else {&eol; fields.payload.custom_details = {&eol; 'Alert message': params.alert_message&eol; };&eol; }&eol;&eol; fields.client = 'Zabbix';&eol; fields.client_url = params.url;&eol; }&eol; else if ((params.eventvalue == 1) && (params.eventupdate == 1) && (params.eventack == 'Yes'))&eol; fields.event_action = 'acknowledge';&eol; else if (params.eventvalue == 0)&eol; fields.event_action = 'resolve';&eol; else&eol; throw 'incorrect values. Update message without ack will not be sent.';&eol;&eol; Zabbix.Log(4, '[PagerDuty Webhook] Sending request:' + JSON.stringify(fields));&eol; resp = req.Post('https://events.pagerduty.com/v2/enqueue',&eol; JSON.stringify(fields)&eol; );&eol; Zabbix.Log(4, '[PagerDuty Webhook] Receiving response:' + resp);&eol;&eol; try {&eol; resp = JSON.parse(resp);&eol; }&eol; catch (error) {&eol; throw 'incorrect response. PagerDuty returned a non-JSON object.';&eol; }&eol;&eol; if (req.Status() != 202) {&eol; if (typeof resp === 'object' && typeof resp.errors === 'object' && typeof resp.errors[0] === 'string') {&eol; throw resp.errors[0];&eol; }&eol; else {&eol; throw 'Unknown error.';&eol; }&eol; }&eol;&eol; if (resp.status != 'success') {&eol; throw 'Unknown error.';&eol; }&eol;&eol; return 'OK';&eol;}&eol;catch (error) {&eol; Zabbix.Log(3, '[PagerDuty Webhook] Notification failed : ' + error);&eol; throw 'PagerDuty notification failed : ' + error;&eol;}|30s |0 |0 | | |Please refer to https://v2.developer.pagerduty.com/docs/send-an-event-events-api-v2 and https://www.zabbix.com/documentation/5.0/manual/config/notifications/media/webhook#example_scripts.&eol; &eol;Set global macro {$ZABBIX.URL} with your Zabbix server URL.&eol;Add a dedicated user with the media type "PagerDuty" and place the integration key in the "token" parameter to integrate into the service. |
ROW |8 |4 |Pushover | | | | | | | |0 |25 |0 |0 |0 |0 | |0 |3 |10s |1 |try {&eol; var params = JSON.parse(value),&eol; request = new CurlHttpRequest(),&eol; data,&eol; response,&eol; severities = [&eol; {name: 'not_classified', color: '#97AAB3'},&eol; {name: 'information', color: '#7499FF'},&eol; {name: 'warning', color: '#FFC859'},&eol; {name: 'average', color: '#FFA059'},&eol; {name: 'high', color: '#E97659'},&eol; {name: 'disaster', color: '#E45959'},&eol; {name: 'resolved', color: '#009900'},&eol; {name: 'default', color: '#000000'}&eol; ],&eol; priority;&eol;&eol; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {&eol; request.SetProxy(params.HTTPProxy);&eol; }&eol;&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol;&eol; if (params.event_value !== '0' && params.event_value !== '1'&eol; && (params.event_source === '0' &pipe;&pipe; params.event_source === '3')) {&eol; throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';&eol; }&eol;&eol; if ([0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity)) === -1) {&eol; params.event_nseverity = '7';&eol; }&eol;&eol; if (params.event_value === '0') {&eol; params.event_nseverity = '6';&eol; }&eol;&eol; priority = params['priority_' + severities[params.event_nseverity].name] &pipe;&pipe; params.priority_default;&eol;&eol; if (isNaN(priority) &pipe;&pipe; priority < -2 &pipe;&pipe; priority > 2) {&eol; throw '"priority" should be -2..2';&eol; }&eol;&eol; if (params.event_source === '0' && isNaN(params.triggerid)) {&eol; throw 'field "triggerid" is not a number';&eol; }&eol;&eol; if (isNaN(params.eventid)) {&eol; throw 'field "eventid" is not a number';&eol; }&eol;&eol; if (typeof params.message !== 'string' &pipe;&pipe; params.message.trim() === '') {&eol; throw 'field "message" cannot be empty';&eol; }&eol;&eol; data = {&eol; token: params.token,&eol; user: params.user,&eol; title: params.title,&eol; message: params.message,&eol; url: (params.event_source === '0') &eol; ? params.url + '/tr_events.php?triggerid=' + params.triggerid + '&eventid=' + params.eventid&eol; : params.url,&eol; url_title: params.url_title,&eol; priority: priority&eol; };&eol;&eol; if (priority == 2) {&eol; if (isNaN(params.retry) &pipe;&pipe; params.retry < 30) {&eol; throw 'field "retry" should be a number with value of at least 30 if "priority" is set to 2';&eol; }&eol;&eol; if (isNaN(params.expire) &pipe;&pipe; params.expire > 10800) {&eol; throw 'field "expire" should be a number with value of at most 10800 if "priority" is set to 2';&eol; }&eol;&eol; data.retry = params.retry;&eol; data.expire = params.expire;&eol; }&eol;&eol; data = JSON.stringify(data);&eol; Zabbix.Log(4, '[ Pushover Webhook ] Sending request: ' + params.endpoint + '\n' + data);&eol;&eol; request.AddHeader('Content-Type: application/json');&eol; response = request.Post(params.endpoint, data);&eol;&eol; Zabbix.Log(4, '[ Pushover Webhook ] Received response with status code ' + request.Status() + '\n' + response);&eol;&eol; if (response !== null) {&eol; try {&eol; response = JSON.parse(response);&eol; }&eol; catch (error) {&eol; Zabbix.Log(4, '[ Pushover Webhook ] Failed to parse response received from Pushover');&eol; response = null;&eol; }&eol; }&eol;&eol; if (request.Status() != 200 &pipe;&pipe; response === null &pipe;&pipe; typeof response !== 'object' &pipe;&pipe; response.status !== 1) {&eol; if (response !== null && typeof response === 'object' && typeof response.errors === 'object'&eol; && typeof response.errors[0] === 'string') {&eol; throw response.errors[0];&eol; }&eol; else {&eol; throw 'Unknown error. Check debug log for more information.';&eol; }&eol; }&eol;&eol; return 'OK';&eol;}&eol;catch (error) {&eol; Zabbix.Log(4, '[ Pushover Webhook ] Pushover notification failed: ' + error);&eol; throw 'Pushover notification failed: ' + error;&eol;}|30s |0 |0 | | |Please refer to setup guide here: https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/media/pushover&eol;&eol;Set token parameter with to your Pushover application key.&eol;When assigning Pushover media to the Zabbix user - add user key into send to field. |
ROW |9 |4 |Slack | | | | | | | |0 |25 |0 |0 |0 |0 | |1 |3 |10s |1 |var SEVERITY_COLORS = [&eol; '#97AAB3', '#7499FF', '#FFC859',&eol; '#FFA059', '#E97659', '#E45959'&eol;];&eol;&eol;var RESOLVE_COLOR = '#009900';&eol;&eol;var SLACK_MODE_HANDLERS = {&eol; alarm: handlerAlarm,&eol; event: handlerEvent&eol;};&eol;&eol;&eol;if (!String.prototype.format) {&eol; String.prototype.format = function() {&eol; var args = arguments;&eol;&eol; return this.replace(/{(\d+)}/g, function(match, number) {&eol; return number in args&eol; ? args[number]&eol; : match&eol; ;&eol; });&eol; };&eol;}&eol;&eol;function isEventProblem(params) {&eol; return params.event_value == 1&eol; && params.event_update_status == 0&eol; ;&eol;}&eol;&eol;function isEventUpdate(params) {&eol; return params.event_value == 1&eol; && params.event_update_status == 1&eol; ;&eol;}&eol;&eol;function isEventResolve(params) {&eol; return params.event_value == 0;&eol;}&eol;&eol;function getPermalink(channelId, messageTimestamp) {&eol; var req = new CurlHttpRequest();&eol;&eol; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {&eol; req.SetProxy(params.HTTPProxy);&eol; }&eol;&eol; req.AddHeader('Content-Type: application/x-www-form-urlencoded; charset=utf-8');&eol; req.AddHeader('Authorization: Bearer ' + params.bot_token);&eol;&eol; var query = '{0}?channel={1}&message_ts={2}'.format(&eol; Slack.getPermalink,&eol; encodeURIComponent(channelId),&eol; encodeURIComponent(messageTimestamp)),&eol; resp = JSON.parse(req.Get(query));&eol;&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw 'message was created, but getting message link was failed with reason "' + resp.error + '"';&eol; }&eol;&eol; return resp.permalink;&eol;}&eol;&eol;function createProblemURL(zabbix_url, triggerid, eventid, event_source) {&eol; var problem_url = '';&eol; if (event_source === '0') {&eol; problem_url = '{0}/tr_events.php?triggerid={1}&eventid={2}'&eol; .format(&eol; zabbix_url,&eol; triggerid,&eol; eventid&eol; );&eol; }&eol; else {&eol; problem_url = zabbix_url;&eol; }&eol;&eol; return problem_url;&eol;}&eol;&eol;function handlerAlarm(params) {&eol; var fields = {&eol; channel: params.channel,&eol; as_user: params.slack_as_user,&eol; };&eol;&eol; if (isEventProblem(params)) {&eol; fields.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; var resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol;&eol; result.tags = {&eol; ['__message_ts_' + params.channel]: resp.ts,&eol; ['__channel_id_' + params.channel]: resp.channel,&eol; ['__message_link_' + params.channel]: getPermalink(resp.channel, resp.ts),&eol; };&eol;&eol; }&eol; else if (isEventUpdate(params)) {&eol; try {&eol; var channel_event_tags = JSON.parse(params.event_tags);&eol; } catch (error) {&eol; throw 'Cannot process event tags: ' + error;&eol; }&eol;&eol; if (Array.isArray(channel_event_tags)) {&eol; for (i in channel_event_tags) {&eol; if (channel_event_tags[i].tag.includes('__message_ts_' + params.channel)) {&eol; fields.thread_ts = channel_event_tags[i].value;&eol; break;&eol; }&eol; }&eol; }&eol;&eol; fields.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_update_date,&eol; params.event_update_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&eol; true&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol;&eol; }&eol; else if (isEventResolve(params)) {&eol; fields.text = '';&eol;&eol; try {&eol; var channel_event_tags = JSON.parse(params.event_tags);&eol; } catch (error) {&eol; throw 'Cannot process event tags: ' + error;&eol; }&eol;&eol; if (Array.isArray(channel_event_tags)) {&eol; for (i in channel_event_tags) {&eol; if (channel_event_tags[i].tag.includes('__channel_id_' + params.channel)) {&eol; fields.channel = channel_event_tags[i].value;&eol; continue;&eol; }&eol; if (channel_event_tags[i].tag.includes('__message_ts_' + params.channel)) {&eol; fields.ts = channel_event_tags[i].value;&eol; }&eol; }&eol; }&eol;&eol; fields.attachments = [&eol; createMessage(&eol; RESOLVE_COLOR,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Slack.chatUpdate, JSON.stringify(fields)));&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol; }&eol;}&eol;&eol;function handlerEvent(params) {&eol; var fields = {&eol; channel: params.channel,&eol; as_user: params.slack_as_user&eol; };&eol;&eol; if (isEventProblem(params)) {&eol; fields.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_date,&eol; params.event_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; var resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol;&eol; result.tags = {&eol; ['__message_link_' + params.channel]: getPermalink(resp.channel, resp.ts)&eol; }&eol;&eol; }&eol; else if (isEventUpdate(params)) {&eol; fields.attachments = [&eol; createMessage(&eol; SEVERITY_COLORS[params.event_nseverity] &pipe;&pipe; 0,&eol; params.event_update_date,&eol; params.event_update_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source),&eol; false&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol;&eol; }&eol; else if (isEventResolve(params)) {&eol; fields.attachments = [&eol; createMessage(&eol; RESOLVE_COLOR,&eol; params.event_recovery_date,&eol; params.event_recovery_time,&eol; createProblemURL(params.zabbix_url, params.trigger_id, params.event_id, params.event_source)&eol; )&eol; ];&eol;&eol; resp = JSON.parse(req.Post(Slack.postMessage, JSON.stringify(fields)));&eol;&eol; if (req.Status() != 200 &pipe;&pipe; !resp.ok &pipe;&pipe; resp.ok === 'false') {&eol; throw resp.error;&eol; }&eol; }&eol;}&eol;&eol;function createMessage(&eol; event_severity_color,&eol; event_date,&eol; event_time,&eol; problem_url,&eol; isShort,&eol; messageText&eol;) {&eol; var message = {&eol; fallback: params.alert_subject,&eol; title: params.alert_subject,&eol; color: event_severity_color,&eol; title_link: problem_url,&eol; pretext: messageText &pipe;&pipe; '',&eol;&eol; fields: [&eol; {&eol; title: 'Host',&eol; value: '{0} [{1}]'.format(params.host_name, params.host_conn),&eol; short: true&eol; },&eol; {&eol; title: 'Event time',&eol; value: '{0} {1}'.format(event_date, event_time),&eol; short: true&eol; }&eol; ],&eol; };&eol;&eol; if (params.event_source === '0') {&eol; message.fields.push(&eol; {&eol; title: 'Severity',&eol; value: params.event_severity,&eol; short: true&eol; },&eol; {&eol; title: 'Opdata',&eol; value: params.event_opdata,&eol; short: true&eol; }&eol; );&eol; }&eol;&eol; if (!isShort && params.event_source === '0') {&eol; message['actions'] = [&eol; {&eol; type: 'button',&eol; text: 'Open in Zabbix',&eol; url: problem_url&eol; }&eol; ];&eol;&eol; message.fields.push(&eol; {&eol; title: 'Event tags',&eol; value: JSON.parse(params.event_tags).filter(function (e) { return !e.tag.includes('__') }).map(function (e) { return e.tag + ': ' + e.value }).join('\n') &pipe;&pipe; 'None',&eol; short: true&eol; },&eol; {&eol; title: 'Trigger description',&eol; value: params.trigger_description,&eol; short: true&eol; }&eol; );&eol; }&eol;&eol; if (params.event_source !== '0' &pipe;&pipe; params.event_update_status === '1') {&eol; message.fields.push(&eol; {&eol; title: 'Details',&eol; value: params.alert_message,&eol; short: false&eol; }&eol; );&eol; }&eol;&eol; return message;&eol;}&eol;&eol;function validateParams(params) {&eol; if (typeof params.bot_token !== 'string' &pipe;&pipe; params.bot_token.trim() === '') {&eol; throw 'Field "bot_token" cannot be empty';&eol; }&eol;&eol; if (typeof params.channel !== 'string' &pipe;&pipe; params.channel.trim() === '') {&eol; throw 'Field "channel" cannot be empty';&eol; }&eol;&eol; if (isNaN(params.event_id)) {&eol; throw 'Field "event_id" is not a number';&eol; }&eol;&eol; if ([0, 1, 2, 3].indexOf(parseInt(params.event_source)) === -1) {&eol; throw 'Incorrect "event_source" parameter given: "' + params.event_source + '".\nMust be 0-3.';&eol; }&eol;&eol; if (params.event_source !== '0') {&eol; params.event_nseverity = '0';&eol; params.event_severity = 'Not classified';&eol; params.event_update_status = '0';&eol; params.slack_mode = 'event';&eol; }&eol;&eol; if (params.event_source === '1' &pipe;&pipe; params.event_source === '2') {&eol; params.event_value = '1';&eol; }&eol;&eol; if (params.event_source === '1') {&eol; params.host_name = params.discovery_host_dns;&eol; params.host_ip = params.discovery_host_ip;&eol; }&eol;&eol; if (!~[0, 1, 2, 3, 4, 5].indexOf(parseInt(params.event_nseverity))) {&eol; throw 'Incorrect "event_nseverity" parameter given: ' + params.event_nseverity + '\nMust be 0-5.';&eol; }&eol;&eol; if (typeof params.event_severity !== 'string' &pipe;&pipe; params.event_severity.trim() === '') {&eol; throw 'Field "event_severity" cannot be empty';&eol; }&eol;&eol; if (params.event_update_status !== '0' && params.event_update_status !== '1') {&eol; throw 'Incorrect "event_update_status" parameter given: ' + params.event_update_status + '\nMust be 0 or 1.';&eol; }&eol;&eol; if (params.event_value !== '0' && params.event_value !== '1') {&eol; throw 'Incorrect "event_value" parameter given: ' + params.event_value + '\nMust be 0 or 1.';&eol; }&eol;&eol; if (typeof params.host_conn !== 'string' &pipe;&pipe; params.host_conn.trim() === '') {&eol; throw 'Field "host_conn" cannot be empty';&eol; }&eol;&eol; if (typeof params.host_name !== 'string' &pipe;&pipe; params.host_name.trim() === '') {&eol; throw 'Field "host_name" cannot be empty';&eol; }&eol;&eol; if (!~['true', 'false'].indexOf(params.slack_as_user.toLowerCase())) {&eol; throw 'Incorrect "slack_as_user" parameter given: ' + params.slack_as_user + '\nMust be "true" or "false".';&eol; }&eol;&eol; if (!~['alarm', 'event'].indexOf(params.slack_mode)) {&eol; throw 'Incorrect "slack_mode" parameter given: ' + params.slack_mode + '\nMust be "alarm" or "event".';&eol; }&eol;&eol; if (isNaN(params.trigger_id) && params.event_source === '0') {&eol; throw 'field "trigger_id" is not a number';&eol; }&eol;&eol; if (typeof params.zabbix_url !== 'string' &pipe;&pipe; params.zabbix_url.trim() === '') {&eol; throw 'Field "zabbix_url" cannot be empty';&eol; }&eol;&eol; if (!/^(http&pipe;https):\/\/.+/.test(params.zabbix_url)) {&eol; throw 'Field "zabbix_url" must contain a schema';&eol; }&eol;}&eol;&eol;try {&eol; var params = JSON.parse(value);&eol;&eol; validateParams(params);&eol;&eol; var req = new CurlHttpRequest(),&eol; result = {tags: {}};&eol;&eol; if (typeof params.HTTPProxy === 'string' && params.HTTPProxy.trim() !== '') {&eol; req.SetProxy(params.HTTPProxy);&eol; }&eol;&eol; req.AddHeader('Content-Type: application/json; charset=utf-8');&eol; req.AddHeader('Authorization: Bearer ' + params.bot_token);&eol;&eol; var slack_endpoint = 'https://slack.com/api/';&eol;&eol; var Slack = {&eol; postMessage: slack_endpoint + 'chat.postMessage',&eol; getPermalink: slack_endpoint + 'chat.getPermalink',&eol; chatUpdate: slack_endpoint + 'chat.update'&eol; };&eol;&eol; params.slack_mode = params.slack_mode.toLowerCase();&eol; params.slack_mode = params.slack_mode in SLACK_MODE_HANDLERS&eol; ? params.slack_mode&eol; : 'alarm';&eol;&eol; SLACK_MODE_HANDLERS[params.slack_mode](params);&eol;&eol; if (params.event_source === '0') {&eol; return JSON.stringify(result);&eol; }&eol; else {&eol; return 'OK';&eol; }&eol;}&eol;catch (error) {&eol; Zabbix.Log(4, '[ Slack Webhook ] Slack notification failed : ' + error);&eol; throw 'Slack notification failed : ' + error;&eol;}|30s |1 |0 | | | |
@@ -624,6 +624,8 @@ ROW |563 |31 |sd_on_premise_auth_token
ROW |564 |31 |sd_request_id |{EVENT.TAGS.__zbx_sd_request_id} |
ROW |565 |31 |sd_url |<PLACE INSTANCE URL> |
ROW |566 |31 |trigger_description |{TRIGGER.DESCRIPTION} |
+ROW |567 |6 |event_update_action |{EVENT.UPDATE.ACTION} |
+ROW |568 |6 |status_counter |25 |
TABLE |media_type_message
FIELDS|mediatype_messageid|mediatypeid|eventsource|recovery|subject |message |