Skip to content

Commit 7e0935e

Browse files
committed
feat: Make it work
1 parent 40184e4 commit 7e0935e

8 files changed

Lines changed: 94 additions & 17 deletions

File tree

src/alert.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ class Alert {
66
constructor (config) {
77
this.config = config
88
}
9+
10+
setID (id) {
11+
this.id = id
12+
return this
13+
}
14+
915
at (time) {
1016
this.timeField = moment(time).format('[at] ' + this.config.dateFormat)
1117
return this
@@ -42,4 +48,4 @@ class Alert {
4248
}
4349
}
4450

45-
module.exporrts = Alert
51+
module.exports = Alert

src/group.js

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,66 @@
11
'use strict'
22

33
const Alert = require('./alert')
4+
const crypto = require('crypto')
5+
const shortHash = (str) => {
6+
let hash = crypto.createHash('sha512').update(str).digest('hex')
7+
return hash.substr(parseInt(hash.substr(0, 1), 16), 16)
8+
}
49

510
class Group {
6-
constructor (main) {
11+
constructor (main, config, prevAlerts) {
712
this.main = main
13+
this.config = config
14+
this.alerts = {}
15+
this.prevAlerts = prevAlerts || []
816
}
917
name (name) {
1018
this.name = name
19+
this.id = shortHash(name)
1120
return this
1221
}
22+
attachAlert (alert) {
23+
this.alerts[alert.id] = alert
24+
}
1325
alert (id) {
14-
const alert = new Alert(id)
26+
const alert = new Alert(this.config).setID(id)
1527
this.attachAlert(alert)
28+
return alert
29+
}
30+
setAutoClear (v) {
31+
this.autoClear = v
32+
}
33+
process () {
34+
let alerts = Object.keys(this.alerts).map(k => this.alerts[k])
35+
let prevAlerts = this.prevAlerts
36+
let clearable = prevAlerts.filter(pa => !alerts.filter(a => a.id === pa.id).length)
37+
let newPrevAlerts = alerts.filter(a => a.type !== 'clear') // don't keep clear events arround
38+
let sendNotify = alerts.filter(a => {
39+
if (!prevAlerts.filter(pa => pa.id === a.id).length && a.type !== 'clear') { // new non-clear
40+
return true
41+
}
42+
43+
if (prevAlerts.filter(pa => pa.id === a.id).length && a.type === 'clear') { // old clear
44+
return true
45+
}
46+
47+
return false
48+
})
49+
if (this.autoClear) {
50+
sendNotify = sendNotify.concat(clearable.map(a =>
51+
this.alert(a.id).type('clear').title('Cleared alert ' + JSON.stringify(a.title)).body('Alert for group ' + JSON.stringify(this.name) + ' has been cleared')
52+
))
53+
} else {
54+
newPrevAlerts = newPrevAlerts.concat(clearable) // keep clearable events arround
55+
}
56+
57+
sendNotify.forEach(alert => {
58+
this.main.notifies.forEach(notify => {
59+
notify.notify(alert)
60+
})
61+
})
62+
63+
return newPrevAlerts
1664
}
1765
}
1866

src/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict'
22

3+
require('colors')
4+
35
const Notifies = {
46
console: require('./notify/console'),
57
notifySend: require('./notify/notifySend')
@@ -13,8 +15,9 @@ const Sources = {
1315
class SysadminNotifier {
1416
constructor (config) {
1517
const globalConf = config.global || {}
16-
this.notify = []
18+
this.notifies = []
1719
this.sources = []
20+
this.prevAlerts = {}
1821
for (const p in config) { // eslint-disable-line guard-for-in
1922
switch (true) {
2023
case p === 'global':
@@ -25,7 +28,7 @@ class SysadminNotifier {
2528
throw new TypeError('Unknown notification system ' + name)
2629
}
2730
const Notify = Notifies[name]
28-
this.notify.push(new Notify(this, Object.assign(globalConf, config[p])))
31+
this.notifies.push(new Notify(this, Object.assign(Object.assign({}, globalConf), config[p])))
2932
break
3033
}
3134
case p.startsWith('source.'): {

src/notify/console.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
const Notify = require('../notify')
66

77
const typeColor = {
8-
ciritical: 'red',
8+
critical: 'red',
99
warning: 'yellow',
1010
clear: 'green'
1111
}
@@ -15,7 +15,7 @@ class Console extends Notify {
1515
const color = typeColor[alert.type]
1616
console.log(`[${alert.timeField ? (alert.timeField.toUpperCase() + '/') : ''}${alert.type.toUpperCase()}] ${alert.title}`[color].bold)
1717
if (alert.body) {
18-
alert.body.split('\n').map(s => (' ' + s)[color]).forEach(console.log)
18+
alert.body.split('\n').map(s => (' ' + s)[color]).forEach((l) => console.log(l))
1919
}
2020
}
2121
}

src/notify/notifySend.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const Notify = require('../notify')
44
const cp = require('child_process')
55

66
const typeIcon = {
7-
ciritical: 'dialog-error',
7+
critical: 'dialog-error',
88
warning: 'dialog-warning',
99
clear: 'flag-green'
1010
}

src/source.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
'use strict'
22

3+
const Group = require('./group')
4+
35
class Source {
46
constructor (main, config) {
57
this.main = main
68
this.config = config
9+
this.intv = 0
10+
}
11+
async doCheck () {
12+
const groups = await this.check()
13+
groups.forEach(g => {
14+
this.main.prevAlerts[g.id] = g.process()
15+
})
16+
this.prevGroups = groups
717
}
818
async start () {
9-
// TODO: add
19+
await this.doCheck()
20+
this.intv = setInterval(() => this.doCheck(), this.config.interval)
1021
}
1122
async stop () {
12-
// TODO: add
23+
clearInterval(this.intv)
24+
}
25+
group (name) {
26+
const g = new Group(this.main, this.config).name(name)
27+
g.prevAlerts = this.main.prevAlerts[g.id] || []
28+
return g
1329
}
1430
}
1531

src/source/netdata.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@ class Netdata extends Source {
1616

1717
}
1818
async check () {
19-
return this.config.hosts.map(host => this.checkHost(host))
19+
return Promise.all(this.config.hosts.map(host => this.checkHost(host)))
2020
}
2121
async checkHost (host) {
22-
const g = this.main.group('netdata host ' + host)
22+
const g = this.group('netdata host ' + host)
2323
try {
24+
g.setAutoClear(true)
2425
let res = await fetch('http://' + host + ':19999/api/v1/alarms?active')
2526
res = await res.json()
26-
console.log(res)
27+
for (const alarmID in res.alarms) { // eslint-disable-line guard-for-in
28+
const alarm = res.alarams[alarmID]
29+
console.log(alarm)
30+
}
2731
} catch (e) {
2832
g.alert('fetch_error').critical().title('Could not fetch netdata alerts for ' + host).body('Please check network connectivity and host uptime').since(Date.now())
2933
}

src/source/uptimerobot.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ const stateMap = {
1212
}
1313

1414
const stateTypeMap = {
15-
0: 'warn',
16-
2: 'critical',
17-
9: 'clear'
15+
0: 'warning',
16+
2: 'clear',
17+
9: 'critical'
1818
}
1919

2020
class UptimeRobot extends Source {
@@ -32,7 +32,7 @@ class UptimeRobot extends Source {
3232
r.last_status_change = Date.parse(r.log[0].datetime)
3333
return r
3434
})
35-
let g = this.main.group('UptimeRobot')
35+
let g = this.group('UptimeRobot')
3636
res.forEach(monitor => {
3737
let alert = g.alert(monitor.id).type(monitor.stateType)
3838
.since(monitor.last_status_change)

0 commit comments

Comments
 (0)