Skip to content

Commit

Permalink
Promql to LogQL emulation (#190)
Browse files Browse the repository at this point in the history
* promql handler prototype

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update qryn.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* Create prom_query.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update qryn.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* update logql2promql library

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update qryn.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update prom_query.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* resync

* Update qryn.js

Signed-off-by: Lorenzo Mangani <[email protected]>

* start/end s -> ns conv

* nodejs "standard" standard cleanup

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* labels and values prom support

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

* Update package.json

Signed-off-by: Lorenzo Mangani <[email protected]>

Signed-off-by: Lorenzo Mangani <[email protected]>
Co-authored-by: akvlad <[email protected]>
  • Loading branch information
lmangani and akvlad authored Aug 21, 2022
1 parent ccc4493 commit 4c076b7
Show file tree
Hide file tree
Showing 8 changed files with 240 additions and 1 deletion.
10 changes: 10 additions & 0 deletions lib/handlers/prom_default.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* Emulated PromQL Query Handler */

async function handler (req, res) {
req.log.debug('GET /api/v1/*')
const resp = {"status": "success", "data": {}};
res.send(resp)
return
}

module.exports = handler
35 changes: 35 additions & 0 deletions lib/handlers/prom_query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* Emulated PromQL Query Handler */

const { p2l } = require('@qxip/promql2logql');
const empty = '{"status" : "success", "data" : {"resultType" : "scalar", "result" : []}}'; // to be removed

async function handler (req, res) {
req.log.debug('GET /loki/api/v1/query')
const resp = { streams: [] }
if (!req.query.query) {
res.send(resp)
return
}
/* remove newlines */
req.query.query = req.query.query.replace(/\n/g, ' ')
/* transpile to logql */
try {
req.query.query = p2l(req.query.query);
} catch(e) {
req.log.error({ err })
res.send(empty)
}
/* scan fingerprints */
/* TODO: handle time tag + direction + limit to govern the query output */
try {
await this.instantQueryScan(
req.query,
{ res: res.raw }
)
} catch (err) {
req.log.error({ err })
res.send(empty)
}
}

module.exports = handler
45 changes: 45 additions & 0 deletions lib/handlers/prom_query_range.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/* Emulated PromQL Query Handler */
/*
Converts PromQL to LogQL queries, accepts the following parameters in the query-string:
query: a PromQL query
limit: max number of entries to return
start: the start time for the query, as a nanosecond Unix epoch (nanoseconds since 1970)
end: the end time for the query, as a nanosecond Unix epoch (nanoseconds since 1970)
direction: forward or backward, useful when specifying a limit
regexp: a regex to filter the returned results, will eventually be rolled into the query language
*/

const { p2l } = require('@qxip/promql2logql')

async function handler (req, res) {
req.log.debug('GET /api/v1/query_range')
const resp = { streams: [] }
if (!req.query.query) {
res.send(resp)
return
}
/* remove newlines */
req.query.query = req.query.query.replace(/\n/g, ' ')
if (!req.query.query) {
res.code(400).send('invalid query')
return
}
// Convert PromQL to LogQL and execute
try {
req.query.query = p2l(req.query.query)
await this.scanFingerprints(
{
...req.query,
start: parseInt(req.query.start) * 1e9,
end: parseInt(req.query.end) * 1e9
},
{ res: res.raw }
)
res.sent = true
} catch (err) {
req.log.error({ err })
res.send(resp)
}
}

module.exports = handler
25 changes: 25 additions & 0 deletions lib/handlers/promlabel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Label Handler */
/*
For retrieving the names of the labels one can query on.
Responses looks like this:
{
"values": [
"instance",
"job",
...
]
}
*/

async function handler (req, res) {
await require('./label.js')({
...req,
query: {
...req.query,
start: req.query.start ? parseInt(req.query.start) * 1e9 : undefined,
end: req.query.end ? parseInt(req.query.end) * 1e9 : undefined
}
}, res)
}

module.exports = handler
25 changes: 25 additions & 0 deletions lib/handlers/promlabel_values.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/* Label Value Handler */
/*
For retrieving the label values one can query on.
Responses looks like this:
{
"values": [
"default",
"cortex-ops",
...
]
}
*/

async function handler (req, res) {
await require('./label_values.js')({
...req,
query: {
...req.query,
start: req.query.start ? parseInt(req.query.start) * 1e9 : undefined,
end: req.query.end ? parseInt(req.query.end) * 1e9 : undefined
}
}, res)
}

module.exports = handler
83 changes: 82 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"xxhash-wasm": "^0.4.2",
"yaml": "^1.10.2",
"json-stable-stringify": "^1.0.1",
"@qxip/promql2logql": "^1.0.10",
"@qxip/influx-line-protocol-parser": "^0.2.1"
},
"devDependencies": {
Expand Down
17 changes: 17 additions & 0 deletions qryn.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,23 @@ fastify.get('/prometheus/api/v1/rules', require('./lib/handlers/alerts/prom_get_
fastify.post('/api/v1/prom/remote/write', require('./lib/handlers/prom_push.js').bind(this))
fastify.post('/api/prom/remote/write', require('./lib/handlers/prom_push.js').bind(this))

/* PROMQETHEUS API EMULATION */
const handlerPromQueryRange = require('./lib/handlers/prom_query_range.js').bind(this)
fastify.get('/api/v1/query_range', handlerPromQueryRange)
const handlerPromQuery = require('./lib/handlers/prom_query.js').bind(this)
fastify.get('/api/v1/query', handlerPromQuery)
const handlerPromLabel = require('./lib/handlers/promlabel.js').bind(this)
const handlerPromLabelValues = require('./lib/handlers/promlabel_values.js').bind(this)
fastify.get('/api/v1/labels', handlerPromLabel) // piggyback on qryn labels
fastify.get('/api/v1/label/:name/values', handlerPromLabelValues) // piggyback on qryn values
fastify.post('/api/v1/labels', handlerPromLabel) // piggyback on qryn labels
fastify.post('/api/v1/label/:name/values', handlerPromLabelValues) // piggyback on qryn values
const handlerPromDefault = require('./lib/handlers/prom_default.js').bind(this)
fastify.get('/api/v1/metadata', handlerPromDefault) // default handler TBD
fastify.get('/api/v1/rules', handlerPromDefault) // default handler TBD
fastify.get('/api/v1/query_exemplars', handlerPromDefault) // default handler TBD
fastify.get('/api/v1/status/buildinfo', handlerPromDefault) // default handler TBD

/* INFLUX WRITE Handlers */
const handlerInfluxWrite = require('./lib/handlers/influx_write.js').bind(this)
fastify.post('/write', handlerInfluxWrite)
Expand Down

0 comments on commit 4c076b7

Please sign in to comment.