@@ -28,7 +28,7 @@ export const generateSql = (options: QueryBuilderOptions): string => {
28
28
*/
29
29
const generateTraceSearchQuery = ( options : QueryBuilderOptions ) : string => {
30
30
const { database, table } = options ;
31
-
31
+
32
32
const queryParts : string [ ] = [ ] ;
33
33
34
34
// TODO: these columns could be a map or some other convenience function
@@ -37,28 +37,28 @@ const generateTraceSearchQuery = (options: QueryBuilderOptions): string => {
37
37
if ( traceId !== undefined ) {
38
38
selectParts . push ( `${ escapeIdentifier ( traceId . name ) } as traceID` ) ;
39
39
}
40
-
40
+
41
41
const traceServiceName = getColumnByHint ( options , ColumnHint . TraceServiceName ) ;
42
42
if ( traceServiceName !== undefined ) {
43
43
selectParts . push ( `${ escapeIdentifier ( traceServiceName . name ) } as serviceName` ) ;
44
44
}
45
-
45
+
46
46
const traceOperationName = getColumnByHint ( options , ColumnHint . TraceOperationName ) ;
47
47
if ( traceOperationName !== undefined ) {
48
48
selectParts . push ( `${ escapeIdentifier ( traceOperationName . name ) } as operationName` ) ;
49
49
}
50
-
50
+
51
51
const traceStartTime = getColumnByHint ( options , ColumnHint . Time ) ;
52
52
if ( traceStartTime !== undefined ) {
53
53
selectParts . push ( `${ escapeIdentifier ( traceStartTime . name ) } as startTime` ) ;
54
54
}
55
-
55
+
56
56
const traceDurationTime = getColumnByHint ( options , ColumnHint . TraceDurationTime ) ;
57
57
if ( traceDurationTime !== undefined ) {
58
58
const timeUnit = options . meta ?. traceDurationUnit ;
59
59
selectParts . push ( getTraceDurationSelectSql ( escapeIdentifier ( traceDurationTime . name ) , timeUnit ) ) ;
60
60
}
61
-
61
+
62
62
const selectPartsSql = selectParts . join ( ', ' ) ;
63
63
64
64
queryParts . push ( 'SELECT' ) ;
@@ -93,7 +93,7 @@ const generateTraceSearchQuery = (options: QueryBuilderOptions): string => {
93
93
*/
94
94
const generateTraceIdQuery = ( options : QueryBuilderOptions ) : string => {
95
95
const { database, table } = options ;
96
-
96
+
97
97
const queryParts : string [ ] = [ ] ;
98
98
99
99
// TODO: these columns could be a map or some other convenience function
@@ -102,48 +102,53 @@ const generateTraceIdQuery = (options: QueryBuilderOptions): string => {
102
102
if ( traceId !== undefined ) {
103
103
selectParts . push ( `${ escapeIdentifier ( traceId . name ) } as traceID` ) ;
104
104
}
105
-
105
+
106
106
const traceSpanId = getColumnByHint ( options , ColumnHint . TraceSpanId ) ;
107
107
if ( traceSpanId !== undefined ) {
108
108
selectParts . push ( `${ escapeIdentifier ( traceSpanId . name ) } as spanID` ) ;
109
109
}
110
-
110
+
111
111
const traceParentSpanId = getColumnByHint ( options , ColumnHint . TraceParentSpanId ) ;
112
112
if ( traceParentSpanId !== undefined ) {
113
113
selectParts . push ( `${ escapeIdentifier ( traceParentSpanId . name ) } as parentSpanID` ) ;
114
114
}
115
-
115
+
116
116
const traceServiceName = getColumnByHint ( options , ColumnHint . TraceServiceName ) ;
117
117
if ( traceServiceName !== undefined ) {
118
118
selectParts . push ( `${ escapeIdentifier ( traceServiceName . name ) } as serviceName` ) ;
119
119
}
120
-
120
+
121
121
const traceOperationName = getColumnByHint ( options , ColumnHint . TraceOperationName ) ;
122
122
if ( traceOperationName !== undefined ) {
123
123
selectParts . push ( `${ escapeIdentifier ( traceOperationName . name ) } as operationName` ) ;
124
124
}
125
-
125
+
126
126
const traceStartTime = getColumnByHint ( options , ColumnHint . Time ) ;
127
127
if ( traceStartTime !== undefined ) {
128
128
selectParts . push ( `${ convertTimeFieldToMilliseconds ( escapeIdentifier ( traceStartTime . name ) ) } as startTime` ) ;
129
129
}
130
-
130
+
131
131
const traceDurationTime = getColumnByHint ( options , ColumnHint . TraceDurationTime ) ;
132
132
if ( traceDurationTime !== undefined ) {
133
133
const timeUnit = options . meta ?. traceDurationUnit ;
134
134
selectParts . push ( getTraceDurationSelectSql ( escapeIdentifier ( traceDurationTime . name ) , timeUnit ) ) ;
135
135
}
136
-
136
+
137
137
// TODO: for tags and serviceTags, consider the column type. They might not require mapping, they could already be JSON.
138
138
const traceTags = getColumnByHint ( options , ColumnHint . TraceTags ) ;
139
139
if ( traceTags !== undefined ) {
140
140
selectParts . push ( `arrayMap(key -> map('key', key, 'value',${ escapeIdentifier ( traceTags . name ) } [key]), mapKeys(${ escapeIdentifier ( traceTags . name ) } )) as tags` ) ;
141
141
}
142
-
142
+
143
143
const traceServiceTags = getColumnByHint ( options , ColumnHint . TraceServiceTags ) ;
144
144
if ( traceServiceTags !== undefined ) {
145
145
selectParts . push ( `arrayMap(key -> map('key', key, 'value',${ escapeIdentifier ( traceServiceTags . name ) } [key]), mapKeys(${ escapeIdentifier ( traceServiceTags . name ) } )) as serviceTags` ) ;
146
146
}
147
+
148
+ const traceStatusCode = getColumnByHint ( options , ColumnHint . TraceStatusCode ) ;
149
+ if ( traceStatusCode !== undefined ) {
150
+ selectParts . push ( `if(${ escapeIdentifier ( traceStatusCode . name ) } IN ('Error', 'STATUS_CODE_ERROR'), 2, 0) as statusCode` ) ;
151
+ }
147
152
const selectPartsSql = selectParts . join ( ', ' ) ;
148
153
149
154
// Optimize trace ID filtering for OTel enabled trace lookups
@@ -207,14 +212,14 @@ const generateTraceIdQuery = (options: QueryBuilderOptions): string => {
207
212
* Generates logs query with columns that fit Grafana's Logs panel
208
213
* Column aliases follow this structure:
209
214
* https://grafana.com/developers/plugin-tools/tutorials/build-a-logs-data-source-plugin#logs-data-frame-format
210
- *
215
+ *
211
216
* note: column order seems to matter as well as alias name
212
217
*/
213
218
const generateLogsQuery = ( _options : QueryBuilderOptions ) : string => {
214
219
// Copy columns so column aliases can be safely mutated
215
220
const options = { ..._options , columns : _options . columns ?. map ( c => ( { ...c } ) ) } ;
216
221
const { database, table } = options ;
217
-
222
+
218
223
const queryParts : string [ ] = [ ] ;
219
224
220
225
// TODO: these columns could be a map or some other convenience function
@@ -263,7 +268,7 @@ const generateLogsQuery = (_options: QueryBuilderOptions): string => {
263
268
queryParts . push ( 'FROM' ) ;
264
269
queryParts . push ( getTableIdentifier ( database , table ) ) ;
265
270
266
-
271
+
267
272
const filterParts = getFilters ( options ) ;
268
273
const hasLogMessageFilter = logMessage && options . meta ?. logMessageLike ;
269
274
@@ -304,7 +309,7 @@ const generateSimpleTimeSeriesQuery = (_options: QueryBuilderOptions): string =>
304
309
// Copy columns so column aliases can be safely mutated
305
310
const options = { ..._options , columns : _options . columns ?. map ( c => ( { ...c } ) ) } ;
306
311
const { database, table } = options ;
307
-
312
+
308
313
const queryParts : string [ ] = [ ] ;
309
314
310
315
const selectParts : string [ ] = [ ] ;
@@ -341,7 +346,7 @@ const generateSimpleTimeSeriesQuery = (_options: QueryBuilderOptions): string =>
341
346
342
347
// (v3) aggregate selections go AFTER group by
343
348
aggregateSelectParts . forEach ( a => selectParts . push ( a ) ) ;
344
-
349
+
345
350
const selectPartsSql = selectParts . join ( ', ' ) ;
346
351
347
352
queryParts . push ( 'SELECT' ) ;
@@ -354,7 +359,7 @@ const generateSimpleTimeSeriesQuery = (_options: QueryBuilderOptions): string =>
354
359
queryParts . push ( 'WHERE' ) ;
355
360
queryParts . push ( filterParts ) ;
356
361
}
357
-
362
+
358
363
const hasAggregates = ( options . aggregates ?. length || 0 > 0 ) ;
359
364
const hasGroupBy = ( options . groupBy ?. length || 0 > 0 ) ;
360
365
if ( hasAggregates || hasGroupBy ) {
@@ -389,7 +394,7 @@ const generateAggregateTimeSeriesQuery = (_options: QueryBuilderOptions): string
389
394
// Copy columns so column aliases can be safely mutated
390
395
const options = { ..._options , columns : _options . columns ?. map ( c => ( { ...c } ) ) } ;
391
396
const { database, table } = options ;
392
-
397
+
393
398
const queryParts : string [ ] = [ ] ;
394
399
const selectParts : string [ ] = [ ] ;
395
400
@@ -407,7 +412,7 @@ const generateAggregateTimeSeriesQuery = (_options: QueryBuilderOptions): string
407
412
const name = `${ agg . aggregateType } (${ agg . column } )` ;
408
413
selectParts . push ( `${ name } ${ alias } ` ) ;
409
414
} ) ;
410
-
415
+
411
416
const selectPartsSql = selectParts . join ( ', ' ) ;
412
417
413
418
queryParts . push ( 'SELECT' ) ;
@@ -477,7 +482,7 @@ const generateTableQuery = (options: QueryBuilderOptions): string => {
477
482
// selectParts.push(g)
478
483
} ) ;
479
484
}
480
-
485
+
481
486
const selectPartsSql = selectParts . join ( ', ' ) ;
482
487
483
488
queryParts . push ( 'SELECT' ) ;
@@ -528,7 +533,7 @@ export const getColumnsByHints = (options: QueryBuilderOptions, hints: readonly
528
533
529
534
const getColumnIdentifier = ( col : SelectedColumn ) : string => {
530
535
let colName = col . name ;
531
-
536
+
532
537
// allow for functions like count()
533
538
if ( colName . includes ( '(' ) || colName . includes ( ')' ) || colName . includes ( '"' ) || colName . includes ( '"' ) || colName . includes ( ' as ' ) ) {
534
539
colName = col . name
@@ -690,7 +695,7 @@ const getFilters = (options: QueryBuilderOptions): string => {
690
695
if ( operator ) {
691
696
filterParts . push ( operator ) ;
692
697
}
693
-
698
+
694
699
if ( isNullFilter ( filter . operator ) ) {
695
700
// empty
696
701
} else if ( filter . operator === FilterOperator . IsEmpty ) {
0 commit comments