Skip to content

Commit

Permalink
Merge pull request #484 from metrico/traceql_nodejs
Browse files Browse the repository at this point in the history
Traceql nodejs
  • Loading branch information
akvlad authored Mar 25, 2024
2 parents 4a2429d + 710cd66 commit 2d2c630
Show file tree
Hide file tree
Showing 13 changed files with 778 additions and 29 deletions.
2 changes: 1 addition & 1 deletion test/e2e
Submodule e2e updated from d45fb2 to f41153
46 changes: 46 additions & 0 deletions test/traceql_parser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
const parser = require('../traceql/parser')

it('traceql: one selector', () => {
const res = parser.ParseScript('{.testId="12345"}')
expect(res.rootToken.value).toEqual('{.testId="12345"}')
})

it('traceql: multiple selectors', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN=9}')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN=9}')
})

it('traceql: multiple selectors OR Brackets', () => {
const res = parser.ParseScript('{.testId="12345" && (.spanN=9 ||.spanN=8)}')
expect(res.rootToken.value).toEqual('{.testId="12345" && (.spanN=9 ||.spanN=8)}')
})

it('traceql: multiple selectors regexp', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN=~"(9|8)"}')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN=~"(9|8)"}')
})

it('traceql: duration', () => {
const res = parser.ParseScript('{.testId="12345" && duration>=9ms}')
expect(res.rootToken.value).toEqual('{.testId="12345" && duration>=9ms}')
})

it('traceql: float comparison', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9}')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9}')
})

it('traceql: count empty result', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | count() > 1')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | count() > 1')
})

it('traceql: max duration empty result', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | max(duration) > 9ms')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | max(duration) > 9ms')
})

it('traceql: max duration', () => {
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | max(duration) > 8ms')
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | max(duration) > 8ms')
})
103 changes: 103 additions & 0 deletions traceql/clickhouse_transpiler/aggregator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const Sql = require('@cloki/clickhouse-sql')
const { getCompareFn, durationToNs } = require('./shared')

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

/**
*
* @param main {BuiltProcessFn}
* @returns {Builder}
*/
withMain (main) {
this.main = main
return this
}

/**
*
* @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 {BuiltProcessFn} */
const res = (ctx) => {
const sel = this.main(ctx)
const fCmpVal = self.cmpVal()
const agg = self.aggregator()
const compareFn = getCompareFn(self.compareFn)
const comparreExp = compareFn(agg, Sql.val(fCmpVal))
// .having is broken
sel.having_conditions = Sql.And([...sel.having_conditions.args, comparreExp])
return sel
}
return res
}

cmpVal () {
if (this.attr === 'duration') {
return durationToNs(this.compareVal)
}
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))')
}
}
}
Loading

0 comments on commit 2d2c630

Please sign in to comment.