Skip to content

Commit ca56705

Browse files
Jason Bulicekabsrivastava
authored andcommitted
Range operators (#478)
* update idl * update autosuggest to allow range operands when whitelisted key is enabled for range query * bring in idl changes to support isRangeQuery metadata on field names, refactor usb code to reflect changes * fix backend, fix front end, adjust data format for chips, improve logic in places for handling chips * test for period key/values and range operators * fix logic to display tabs #472 * fix grpc bug * fix issue with duration operator drop down not showing, set > as first option * fix bug with merging names and metadata
1 parent 87f8423 commit ca56705

16 files changed

Lines changed: 307 additions & 157 deletions

File tree

haystack-idl

server/connectors/traces/haystack/expressionTreeBuilder.js

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,28 @@
1414
* limitations under the License.
1515
*/
1616

17-
const requestBuilder = {};
17+
const expressionTreeBuilder = {};
1818
const messages = require('../../../../static_codegen/traceReader_pb');
1919

2020
const reservedField = ['startTime', 'endTime', 'limit', 'useExpressionTree', 'spanLevelFilters', 'granularity'];
2121

22+
expressionTreeBuilder.createFieldFromKeyValue = (key, value) => {
23+
const field = new messages.Field();
24+
field.setName(key);
25+
let fieldValue = value;
26+
let operator = messages.Field.Operator.EQUAL;
27+
28+
// check for custom operator at beginning of value string
29+
if (value[0] === '>' || value[0] === '<') {
30+
operator = value[0] === '>' ? messages.Field.Operator.GREATER_THAN : messages.Field.Operator.LESS_THAN;
31+
fieldValue = value.substr(1, value.length);
32+
}
33+
field.setValue(fieldValue);
34+
field.setOperator(operator);
35+
36+
return field;
37+
};
38+
2239
function createSpanLevelExpression(spanLevelFilters) {
2340
return spanLevelFilters.map((filterJson) => {
2441
const filter = JSON.parse(filterJson);
@@ -31,9 +48,7 @@ function createSpanLevelExpression(spanLevelFilters) {
3148
.map((key) => {
3249
const op = new messages.Operand();
3350

34-
const field = new messages.Field();
35-
field.setName(key);
36-
field.setValue(filter[key]);
51+
const field = expressionTreeBuilder.createFieldFromKeyValue(key, filter[key]);
3752

3853
op.setField(field);
3954

@@ -53,9 +68,7 @@ function createTraceLevelOperands(query) {
5368
.map((key) => {
5469
const operand = new messages.Operand();
5570

56-
const field = new messages.Field();
57-
field.setName(key);
58-
field.setValue(query[key]);
71+
const field = expressionTreeBuilder.createFieldFromKeyValue(key, query[key]);
5972

6073
operand.setField(field);
6174

@@ -64,7 +77,7 @@ function createTraceLevelOperands(query) {
6477
}
6578

6679

67-
requestBuilder.createFilterExpression = (query) => {
80+
expressionTreeBuilder.createFilterExpression = (query) => {
6881
const expressionTree = new messages.ExpressionTree();
6982

7083
expressionTree.setOperator(messages.ExpressionTree.Operator.AND);
@@ -81,4 +94,4 @@ requestBuilder.createFilterExpression = (query) => {
8194
return expressionTree;
8295
};
8396

84-
module.exports = requestBuilder;
97+
module.exports = expressionTreeBuilder;

server/connectors/traces/haystack/search/searchRequestBuilder.js

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
const createFilterExpression = require('../expressionTreeBuilder').createFilterExpression;
17+
const expressionTreeBuilder = require('../expressionTreeBuilder');
1818

1919
const requestBuilder = {};
2020
const messages = require('../../../../../static_codegen/traceReader_pb');
@@ -25,20 +25,14 @@ const DEFAULT_RESULTS_LIMIT = 25;
2525
function createFieldsList(query) {
2626
return Object.keys(query)
2727
.filter(key => query[key] && !reservedField.includes(key))
28-
.map((key) => {
29-
const field = new messages.Field();
30-
field.setName(key);
31-
field.setValue(query[key]);
32-
33-
return field;
34-
});
28+
.map(key => expressionTreeBuilder(key, query[key]));
3529
}
3630

3731
requestBuilder.buildRequest = (query) => {
3832
const request = new messages.TracesSearchRequest();
3933

4034
if (query.useExpressionTree) {
41-
request.setFilterexpression(createFilterExpression(query));
35+
request.setFilterexpression(expressionTreeBuilder.createFilterExpression(query));
4236
} else {
4337
request.setFieldsList(createFieldsList(query));
4438
}

server/connectors/traces/haystack/tracesConnector.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,22 @@ connector.getSearchableKeys = () => {
7979
return fieldNameFetcher
8080
.fetch(request)
8181
.then((result) => {
82-
const keys = result.getNamesList();
82+
const fieldNamesWithMetadata = {};
83+
const names = result.getNamesList();
84+
const metadata = result.getFieldMetadataList();
85+
86+
// create map with key as whitelisted field name
87+
names.forEach((name, index) => {
88+
fieldNamesWithMetadata[name] = {isRangeQuery: metadata[index] ? metadata[index].getIsrangequery() : false};
89+
});
90+
8391
// additional keys which are not part of Index
84-
keys.push('traceId', 'serviceName', 'operationName');
85-
return keys;
92+
fieldNamesWithMetadata.traceId = {isRangeQuery: false};
93+
fieldNamesWithMetadata.serviceName = {isRangeQuery: false};
94+
fieldNamesWithMetadata.operationName = {isRangeQuery: false};
95+
fieldNamesWithMetadata.duration = {isRangeQuery: true};
96+
97+
return fieldNamesWithMetadata;
8698
});
8799
};
88100

server/connectors/traces/stub/tracesConnector.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,15 @@ connector.getTimeline = query => Q.fcall(() => {
276276
return getRandomValues(granularity, points, parseInt(query.startTime, 10));
277277
});
278278

279-
connector.getSearchableKeys = () => Q.fcall(() => ['serviceName', 'operationName', 'traceId', 'error', 'minDuration', 'guid', 'testid']);
279+
connector.getSearchableKeys = () => Q.fcall(() => ({
280+
serviceName: {isRangeQuery: false},
281+
operationName: {isRangeQuery: false},
282+
traceId: {isRangeQuery: false},
283+
error: {isRangeQuery: false, values: ['true', 'false']},
284+
duration: {isRangeQuery: true},
285+
guid: {isRangeQuery: false},
286+
testid: {isRangeQuery: false}
287+
}));
280288

281289
const latencyCost = {
282290
latencyCost: [{

0 commit comments

Comments
 (0)