pass additional arguments to alarm URLs; optimizations in alarm-notify.sh
Costa Tsaousis (ktsaou) committed
Sep 11, 2016 at 14:42 UTC
73752d98410a5bc35238e1cb392e47182fa61b16
3 files changed
+92
-40
plugins.d/alarm-notify.sh
+55
-31
@@ -5,11 +5,22 @@
5
6
me="${0}"
7
8
+if [ $(( ${BASH_VERSINFO[0]} )) -lt 4 ]
9
+then
10
+ echo >&2
11
+ echo >&2 "$me: ERROR"
12
+ echo >&2 "BASH version 4 or later is required."
13
+ echo >&2 "You are running version: ${BASH_VERSION}"
14
+ echo >&2 "Please upgrade."
15
+ echo >&2
16
+ exit 1
17
+fi
18
+
19
# -----------------------------------------------------------------------------
20
# parse command line parameters
21
22
recipient="${1}" # the recepient of the email
12
-hostname="${2}" # the hostname this event refers to
23
+host="${2}" # the host this event refers to
24
unique_id="${3}" # the unique id of this event
25
alarm_id="${4}" # the unique id of the alarm that generated this event
26
event_id="${5}" # the incremental id of the event, for this alarm
@@ -17,8 +28,8 @@ when="${6}" # the timestamp this event occured
28
name="${7}" # the name of the alarm, as given in netdata health.d entries
29
chart="${8}" # the name of the chart (type.id)
30
family="${9}" # the family of the chart
20
-status="${10}" # the current status : UNITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
21
-old_status="${11}" # the previous status: UNITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
31
+status="${10}" # the current status : REMOVED, UNITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
32
+old_status="${11}" # the previous status: REMOVED, UNITIALIZED, UNDEFINED, CLEAR, WARNING, CRITICAL
33
value="${12}" # the current value
34
old_value="${13}" # the previous value
35
src="${14}" # the line number and file the alarm has been configured
@@ -79,7 +90,7 @@ if [ -f "${NETDATA_CONFIG_DIR}/health_alarm_notify.conf" ]
90
fi
91
92
# -----------------------------------------------------------------------------
82
-# find the exact recipient per method
93
+# find the recipient's addresses per method
94
95
declare -A arr_slack=()
96
declare -A arr_pushover=()
@@ -87,7 +98,7 @@ declare -A arr_email=()
98
99
# netdata may call us with multiple recipients
100
# so, here we find the unique ones
90
-for x in ${recipient}
101
+for x in ${recipient//,/ }
102
do
103
# email
104
a="${role_recipients_email[${recipient}]}"
@@ -158,9 +169,9 @@ fi
169
# -----------------------------------------------------------------------------
170
# get the system hostname
171
161
-[ -z "${hostname}" ] && hostname="${NETDATA_HOSTNAME}"
162
-[ -z "${hostname}" ] && hostname="${NETDATA_REGISTRY_HOSTNAME}"
163
-[ -z "${hostname}" ] && hostname="$(hostname 2>/dev/null)"
172
+[ -z "${host}" ] && host="${NETDATA_HOSTNAME}"
173
+[ -z "${host}" ] && host="${NETDATA_REGISTRY_HOSTNAME}"
174
+[ -z "${host}" ] && host="$(hostname 2>/dev/null)"
175
176
# -----------------------------------------------------------------------------
177
# get the date the alarm happened
@@ -189,7 +200,9 @@ urlencode() {
200
esac
201
encoded+="${o}"
202
done
192
- echo "${encoded}"
203
+
204
+ REPLY="${encoded}"
205
+ echo "${REPLY}"
206
}
207
208
# -----------------------------------------------------------------------------
@@ -197,7 +210,7 @@ urlencode() {
210
# using DAYS, MINUTES, SECONDS
211
212
duration4human() {
200
- local s="${1}" d=0 h=0 m=0 ds="day" hs="hour" ms="minute" ss="second"
213
+ local s="${1}" d=0 h=0 m=0 ds="day" hs="hour" ms="minute" ss="second" ret
214
d=$(( s / 86400 ))
215
s=$(( s - (d * 86400) ))
216
h=$(( s / 3600 ))
@@ -212,9 +225,9 @@ duration4human() {
225
[ ${h} -gt 1 ] && hs="hours"
226
if [ ${h} -gt 0 ]
227
then
215
- echo "${d} ${ds} and ${h} ${hs}"
228
+ ret="${d} ${ds} and ${h} ${hs}"
229
else
217
- echo "${d} ${ds}"
230
+ ret="${d} ${ds}"
231
fi
232
elif [ ${h} -gt 0 ]
233
then
@@ -223,9 +236,9 @@ duration4human() {
236
[ ${m} -gt 1 ] && ms="minutes"
237
if [ ${m} -gt 0 ]
238
then
226
- echo "${h} ${hs} and ${m} ${ms}"
239
+ ret="${h} ${hs} and ${m} ${ms}"
240
else
228
- echo "${h} ${hs}"
241
+ ret="${h} ${hs}"
242
fi
243
elif [ ${m} -gt 0 ]
244
then
@@ -233,31 +246,36 @@ duration4human() {
246
[ ${s} -gt 1 ] && ss="seconds"
247
if [ ${s} -gt 0 ]
248
then
236
- echo "${m} ${ms} and ${s} ${ss}"
249
+ ret="${m} ${ms} and ${s} ${ss}"
250
else
238
- echo "${m} ${ms}"
251
+ ret="${m} ${ms}"
252
fi
253
else
254
[ ${s} -gt 1 ] && ss="seconds"
242
- echo "${s} ${ss}"
255
+ ret="${s} ${ss}"
256
fi
257
+
258
+ REPLY="${ret}"
259
+ echo "${REPLY}"
260
}
261
262
# -----------------------------------------------------------------------------
263
# email sender
264
265
send_email() {
266
+ local ret=
267
if [ "${SEND_EMAIL}" = "YES" ]
268
then
269
270
"${sendmail}" -t
271
+ ret=$?
272
255
- if [ $? -eq 0 ]
273
+ if [ $ret -eq 0 ]
274
then
257
- echo >&2 "${me}: Sent notification email for ${status} on '${chart}.${name}' to '${to_email}'"
275
+ echo >&2 "${me}: Sent email notification for: ${host} ${chart}.${name} is ${status} to '${to_email}'"
276
return 0
277
else
260
- echo >&2 "${me}: FAILED to send notification email for ${status} on '${chart}.${name}' to '${to_email}'"
278
+ echo >&2 "${me}: Failed to send email notification for: ${host} ${chart}.${name} is ${status} to '${to_email}' with error code ${ret}."
279
return 1
280
fi
281
fi
@@ -325,7 +343,7 @@ send_slack() {
343
for channel in ${channels}
344
do
345
httpcode=$(${curl} --write-out %{http_code} --silent --output /dev/null -X POST --data-urlencode \
328
- "payload={\"channel\": \"#${channel}\", \"username\": \"${username}\", \"text\": \"${hostname} ${status_message} - ${author} ${raised_for} - click <${goto_url}|here> to view the netdata dashboard.\", \"icon_url\": \"${image}\", \"attachments\": [{\"fallback\": \"${alarm} - ${info}\", \"color\": \"${color}\", \"title\": \"${alarm}\", \"title_link\": \"${goto_url}\", \"text\": \"${info}\", \"footer\": \"netdata\", \"footer_icon\": \"${NETDATA_REGISTRY_URL}/images/seo-performance-128.png\", \"ts\": ${when}}]}" \
346
+ "payload={\"channel\": \"#${channel}\", \"username\": \"${username}\", \"text\": \"${host} ${status_message} - ${author} ${raised_for} - click <${goto_url}|here> to view the netdata dashboard.\", \"icon_url\": \"${image}\", \"attachments\": [{\"fallback\": \"${alarm} - ${info}\", \"color\": \"${color}\", \"title\": \"${alarm}\", \"title_link\": \"${goto_url}\", \"text\": \"${info}\", \"footer\": \"netdata\", \"footer_icon\": \"${NETDATA_REGISTRY_URL}/images/seo-performance-128.png\", \"ts\": ${when}}]}" \
347
"${webhook}")
348
349
if [ "${httpcode}" == "200" ]
@@ -348,13 +366,19 @@ send_slack() {
366
# prepare the content of the notification
367
368
# the url to send the user on click
351
-goto_url="${NETDATA_REGISTRY_URL}/goto-host-from-alarm.html?host=$(urlencode "${NETDATA_REGISTRY_HOSTNAME}")&chart=${chart}&family=${family}"
369
+urlencode "${NETDATA_REGISTRY_HOSTNAME}" >/dev/null; url_host="${REPLY}"
370
+urlencode "${chart}" >/dev/null; url_chart="${REPLY}"
371
+urlencode "${family}" >/dev/null; url_family="${REPLY}"
372
+urlencode "${name}" >/dev/null; url_name="${REPLY}"
373
+goto_url="${NETDATA_REGISTRY_URL}/goto-host-from-alarm.html?host=${url_host}&chart=${url_chart}&family=${url_family}&alarm=${url_name}&alarm_unique_id=${unique_id}&alarm_id=${alarm_id}&alarm_event_id=${event_id}"
374
375
# the severity of the alarm
376
severity="${status}"
377
378
# the time the alarm was raised
357
-raised_for="(was ${old_status,,} for $(duration4human ${duration}))"
379
+duration4human ${duration} >/dev/null; duration_txt="${REPLY}"
380
+duration4human ${non_clear_duration} >/dev/null; non_clear_duration_txt="${REPLY}"
381
+raised_for="(was ${old_status,,} for ${duration_txt}"
382
383
# the key status message
384
status_message="status unknown"
@@ -398,7 +422,7 @@ then
422
severity="Recovered from ${old_status}"
423
if [ $non_clear_duration -gt $duration ]
424
then
401
- raised_for="(had issues for $(duration4human ${non_clear_duration}))"
425
+ raised_for="(alarm was raised for ${non_clear_duration_txt})"
426
fi
427
428
elif [ "${old_status}" = "WARNING" -a "${status}" = "CRITICAL" ]
@@ -406,7 +430,7 @@ then
430
severity="Escalated to ${status}"
431
if [ $non_clear_duration -gt $duration ]
432
then
409
- raised_for="(has issues for $(duration4human ${non_clear_duration}))"
433
+ raised_for="(alarm is raised for ${non_clear_duration_txt})"
434
fi
435
436
elif [ "${old_status}" = "CRITICAL" -a "${status}" = "WARNING" ]
@@ -414,7 +438,7 @@ then
438
severity="Demoted to ${status}"
439
if [ $non_clear_duration -gt $duration ]
440
then
417
- raised_for="(has issues for $(duration4human ${non_clear_duration}))"
441
+ raised_for="(alarm is raised for ${non_clear_duration_txt})"
442
fi
443
444
else
@@ -432,15 +456,15 @@ raised_for_html=
456
# send the slack notification
457
458
# slack aggregates posts from the same username
435
-# so we use "${hostname} ${status}" as the bot username, to make them diff
459
+# so we use "${host} ${status}" as the bot username, to make them diff
460
437
-send_slack "${SLACK_WEBHOOK_URL}" "${to_slack}" "${when}" "${hostname} ${status}" "${image}" "${chart} (${family})"
461
+send_slack "${SLACK_WEBHOOK_URL}" "${to_slack}" "${when}" "${host} ${status}" "${image}" "${chart} (${family})"
462
SENT_SLACK=$?
463
464
# -----------------------------------------------------------------------------
465
# send the pushover notification
466
443
-send_pushover "${PUSHOVER_APP_TOKEN}" "${to_pushover}" "${when}" "${goto_url}" "${status}" "${hostname} ${status_message} - ${name//_/ } - ${chart}" "
467
+send_pushover "${PUSHOVER_APP_TOKEN}" "${to_pushover}" "${when}" "${goto_url}" "${status}" "${host} ${status_message} - ${name//_/ } - ${chart}" "
468
<font color=\"${color}\"><b>${alarm}</b></font>${info_html}<br/>
469
<small><b>${chart}</b><br/>Chart<br/> </small>
470
<small><b>${family}</b><br/>Family<br/> </small>
@@ -457,7 +481,7 @@ SENT_PUSHOVER=$?
481
482
send_email <<EOF
483
To: ${to_email}
460
-Subject: ${hostname} ${status_message} - ${name//_/ } - ${chart}
484
+Subject: ${host} ${status_message} - ${name//_/ } - ${chart}
485
Content-Type: text/html
486
487
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
@@ -478,7 +502,7 @@ Content-Type: text/html
502
</tr>
503
<tr>
504
<td bgcolor="${color}" style="font-size: 16px; vertical-align: top; font-weight: 400; text-align: center; margin: 0; padding: 10px; color: #ffffff; background: ${color} !important; border: 1px solid ${color}; border-top-color: ${color};" align="center" valign="top">
481
- <h1 style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-weight: 400; margin: 0;">${hostname} ${status_message}</h1>
505
+ <h1 style="font-family: 'Helvetica Neue', 'Helvetica', Helvetica, Arial, sans-serif; font-weight: 400; margin: 0;">${host} ${status_message}</h1>
506
</td>
507
</tr>
508
<tr>
web/goto-host-from-alarm.html
+14
-1
@@ -23,6 +23,10 @@
23
host: null,
24
chart: null,
25
family: null,
26
+ alarm: null,
27
+ alarm_unique_id: 0,
28
+ alarm_id: 0,
29
+ alarm_event_id: 0,
30
hasProperty: function(property) {
31
return typeof this[property] !== 'undefined';
32
}
@@ -40,7 +44,16 @@
44
}
45
46
function netdataURL(url) {
43
- return url + '#top;show_alarms=true;chart=' + urlOptions.chart + ';family=' + urlOptions.family;
47
+ return url + '#top'
48
+ + ';nowelcome=1'
49
+ + ';show_alarms=1'
50
+ + ';chart=' + urlOptions.chart.toString()
51
+ + ';family=' + urlOptions.family.toString()
52
+ + ';alarm=' + urlOptions.alarm.toString()
53
+ + ';alarm_unique_id=' + urlOptions.alarm_unique_id.toString()
54
+ + ';alarm_id=' + urlOptions.alarm_id.toString()
55
+ + ';alarm_event_id=' + urlOptions.alarm_event_id.toString()
56
+ ;
57
}
58
59
var gotoServerValidateRemaining = 0;
web/index.html
+23
-8
@@ -408,10 +408,14 @@
408
pan_and_zoom: false,
409
after: 0,
410
before: 0,
411
- nowelcome: 0,
412
- show_alarms: 0,
411
+ nowelcome: false,
412
+ show_alarms: false,
413
chart: null,
414
family: null,
415
+ alarm: null,
416
+ alarm_unique_id: 0,
417
+ alarm_id: 0,
418
+ alarm_event_id: 0,
419
hasProperty: function(property) {
420
// console.log('checking property ' + property + ' of type ' + typeof(this[property]));
421
return typeof this[property] !== 'undefined';
@@ -461,8 +465,21 @@
465
}
466
}
467
464
- if(urlOptions.before > 0 && urlOptions.after > 0)
468
+ var booleans = [ 'nowelcome', 'show_alarms', 'pan_and_zoom' ];
469
+ len = booleans.length;
470
+ while(len--) {
471
+ if(urlOptions[booleans[len]] === 'true' || urlOptions[booleans[len]] === true || urlOptions[booleans[len]] === '1' || urlOptions[booleans[len]] === 1)
472
+ urlOptions[booleans[len]] = true;
473
+ else
474
+ urlOptions[booleans[len]] = false;
475
+ }
476
+
477
+ if(urlOptions.before > 0 && urlOptions.after > 0) {
478
urlOptions.pan_and_zoom = true;
479
+ urlOptions.nowelcome = true;
480
+ }
481
+ else
482
+ urlOptions.pan_and_zoom = false;
483
484
// console.log(urlOptions);
485
}
@@ -3030,10 +3047,8 @@ function finalizePage() {
3047
// the Dom elements are initially zero-sized
3048
NETDATA.parseDom();
3049
3033
- if(urlOptions.pan_and_zoom === true) {
3034
- urlOptions.nowelcome = true;
3050
+ if(urlOptions.pan_and_zoom === true)
3051
NETDATA.globalPanAndZoom.setMaster(NETDATA.options.targets[0], urlOptions.after, urlOptions.before);
3036
- }
3052
3053
// ------------------------------------------------------------------------
3054
// https://github.com/viralpatel/jquery.shorten/blob/master/src/jquery.shorten.js
@@ -3299,7 +3314,7 @@ function finalizePage() {
3314
});
3315
3316
if(isdemo()) {
3302
- if(!urlOptions.nowelcome) {
3317
+ if(urlOptions.nowelcome !== true) {
3318
setTimeout(function() {
3319
$('#welcomeModal').modal();
3320
}, 1000);
@@ -3319,7 +3334,7 @@ function finalizePage() {
3334
}
3335
else notifyForUpdate();
3336
3322
- if(urlOptions.show_alarms === 'true')
3337
+ if(urlOptions.show_alarms === true)
3338
setTimeout(function() { $('#alarmsModal').modal('show'); }, 1000);
3339
}
3340