qryn/cloki.js

215 lines
6.3 KiB
JavaScript
Raw Normal View History

2021-08-20 21:31:05 +02:00
#!/usr/bin/env node
2018-12-26 15:06:39 +01:00
/*
* Loki API to Clickhouse Gateway
2021-01-22 23:23:39 +01:00
* (C) 2018-2021 QXIP BV
2018-12-26 15:06:39 +01:00
*/
2021-11-08 11:43:59 -06:00
this.debug = process.env.DEBUG || false
2021-11-09 12:10:20 -06:00
// const debug = this.debug
2018-12-27 13:26:15 +01:00
2021-11-08 11:43:59 -06:00
this.readonly = process.env.READONLY || false
this.http_user = process.env.CLOKI_LOGIN || false
this.http_password = process.env.CLOKI_PASSWORD || false
2018-12-26 15:06:39 +01:00
2021-11-08 11:43:59 -06:00
require('./plugins/engine')
2021-10-19 16:18:25 +03:00
2021-11-08 11:43:59 -06:00
const DATABASE = require('./lib/db/clickhouse')
const UTILS = require('./lib/utils')
2018-12-26 15:06:39 +01:00
2018-12-27 03:22:06 +01:00
/* ProtoBuf Helper */
2021-11-08 11:43:59 -06:00
const fs = require('fs')
const protoBuff = require('protocol-buffers')
2021-12-13 11:31:49 +02:00
const { startAlerting, stop } = require('./lib/db/alerting')
2021-11-08 11:43:59 -06:00
const messages = protoBuff(fs.readFileSync('lib/loki.proto'))
2021-12-11 23:12:37 +02:00
const yaml = require('yaml')
2018-12-27 03:22:06 +01:00
2018-12-26 15:06:39 +01:00
/* Fingerprinting */
2021-11-08 11:43:59 -06:00
this.fingerPrint = UTILS.fingerPrint
this.toJSON = UTILS.toJSON
2018-12-26 16:55:13 +01:00
2021-06-15 00:28:51 +02:00
/* Database this.bulk Helpers */
2021-11-08 11:43:59 -06:00
this.bulk = DATABASE.cache.bulk // samples
this.bulk_labels = DATABASE.cache.bulk_labels // labels
this.labels = DATABASE.cache.labels // in-memory labels
2018-12-26 15:06:39 +01:00
/* Function Helpers */
2021-11-08 11:43:59 -06:00
this.labelParser = UTILS.labelParser
2018-12-28 02:12:45 +01:00
2021-11-08 11:43:59 -06:00
const init = DATABASE.init
this.reloadFingerprints = DATABASE.reloadFingerprints
this.scanFingerprints = DATABASE.scanFingerprints
this.instantQueryScan = DATABASE.instantQueryScan
2021-11-08 11:43:59 -06:00
this.scanMetricFingerprints = DATABASE.scanMetricFingerprints
2021-11-30 13:09:49 +02:00
this.scanClickhouse = DATABASE.scanClickhouse;
(async () => {
if (!this.readonly) await init(process.env.CLICKHOUSE_DB || 'cloki')
await startAlerting()
})().catch((err) => {
2021-11-25 20:46:06 +02:00
console.log(err)
process.exit(1)
})
2018-12-26 15:06:39 +01:00
/* Fastify Helper */
2021-11-08 11:43:59 -06:00
const fastify = require('fastify')({
2021-12-09 16:24:12 +02:00
2021-12-13 10:17:12 +02:00
logger: false,
2021-11-29 13:57:54 +01:00
bodyLimit: parseInt(process.env.FASTIFY_BODYLIMIT) || 5242880,
2021-12-09 09:11:20 +02:00
requestTimeout: parseInt(process.env.FASTIFY_REQUESTTIMEOUT) || 0,
2021-11-29 13:57:54 +01:00
maxRequestsPerSocket: parseInt(process.env.FASTIFY_MAXREQUESTS) || 0
2021-11-08 11:43:59 -06:00
})
2018-12-26 15:06:39 +01:00
2021-11-08 11:43:59 -06:00
fastify.register(require('fastify-url-data'))
fastify.register(require('fastify-websocket'))
2021-06-26 21:50:56 +03:00
fastify.after((err) => {
2021-11-08 11:43:59 -06:00
if (err) throw err
})
2018-12-27 01:02:51 +01:00
/* Enable Simple Authentication */
2021-10-31 19:46:46 +01:00
if (this.http_user && this.http_password) {
2021-11-08 11:43:59 -06:00
function checkAuth (username, password, req, reply, done) {
if (username === this.http_user && password === this.http_password) {
done()
} else {
done(new Error('Unauthorized!: Wrong username/password.'))
2021-10-31 19:46:46 +01:00
}
2021-11-08 11:43:59 -06:00
}
const validate = checkAuth.bind(this)
fastify.register(require('fastify-basic-auth'), {
validate
})
fastify.after(() => {
fastify.addHook('preHandler', fastify.basicAuth)
})
}
2021-11-08 11:43:59 -06:00
fastify.addContentTypeParser('text/plain', {
parseAs: 'string'
}, function (req, body, done) {
try {
const json = JSON.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
2018-12-26 15:06:39 +01:00
2021-12-11 23:12:37 +02:00
fastify.addContentTypeParser('application/yaml', {
parseAs: 'string'
}, function (req, body, done) {
try {
const json = yaml.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
2021-11-19 10:55:25 +02:00
try {
2021-11-20 14:55:10 -06:00
const snappy = require('snappyjs')
2021-11-18 16:19:41 +02:00
/* Protobuf Handler */
fastify.addContentTypeParser('application/x-protobuf', { parseAs: 'buffer' },
async function (req, body, done) {
let _data = await snappy.uncompress(body)
_data = messages.PushRequest.decode(_data)
_data.streams = _data.streams.map(s => ({
...s,
entries: s.entries.map(e => {
const millis = Math.floor(e.timestamp.nanos / 1000000)
return {
...e,
timestamp: e.timestamp.seconds * 1000 + millis
}
})
}))
return _data.streams
})
2021-11-19 10:55:25 +02:00
} catch (e) {
console.log(e)
console.log('Protobuf ingesting is unsupported')
2021-11-18 16:19:41 +02:00
}
2018-12-29 02:30:14 +01:00
2021-11-12 18:27:24 +02:00
fastify.addContentTypeParser('*', function (request, payload, done) {
if (request.headers['content-type']) {
done(payload)
return
}
let data = ''
payload.on('data', chunk => { data += chunk })
payload.on('end', () => {
done(null, data)
})
})
2021-06-15 00:28:51 +02:00
/* 404 Handler */
2021-11-09 12:10:20 -06:00
const handler404 = require('./lib/handlers/404.js').bind(this)
fastify.setNotFoundHandler(handler404)
2021-11-17 12:42:30 +02:00
fastify.setErrorHandler(require('./lib/handlers/errors').handler.bind(this))
2018-12-29 02:30:14 +01:00
2021-06-15 00:28:51 +02:00
/* Hello cloki test API */
2021-11-09 12:10:20 -06:00
const handlerHello = require('./lib/handlers/ready').bind(this)
fastify.get('/hello', handlerHello)
fastify.get('/ready', handlerHello)
2021-02-04 21:42:15 +01:00
2021-06-15 00:28:51 +02:00
/* Write Handler */
2021-11-09 12:10:20 -06:00
const handlerPush = require('./lib/handlers/push.js').bind(this)
fastify.post('/loki/api/v1/push', handlerPush)
2020-11-23 15:26:14 +01:00
/* Telegraf HTTP Bulk handler */
2021-11-09 12:10:20 -06:00
const handlerTelegraf = require('./lib/handlers/telegraf.js').bind(this)
fastify.post('/telegraf', handlerTelegraf)
2018-12-26 15:06:39 +01:00
/* Query Handler */
2021-11-09 12:10:20 -06:00
const handlerQueryRange = require('./lib/handlers/query_range.js').bind(this)
fastify.get('/loki/api/v1/query_range', handlerQueryRange)
2018-12-26 15:06:39 +01:00
/* Label Handlers */
/* Label Value Handler via query (test) */
2021-11-09 12:10:20 -06:00
const handlerQuery = require('./lib/handlers/query.js').bind(this)
fastify.get('/loki/api/v1/query', handlerQuery)
2021-06-15 00:28:51 +02:00
/* Label Handlers */
2021-11-09 12:10:20 -06:00
const handlerLabel = require('./lib/handlers/label.js').bind(this)
fastify.get('/loki/api/v1/label', handlerLabel)
fastify.get('/loki/api/v1/labels', handlerLabel)
2018-12-26 15:06:39 +01:00
/* Label Value Handler */
2021-11-09 12:10:20 -06:00
const handlerLabelValues = require('./lib/handlers/label_values.js').bind(this)
fastify.get('/loki/api/v1/label/:name/values', handlerLabelValues)
2018-12-26 15:06:39 +01:00
/* Series Placeholder - we do not track this as of yet */
2021-11-09 12:10:20 -06:00
const handlerSeries = require('./lib/handlers/series.js').bind(this)
fastify.get('/loki/api/v1/series', handlerSeries)
2021-11-08 11:43:59 -06:00
fastify.get('/loki/api/v1/tail', { websocket: true }, require('./lib/handlers/tail').bind(this))
2021-11-01 11:36:48 +02:00
2021-12-13 11:31:49 +02:00
// ALERT MANAGER
2021-12-09 16:24:12 +02:00
fastify.get('/api/prom/rules', require('./lib/handlers/alerts/get_rules').bind(this))
2021-12-11 23:12:37 +02:00
fastify.get('/api/prom/rules/:ns/:group', require('./lib/handlers/alerts/get_group').bind(this))
2021-12-13 11:31:49 +02:00
fastify.post('/api/prom/rules/:ns', require('./lib/handlers/alerts/post_group').bind(this))
2021-12-11 23:12:37 +02:00
fastify.delete('/api/prom/rules/:ns/:group', require('./lib/handlers/alerts/del_group').bind(this))
fastify.delete('/api/prom/rules/:ns', require('./lib/handlers/alerts/del_ns').bind(this))
2021-12-13 10:17:12 +02:00
fastify.get('/prometheus/api/v1/rules', require('./lib/handlers/alerts/prom_get_rules').bind(this))
2021-11-17 12:42:30 +02:00
2018-12-27 02:26:49 +01:00
// Run API Service
fastify.listen(
2021-11-08 11:43:59 -06:00
process.env.PORT || 3100,
process.env.HOST || '0.0.0.0',
(err, address) => {
if (err) throw err
console.log('cLoki API up')
fastify.log.info(`cloki API listening on ${address}`)
}
)
2021-06-26 21:50:56 +03:00
module.exports.stop = () => {
2021-11-08 11:43:59 -06:00
fastify.close()
DATABASE.stop()
2021-12-20 12:05:44 +02:00
require('./parser/transpiler').stop()
2021-12-13 11:31:49 +02:00
stop()
2021-11-08 11:43:59 -06:00
}