Skip to content

Commit 2d2c630

Browse files
authored
Merge pull request #484 from metrico/traceql_nodejs
Traceql nodejs
2 parents 4a2429d + 710cd66 commit 2d2c630

13 files changed

+778
-29
lines changed

test/e2e

Submodule e2e updated from d45fb2d to f411532

test/traceql_parser.test.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const parser = require('../traceql/parser')
2+
3+
it('traceql: one selector', () => {
4+
const res = parser.ParseScript('{.testId="12345"}')
5+
expect(res.rootToken.value).toEqual('{.testId="12345"}')
6+
})
7+
8+
it('traceql: multiple selectors', () => {
9+
const res = parser.ParseScript('{.testId="12345" &&.spanN=9}')
10+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN=9}')
11+
})
12+
13+
it('traceql: multiple selectors OR Brackets', () => {
14+
const res = parser.ParseScript('{.testId="12345" && (.spanN=9 ||.spanN=8)}')
15+
expect(res.rootToken.value).toEqual('{.testId="12345" && (.spanN=9 ||.spanN=8)}')
16+
})
17+
18+
it('traceql: multiple selectors regexp', () => {
19+
const res = parser.ParseScript('{.testId="12345" &&.spanN=~"(9|8)"}')
20+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN=~"(9|8)"}')
21+
})
22+
23+
it('traceql: duration', () => {
24+
const res = parser.ParseScript('{.testId="12345" && duration>=9ms}')
25+
expect(res.rootToken.value).toEqual('{.testId="12345" && duration>=9ms}')
26+
})
27+
28+
it('traceql: float comparison', () => {
29+
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9}')
30+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9}')
31+
})
32+
33+
it('traceql: count empty result', () => {
34+
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | count() > 1')
35+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | count() > 1')
36+
})
37+
38+
it('traceql: max duration empty result', () => {
39+
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | max(duration) > 9ms')
40+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | max(duration) > 9ms')
41+
})
42+
43+
it('traceql: max duration', () => {
44+
const res = parser.ParseScript('{.testId="12345" &&.spanN>=8.9} | max(duration) > 8ms')
45+
expect(res.rootToken.value).toEqual('{.testId="12345" &&.spanN>=8.9} | max(duration) > 8ms')
46+
})
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const Sql = require('@cloki/clickhouse-sql')
2+
const { getCompareFn, durationToNs } = require('./shared')
3+
4+
module.exports = class Builder {
5+
constructor () {
6+
this.main = null
7+
this.fn = ''
8+
this.attr = ''
9+
this.compareFn = ''
10+
this.compareVal = ''
11+
}
12+
13+
/**
14+
*
15+
* @param main {BuiltProcessFn}
16+
* @returns {Builder}
17+
*/
18+
withMain (main) {
19+
this.main = main
20+
return this
21+
}
22+
23+
/**
24+
*
25+
* @param fn {string}
26+
* @returns {Builder}
27+
*/
28+
withFn (fn) {
29+
this.fn = fn
30+
return this
31+
}
32+
33+
/**
34+
*
35+
* @param attr {string}
36+
* @returns {Builder}
37+
*/
38+
withAttr (attr) {
39+
this.attr = attr
40+
return this
41+
}
42+
43+
/**
44+
*
45+
* @param fn {string}
46+
* @returns {Builder}
47+
*/
48+
withCompareFn (fn) {
49+
this.compareFn = fn
50+
return this
51+
}
52+
53+
/**
54+
*
55+
* @param val {string}
56+
* @returns {Builder}
57+
*/
58+
withCompareVal (val) {
59+
this.compareVal = val
60+
return this
61+
}
62+
63+
/**
64+
* @returns {ProcessFn}
65+
*/
66+
build () {
67+
const self = this
68+
/** @type {BuiltProcessFn} */
69+
const res = (ctx) => {
70+
const sel = this.main(ctx)
71+
const fCmpVal = self.cmpVal()
72+
const agg = self.aggregator()
73+
const compareFn = getCompareFn(self.compareFn)
74+
const comparreExp = compareFn(agg, Sql.val(fCmpVal))
75+
// .having is broken
76+
sel.having_conditions = Sql.And([...sel.having_conditions.args, comparreExp])
77+
return sel
78+
}
79+
return res
80+
}
81+
82+
cmpVal () {
83+
if (this.attr === 'duration') {
84+
return durationToNs(this.compareVal)
85+
}
86+
return parseFloat(this.compareVal)
87+
}
88+
89+
aggregator () {
90+
switch (this.fn) {
91+
case 'count':
92+
return new Sql.Raw('toFloat64(count(distinct index_search.span_id))')
93+
case 'avg':
94+
return new Sql.Raw('avgIf(agg_val, isNotNull(agg_val))')
95+
case 'max':
96+
return new Sql.Raw('maxIf(agg_val, isNotNull(agg_val))')
97+
case 'min':
98+
return new Sql.Raw('minIf(agg_val, isNotNull(agg_val))')
99+
case 'sum':
100+
return new Sql.Raw('sumIf(agg_val, isNotNull(agg_val))')
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)