mirror of
https://github.com/metrico/qryn.git
synced 2025-03-14 10:07:18 +00:00
alerting
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1,3 @@
|
||||
node_modules
|
||||
/docker-env/
|
||||
/docker-env/
|
||||
|
7
cloki.js
7
cloki.js
@ -51,7 +51,8 @@ this.scanClickhouse = DATABASE.scanClickhouse;
|
||||
|
||||
/* Fastify Helper */
|
||||
const fastify = require('fastify')({
|
||||
logger: false,
|
||||
|
||||
logger: true,
|
||||
bodyLimit: parseInt(process.env.FASTIFY_BODYLIMIT) || 5242880,
|
||||
requestTimeout: parseInt(process.env.FASTIFY_REQUESTTIMEOUT) || 0,
|
||||
maxRequestsPerSocket: parseInt(process.env.FASTIFY_MAXREQUESTS) || 0
|
||||
@ -202,8 +203,8 @@ fastify.post('/config/v1/alerts', {
|
||||
}
|
||||
}
|
||||
})
|
||||
fastify.get('/config/v1/alerts', require('./lib/handlers/alerts/get_rules').bind(this))
|
||||
fastify.get('/config/v1/alerts/:name', require('./lib/handlers/alerts/get_rule').bind(this))
|
||||
fastify.get('/api/prom/rules', require('./lib/handlers/alerts/get_rules').bind(this))
|
||||
fastify.get('/api/prom/rules/:ns/:rule', require('./lib/handlers/alerts/get_rule').bind(this))
|
||||
fastify.put('/config/v1/alerts/:name', {
|
||||
handler: require('./lib/handlers/alerts/put_rule').putAlert.bind(this),
|
||||
schema: {
|
||||
|
@ -564,8 +564,6 @@
|
||||
enabled = true
|
||||
host = smtp.gmail.com:465
|
||||
user = akvlad90@gmail.com
|
||||
# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;"""
|
||||
password = ciprydyxoxdyuuow
|
||||
;cert_file =
|
||||
;key_file =
|
||||
;skip_verify = false
|
||||
|
@ -2,22 +2,96 @@ const transpiler = require('../../parser/transpiler')
|
||||
const { dropAlertViews, createAlertViews, incAlertMark, dropOutdatedParts, getLastAlert, getAlertRules } = require('./clickhouse')
|
||||
const { samplesTableName } = require('../utils')
|
||||
|
||||
module.exports.addAlert = async (name, request, labels) => {
|
||||
const watcher = new AlertWatcher(name, request, labels)
|
||||
await watcher.run()
|
||||
alerts[name] = watcher
|
||||
module.exports.setGroup = async (namespace, group) => {
|
||||
const rulesToAdd = alerts[namespace] && alerts[namespace][group.name]
|
||||
? group.rules.filter(r => !alerts[namespace][group.name][r.alert])
|
||||
: group.rules
|
||||
const rulesToDelete = alerts[namespace] && alerts[namespace][group.name]
|
||||
? Object.keys(alerts[namespace][group.name])
|
||||
.filter(k => !group.alerts.some(r => r.alert === k))
|
||||
.map(k => alerts[namespace][group.name][k])
|
||||
: []
|
||||
const rulesToUpdate = alerts[namespace] && alerts[namespace][group.name]
|
||||
? group.rules
|
||||
.filter(r => alerts[namespace][group.name][r.alert])
|
||||
.map(r => [alerts[namespace][group.name][r.alert], r])
|
||||
: []
|
||||
for (const rul of rulesToAdd) {
|
||||
const w = new AlertWatcher(rul)
|
||||
await w.run()
|
||||
rul._watcher = w
|
||||
}
|
||||
for (const rul of rulesToDelete) {
|
||||
const w = rul._watcher
|
||||
await w.drop()
|
||||
}
|
||||
for (const [_old, _new] of rulesToUpdate) {
|
||||
const w = _old._watcher
|
||||
await w.edit(_new)
|
||||
_new._watcher = w
|
||||
}
|
||||
alerts[namespace] = alerts[namespace] || {}
|
||||
alerts[namespace][group.name] = group
|
||||
}
|
||||
|
||||
module.exports.editAlert = async (name, request, labels) => {
|
||||
if (!alerts[name]) {
|
||||
await module.exports.addAlert(name, request, labels)
|
||||
/**
|
||||
*
|
||||
* @param ns {string}
|
||||
* @returns {Object<string, Object<string, {name: string, interval: string, rules: Object}>> } namespace
|
||||
*/
|
||||
module.exports.getAll = () => {
|
||||
return alerts
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ns {string}
|
||||
* @returns {Object<string, {name: string, interval: string, rules: Object}>} namespace
|
||||
*/
|
||||
module.exports.getNs = (ns) => {
|
||||
return alerts[ns]
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ns {string}
|
||||
* @param grp {string}
|
||||
* @returns {{name: string, interval: string, rules: Object} | undefined} group
|
||||
*/
|
||||
module.exports.getGroup = (ns, grp) => {
|
||||
return alerts[ns] && alerts[ns][grp] ? alerts[ns][grp] : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param ns {string}
|
||||
* @param grp {string}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
module.exports.dropGroup = async (ns, grp) => {
|
||||
if (!alerts[ns] || !alerts[ns][grp]) {
|
||||
return
|
||||
}
|
||||
await alerts[name].edit(request, labels)
|
||||
for (const rul of Object.values(alerts[ns][grp].rules)) {
|
||||
const w = rul._watcher
|
||||
await w.drop()
|
||||
}
|
||||
delete alerts[ns][grp]
|
||||
}
|
||||
|
||||
module.exports.dropAlert = async (name) => {
|
||||
alerts[name] && await alerts[name].drop()
|
||||
/**
|
||||
*
|
||||
* @param ns {string}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
module.exports.dropNs = async (ns) => {
|
||||
if (!alerts[ns]) {
|
||||
return
|
||||
}
|
||||
for (const grp of Object.keys(alerts[ns])) {
|
||||
await module.exports.dropGroup(ns, grp)
|
||||
}
|
||||
delete alerts[ns]
|
||||
}
|
||||
|
||||
module.exports.stop = () => {
|
||||
@ -35,7 +109,7 @@ module.exports.startAlerting = async () => {
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Object<string, AlertWatcher>}
|
||||
* @type {Object<string, Object<string, {name: string, interval: string, rules: Object}>>}
|
||||
*/
|
||||
let alerts = {}
|
||||
|
||||
@ -62,6 +136,10 @@ class AlertWatcher {
|
||||
this.labels = labels
|
||||
}
|
||||
|
||||
async update() {
|
||||
|
||||
}
|
||||
|
||||
async drop () {
|
||||
this.stop()
|
||||
await this._dropViews()
|
||||
|
@ -1006,10 +1006,12 @@ module.exports.deleteAlertRule = async (name) => {
|
||||
*/
|
||||
module.exports.dropAlertViews = async (name) => {
|
||||
const fp = UTILS.fingerPrint('alert_rule' + name)
|
||||
console.log(`DROP VIEW IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}`)
|
||||
console.log(`DROP TABLE IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark`)
|
||||
await axios.post(getClickhouseUrl(),
|
||||
`DROP VIEW IF EXISTS _alert_view_${fp}`)
|
||||
`DROP VIEW IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}`)
|
||||
await axios.post(getClickhouseUrl(),
|
||||
`DROP TABLE IF EXISTS _alert_view_${fp}_mark`)
|
||||
`DROP TABLE IF EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark`)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1026,7 +1028,9 @@ module.exports.createAlertViews = async (name, request) => {
|
||||
'mark'
|
||||
]
|
||||
)
|
||||
request.withs.str_sel.inline = true
|
||||
const strRequest = request.toString()
|
||||
console.log(strRequest)
|
||||
await axios.post(getClickhouseUrl(),
|
||||
`CREATE TABLE IF NOT EXISTS ${DATABASE_NAME()}._alert_view_${fp}_mark (id UInt8 default 0,mark UInt64) ` +
|
||||
'ENGINE ReplacingMergeTree(mark) ORDER BY id')
|
||||
|
@ -1,11 +1,32 @@
|
||||
const { CLokiNotFound } = require('../errors')
|
||||
const clickhouse = require('../../db/clickhouse')
|
||||
const yaml = require('yaml')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
const name = req.params.name
|
||||
/*const name = req.params.name
|
||||
const rule = await clickhouse.getAlertRule(name)
|
||||
if (!rule) {
|
||||
throw new CLokiNotFound(`Rule with name '${name}' not found`)
|
||||
}
|
||||
res.send(rule)
|
||||
res.send(rule)*/
|
||||
const result = {
|
||||
fake: [
|
||||
{
|
||||
name: 'fake',
|
||||
interval: '1m',
|
||||
rules: [{
|
||||
alert: 'fake',
|
||||
expr: 'rate({test_id="_TEST_"}[1m])',
|
||||
for: '1m',
|
||||
annotations:
|
||||
{
|
||||
a1: 'fake'
|
||||
},
|
||||
labels: { l1: 'fake' }
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
console.log(yaml.stringify(result.fake[0]))
|
||||
res.header('Content-Type', 'yaml').send(yaml.stringify(result.fake[0]))
|
||||
}
|
||||
|
@ -1,19 +1,28 @@
|
||||
const { CLokiBadRequest } = require('../errors')
|
||||
const clickhouse = require('../../db/clickhouse')
|
||||
const yaml = require('yaml')
|
||||
|
||||
module.exports = async (req, res) => {
|
||||
const limit = req.query.limit ? parseInt(req.query.limit) : 100
|
||||
const offset = req.query.limit ? parseInt(req.query.offset) : 0
|
||||
if (isNaN(limit)) {
|
||||
throw new CLokiBadRequest('limit is not a number')
|
||||
const result = {
|
||||
fake: [
|
||||
{
|
||||
name: 'fake',
|
||||
interval: '1m',
|
||||
rules: [{
|
||||
alert: 'fake',
|
||||
expr: 'rate({test_id="_TEST_"}[1m])',
|
||||
for: '1m',
|
||||
annotations:
|
||||
{
|
||||
a1: 'fake'
|
||||
},
|
||||
labels: { l1: 'fake' }
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
if (isNaN(offset)) {
|
||||
throw new CLokiBadRequest('offset is not a number')
|
||||
}
|
||||
const result = await clickhouse.getAlertRules(limit, offset)
|
||||
const count = await clickhouse.getAlertRulesCount()
|
||||
res.send({
|
||||
alerts: result,
|
||||
count: count
|
||||
})
|
||||
//const result = await clickhouse.getAlertRules(limit, offset)
|
||||
//const count = await clickhouse.getAlertRulesCount()
|
||||
console.log(yaml.stringify(result))
|
||||
res.header('Content-Type', 'yaml').send(yaml.stringify(result))
|
||||
}
|
||||
|
7
package-lock.json
generated
7
package-lock.json
generated
@ -2054,7 +2054,7 @@
|
||||
}
|
||||
},
|
||||
"clickhouse-sql": {
|
||||
"version": "git+https://github.com/metrico/node-clickhouse-sql.git#f88f606ca40dbaa5195809289eab9fa33e43c6c5",
|
||||
"version": "git+https://github.com/metrico/node-clickhouse-sql.git#f81ce8a5e5885e010dbecbfb64866024661ef03b",
|
||||
"from": "git+https://github.com/metrico/node-clickhouse-sql.git"
|
||||
},
|
||||
"cliui": {
|
||||
@ -9088,6 +9088,11 @@
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "16.2.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
|
||||
|
@ -50,7 +50,8 @@
|
||||
"scramjet": "^4.36.1",
|
||||
"short-hash": "^1.0.0",
|
||||
"snappyjs": "^0.6.1",
|
||||
"ws": "^8.3.0"
|
||||
"ws": "^8.3.0",
|
||||
"yaml": "^1.10.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"casual": "^1.6.2",
|
||||
|
Reference in New Issue
Block a user