Skip to content

Commit

Permalink
fix: port traceql to nodejs
Browse files Browse the repository at this point in the history
  • Loading branch information
akvlad committed Mar 20, 2024
1 parent b4cda9e commit 7d0440a
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 0 deletions.
101 changes: 101 additions & 0 deletions traceql/clickhouse_transpiler/aggregator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
const Sql = require('@cloki/clickhouse-sql')
const {getCompareFn} = require('./shared')

module.exports = class Builder {
constructor () {
this.fn = ''
this.attr = ''
this.compareFn = ''
this.compareVal = ''
}

/**
*
* @param fn {string}
* @returns {Builder}
*/
withFn (fn) {
this.fn = fn
return this
}

/**
*
* @param attr {string}
* @returns {Builder}
*/
withAttr (attr) {
this.attr = attr
return this
}

/**
*
* @param fn {string}
* @returns {Builder}
*/
withCompareFn (fn) {
this.compareFn = fn
return this
}

/**
*
* @param val {string}
* @returns {Builder}
*/
withCompareVal (val) {
this.compareVal = val
return this
}

/**
* @returns {ProcessFn}
*/
build () {
const self = this
/** @type {ProcessFn} */
const res = (sel, ctx) => {
const fCmpVal = self.cmpVal()
const agg = self.aggregator()
const compareFn = getCompareFn(self.compareFn)
return sel.having(compareFn(agg, Sql.val(fCmpVal)))
}
return res
}

cmpVal() {
if (this.attr === 'duration') {
const measurements = {
ns: 1,
us: 1000,
ms: 1000000,
s: 1000000000,
m: 1000000000 * 60,
h: 1000000000 * 3600,
d: 1000000000 * 3600 * 24
}
const durationRe = this.compareVal.match(/(\d+\.?\d*)(ns|us|ms|s|m|h|d)?/)
if (!durationRe) {
throw new Error('Invalid duration compare value')
}
return parseFloat(durationRe[1]) * measurements[durationRe[2].toLowerCase()]
}
return parseFloat(this.compareVal)
}

aggregator () {
switch (this.fn) {
case 'count':
return new Sql.Raw('toFloat64(count(distinct index_search.span_id))')
case 'avg':
return new Sql.Raw('avgIf(agg_val, isNotNull(agg_val))')
case 'max':
return new Sql.Raw('maxIf(agg_val, isNotNull(agg_val))')
case 'min':
return new Sql.Raw('minIf(agg_val, isNotNull(agg_val))')
case 'sum':
return new Sql.Raw('sumIf(agg_val, isNotNull(agg_val))')
}
}
}
Empty file.
17 changes: 17 additions & 0 deletions traceql/clickhouse_transpiler/group_by.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const Sql = require('@cloki/clickhouse-sql')
/**
* @type {ProcessFn}
*/
module.exports = (sel, ctx) => {
const withMain = new Sql.With('index_search', sel)
return (new Sql.Select())
.with(withMain)
.select(
['trace_id', 'trace_id'],
[new Sql.Raw('groupArray(span_id)'), 'span_id'],
[new Sql.Raw('groupArray(duration)'), 'duration'],
[new Sql.Raw('groupArray(timestamp_ns)'), 'timestamp_ns']
).from(new Sql.WithReference(withMain))
.groupBy('trace_id')
.orderBy([new Sql.Raw('max(index_search.timestamp_ns)'), 'desc'])
}
25 changes: 25 additions & 0 deletions traceql/clickhouse_transpiler/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const Sql = require('@cloki/clickhouse-sql')
const { format } = require('date-fns')
/**
* @typedef {function(Sql.Select, {
* from: Date,
* to: Date,
* tracesAttrsTable: string,
* limit: number
* }): Select} ProcessFn
* @type ProcessFn
*/
module.exports.process = (sel, ctx) => {
return (new Sql.Select()).select(['trace_id', 'trace_id'],
[new Sql.Raw('lower(hex(span_id))'), 'span_id'],
[new Sql.Raw('any(duration)'), 'duration'],
[new Sql.Raw('any(timestamp_ns)', 'timestamp_ns')])
.from([ctx.tracesAttrsTable, 'traces_idx'])
.where(Sql.And(
Sql.Gte('date', Sql.val(format(ctx.from, 'yyyy-MM-dd'))),
Sql.Lt('date', Sql.val(format(ctx.to, 'yyyy-MM-dd'))),
Sql.Gte('traces_idx.timestamp_ns', new Sql.Raw(ctx.from.getTime() + '000000')),
Sql.Lt('traces_idx.timestamp_ns', new Sql.Raw(ctx.to.getTime() + '000000'))
)).groupBy('trace_id', 'span_id')
.orderBy(['timestamp_ns', 'desc'])
}
10 changes: 10 additions & 0 deletions traceql/clickhouse_transpiler/limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
*
* @type {ProcessFn}
*/
module.exports.process = (sel, ctx) => {
if (!ctx.limit) {
return sel
}
return sel.limit(ctx.limit)
}
22 changes: 22 additions & 0 deletions traceql/clickhouse_transpiler/shared.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const Sql = require('@cloki/clickhouse-sql')
/**
*
* @param op {string}
*/
module.exports.getCompareFn = (op) => {
switch (op) {
case '=':
return Sql.Eq
case '>':
return Sql.Gt
case '<':
return Sql.Lt
case '>=':
return Sql.Gte
case '<=':
return Sql.Lte
case '!=':
return Sql.Ne
}
throw new Error('not supported operator: ' + op)
}
9 changes: 9 additions & 0 deletions traceql/parser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const fs = require('fs')
const path = require('path')
const { Compiler } = require('bnf')

const bnf = fs.readFileSync(path.join(__dirname, 'traceql.bnf')).toString()
const compiler = new Compiler()
compiler.AddLanguage(bnf, 'traceql')

module.exports = compiler
20 changes: 20 additions & 0 deletions traceql/traceql.bnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<SYNTAX> ::= <selector> *(<OWSP> <and_or> <OWSP> <SYNTAX>)

selector ::= "{" <OWSP> <attr_selector_exp> <OWSP> "}" [<OWSP> <aggregator>]
attr_selector_exp ::= (<attr_selector> | "(" <OWSP> <attr_selector_exp> <OWSP> ")") [ <OWSP> <and_or> <OWSP> <attr_selector_exp>]
and_or ::= "&&" | "||"

aggregator ::= "|" <OWSP> <fn> <OWSP> <attr> <OWSP> <cmp> <OWSP> <number> [<measurement>]
fn ::= "count"|"sum"|"min"|"max"|"avg"
attr ::= "(" <OWSP> [<label_name>] <OWSP> ")"
cmp ::= "="|"!="|"<"|"<="|">"|">="
measurement ::= "ns"|"us"|"ms"|"s"|"m"|"h"|"d"

label_name ::= ("." | <ALPHA> | "_") *("." | <ALPHA> | "_" | <DIGITS>)
number ::= ["-"] <DIGITS> ["." <DIGITS>]

attr_selector ::= <label_name> <OWSP> <op> <OWSP> <value>
op ::= ">="|"<="|"=~"|"="|"!="|"<"|">"|"!~"
value ::= <time_val> | <number> | <quoted_str>
time_val ::= (<DIGITS> ["." <DIGITS>]) <measurement>
quoted_str ::= (<QUOTE><QUOTE>) | (<AQUOTE><AQUOTE>) | <QLITERAL> | <AQLITERAL>

0 comments on commit 7d0440a

Please sign in to comment.