1- import { DataFrame ,
1+ import {
2+ DataFrame ,
23 Field ,
34 FieldType , // Imported for mapGreptimeTypeToGrafana
45 FieldConfig ,
@@ -9,6 +10,7 @@ import { DataFrame,
910import { GreptimeDataTypes } from './types' ;
1011import { getColumnsByHint } from 'data/sqlGenerator' ;
1112import { ColumnHint , QueryBuilderOptions } from 'types/queryBuilder' ;
13+ import { CHQuery } from 'types/sql' ;
1214
1315
1416/**
@@ -44,7 +46,7 @@ function mapGreptimeTypeToGrafana(greptimeType: string | undefined | null): Fiel
4446 }
4547 // Interval types -> map to string for now
4648 if ( lowerType . includes ( 'interval' ) ) {
47- return FieldType . string ;
49+ return FieldType . string ;
4850 }
4951
5052 // Log unhandled types and default to 'other'
@@ -232,7 +234,7 @@ export const greptimeTypeToGrafana: Record<GreptimeDataTypes, FieldType> = {
232234
233235type GreptimeTimeType = GreptimeDataTypes . TimestampSecond | GreptimeDataTypes . TimestampMillisecond | GreptimeDataTypes . TimestampMicrosecond | GreptimeDataTypes . TimestampNanosecond
234236export function toMs ( time : number , columnType : GreptimeTimeType ) {
235- switch ( columnType ) {
237+ switch ( columnType ) {
236238 case GreptimeDataTypes . TimestampSecond :
237239 return time * 1000
238240 case GreptimeDataTypes . TimestampMillisecond :
@@ -248,7 +250,7 @@ export function toMs(time: number, columnType: GreptimeTimeType) {
248250}
249251
250252
251- export function transformGreptimeDBLogs ( sqlResponse : GreptimeResponse , refId ?: string ) {
253+ export function transformGreptimeDBLogs ( sqlResponse : GreptimeResponse , query : CHQuery , contextColumns : string [ ] ) {
252254 if ( ! sqlResponse . output || sqlResponse . output . length === 0 ) {
253255 console . error ( 'GreptimeDB query failed or returned no data:' , sqlResponse . error ) ;
254256 return null ; // Or handle the error as needed
@@ -268,9 +270,9 @@ export function transformGreptimeDBLogs(sqlResponse: GreptimeResponse, refId?: s
268270 let severityColumnIndex = - 1 ;
269271 let idColumnIndex = - 1 ;
270272 const labelColumnIndices : Record < string , number > = { } ;
273+ const contextColumnIndices : Record < string , number > = { } ;
271274
272275 columnSchemas . forEach ( ( schema , index ) => {
273- console . log ( schema )
274276 const lowerCaseName = schema . name . toLowerCase ( ) ;
275277 if ( lowerCaseName === 'ts' || lowerCaseName === 'timestamp' ) {
276278 timestampColumnIndex = index ;
@@ -280,6 +282,8 @@ export function transformGreptimeDBLogs(sqlResponse: GreptimeResponse, refId?: s
280282 severityColumnIndex = index ;
281283 } else if ( lowerCaseName === 'id' ) {
282284 idColumnIndex = index ;
285+ } else if ( contextColumns . includes ( schema . name ) ) {
286+ contextColumnIndices [ schema . name ] = index ;
283287 } else {
284288 // Consider other columns as potential labels
285289 labelColumnIndices [ schema . name ] = index ;
@@ -296,10 +300,10 @@ export function transformGreptimeDBLogs(sqlResponse: GreptimeResponse, refId?: s
296300 const severities : string [ ] = [ ] ;
297301 const ids : string [ ] = [ ] ;
298302 const labelsArray : Array < Record < string , any > > = [ ] ;
299-
303+ const contextColumnValues : Record < string , string [ ] > = { } ;
300304 rows . forEach ( ( row ) => {
301305 const timestampValue = toMs ( row [ timestampColumnIndex ] , columnSchemas [ timestampColumnIndex ] . data_type as GreptimeTimeType ) ;
302-
306+
303307 timestamps . push (
304308 typeof timestampValue === 'string' || typeof timestampValue === 'number'
305309 ? new Date ( timestampValue ) . getTime ( )
@@ -316,6 +320,14 @@ export function transformGreptimeDBLogs(sqlResponse: GreptimeResponse, refId?: s
316320 }
317321 }
318322 labelsArray . push ( labels ) ;
323+
324+ for ( const contextName in contextColumnIndices ) {
325+ if ( ! contextColumnValues [ contextName ] ) {
326+ contextColumnValues [ contextName ] = [ ] ;
327+ }
328+ contextColumnValues [ contextName ] . push ( row [ contextColumnIndices [ contextName ] ] ) ;
329+ }
330+
319331 } ) ;
320332
321333 const fields = [
@@ -331,10 +343,14 @@ export function transformGreptimeDBLogs(sqlResponse: GreptimeResponse, refId?: s
331343 fields . push ( { name : 'id' , type : FieldType . string , values : ids } ) ;
332344 }
333345
346+ for ( const contextName in contextColumnValues ) {
347+ fields . push ( { name : contextName , type : FieldType . string , values : contextColumnValues [ contextName ] } ) ;
348+ }
349+
334350 fields . push ( { name : 'labels' , type : FieldType . other , values : labelsArray } ) ;
335351
336352 const result = createDataFrame ( {
337- refId : refId ,
353+ refId : query . refId ,
338354 fields : fields ,
339355 meta : {
340356 preferredVisualisationType : 'logs' ,
@@ -376,7 +392,7 @@ export function transformGreptimeDBTraceDetails(response: GreptimeResponse, buil
376392 const rows = records . rows ;
377393
378394 const spans : GrafanaTraceSpan [ ] = rows . map ( row => {
379- const data : Record < string , any > = { span_attributes : [ ] , service_attributes : [ ] } ;
395+ const data : Record < string , any > = { span_attributes : [ ] , service_attributes : [ ] } ;
380396 const tagColumnNames = getColumnsByHint ( builderOptions , ColumnHint . TraceTags ) ?. map ( ( v ) => v . name ) || [ ]
381397 const serticeTagColumnNames = getColumnsByHint ( builderOptions , ColumnHint . TraceServiceTags ) ?. map ( ( v ) => v . name ) || [ ]
382398 columns . forEach ( ( schema , index ) => {
@@ -393,7 +409,7 @@ export function transformGreptimeDBTraceDetails(response: GreptimeResponse, buil
393409 } else {
394410 data [ schema . name ] = row [ index ] ;
395411 }
396-
412+
397413 } ) ;
398414
399415
@@ -419,12 +435,12 @@ export function transformGreptimeDBTraceDetails(response: GreptimeResponse, buil
419435 { name : 'operationName' , type : FieldType . string , values : spans . map ( s => s . operationName ) } ,
420436 { name : 'serviceName' , type : FieldType . string , values : spans . map ( s => s . serviceName ) } ,
421437 { name : 'startTime' , type : FieldType . time , values : spans . map ( s => s . startTime ) } ,
422- // { name: 'duration', type: FieldType.number, values: [
423- // 50,
424- // 100
425- // ],
426- // "config": { "unit": "ms" }, },
427- { name : 'duration' , type : FieldType . number , values : spans . map ( s => s . duration ) , "config" : { "unit" : "ms" } , } ,
438+ // { name: 'duration', type: FieldType.number, values: [
439+ // 50,
440+ // 100
441+ // ],
442+ // "config": { "unit": "ms" }, },
443+ { name : 'duration' , type : FieldType . number , values : spans . map ( s => s . duration ) , "config" : { "unit" : "ms" } , } ,
428444 { name : 'tags' , type : FieldType . other , values : spans . map ( s => s . tags ) } ,
429445 { name : 'serviceTags' , type : FieldType . other , values : spans . map ( s => s . serviceTags ) } ,
430446 // { name: 'logs', type: FieldType.other, values: spans.map(s => s.logs) },
@@ -527,107 +543,107 @@ export function transformGreptimeResponseToGrafana(
527543
528544 // Case 1: No grouping columns or only one grouping column.
529545 if ( groupingColumnIndices . length === 0 ) {
530- const columnValueArrays : any [ ] [ ] = Array . from ( { length : numCols } , ( ) => new Array ( numRows ) ) ;
531-
532- for ( let rowIndex = 0 ; rowIndex < numRows ; rowIndex ++ ) {
533- const row = rows [ rowIndex ] ;
534- for ( let colIndex = 0 ; colIndex < numCols ; colIndex ++ ) {
535- const colSchema = columnSchemas [ colIndex ] ;
536- const grafanaDataType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
537- if ( grafanaDataType === FieldType . time ) {
538- columnValueArrays [ colIndex ] [ rowIndex ] = toMs ( row [ colIndex ] , colSchema . data_type as GreptimeTimeType ) ;
539- } else {
540- columnValueArrays [ colIndex ] [ rowIndex ] = row [ colIndex ] ;
541- }
542- }
546+ const columnValueArrays : any [ ] [ ] = Array . from ( { length : numCols } , ( ) => new Array ( numRows ) ) ;
547+
548+ for ( let rowIndex = 0 ; rowIndex < numRows ; rowIndex ++ ) {
549+ const row = rows [ rowIndex ] ;
550+ for ( let colIndex = 0 ; colIndex < numCols ; colIndex ++ ) {
551+ const colSchema = columnSchemas [ colIndex ] ;
552+ const grafanaDataType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
553+ if ( grafanaDataType === FieldType . time ) {
554+ columnValueArrays [ colIndex ] [ rowIndex ] = toMs ( row [ colIndex ] , colSchema . data_type as GreptimeTimeType ) ;
555+ } else {
556+ columnValueArrays [ colIndex ] [ rowIndex ] = row [ colIndex ] ;
557+ }
543558 }
544- const fields : Field [ ] = columnSchemas . map ( ( colSchema , i ) => {
545- const fieldName = colSchema . name || `column_${ i + 1 } ` ;
546- const fieldType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
547- const values = columnValueArrays [ i ] ;
548- const config : FieldConfig = {
549- displayName : fieldName ,
550- } ;
551- return {
552- name : fieldName ,
553- type : fieldType ,
554- config : config ,
555- values : values ,
556- } ;
557- } ) ;
558- const frame : DataFrame = {
559- name : `Result ${ index + 1 } ` ,
560- refId : refId ,
561- fields : fields ,
562- length : numRows ,
559+ }
560+ const fields : Field [ ] = columnSchemas . map ( ( colSchema , i ) => {
561+ const fieldName = colSchema . name || `column_${ i + 1 } ` ;
562+ const fieldType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
563+ const values = columnValueArrays [ i ] ;
564+ const config : FieldConfig = {
565+ displayName : fieldName ,
563566 } ;
564- dataFrames . push ( frame ) ;
567+ return {
568+ name : fieldName ,
569+ type : fieldType ,
570+ config : config ,
571+ values : values ,
572+ } ;
573+ } ) ;
574+ const frame : DataFrame = {
575+ name : `Result ${ index + 1 } ` ,
576+ refId : refId ,
577+ fields : fields ,
578+ length : numRows ,
579+ } ;
580+ dataFrames . push ( frame ) ;
565581 } else {
566- // Case 2: Multiple grouping columns - create multiple series
567- // Iterate through rows from the response
568- for ( let rowIndex = 0 ; rowIndex < numRows ; rowIndex ++ ) {
569- const row = rows [ rowIndex ] ;
570-
571- // Validate row structure
572- if ( ! Array . isArray ( row ) || row . length !== numCols ) {
573- console . error ( `Row ${ rowIndex } in result set ${ index } has incorrect length (${ row ?. length ?? 'undefined' } ), expected ${ numCols } . Skipping row.` ) ;
574- continue ; // Move to the next row
575- }
576-
577- // Construct a unique key for the series based on the grouping column values.
578- let groupKey = '' ;
579- for ( const groupIndex of groupingColumnIndices ) {
580- groupKey += `${ columnSchemas [ groupIndex ] . name } :${ row [ groupIndex ] } ;` ;
581- }
582-
583- // Initialize the series entry if it doesn't exist
584- if ( ! seriesMap [ groupKey ] ) {
585- seriesMap [ groupKey ] = Array . from ( { length : numCols } , ( ) => [ ] ) ;
586- }
587-
588- // Populate the series data
589- for ( let colIndex = 0 ; colIndex < numCols ; colIndex ++ ) {
590- const colSchema = columnSchemas [ colIndex ] ;
591- const grafanaDataType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
592-
593- if ( grafanaDataType === FieldType . time ) {
594- seriesMap [ groupKey ] [ colIndex ] . push ( toMs ( row [ colIndex ] , colSchema . data_type as GreptimeTimeType ) ) ;
595- } else {
596- seriesMap [ groupKey ] [ colIndex ] . push ( row [ colIndex ] ) ;
597- }
598- }
582+ // Case 2: Multiple grouping columns - create multiple series
583+ // Iterate through rows from the response
584+ for ( let rowIndex = 0 ; rowIndex < numRows ; rowIndex ++ ) {
585+ const row = rows [ rowIndex ] ;
586+
587+ // Validate row structure
588+ if ( ! Array . isArray ( row ) || row . length !== numCols ) {
589+ console . error ( `Row ${ rowIndex } in result set ${ index } has incorrect length (${ row ?. length ?? 'undefined' } ), expected ${ numCols } . Skipping row.` ) ;
590+ continue ; // Move to the next row
599591 }
600- // --- Create Grafana DataFrames from Series ---
601- for ( const groupKey in seriesMap ) {
602- if ( ! Object . prototype . hasOwnProperty . call ( seriesMap , groupKey ) ) {
603- continue ;
592+
593+ // Construct a unique key for the series based on the grouping column values.
594+ let groupKey = '' ;
595+ for ( const groupIndex of groupingColumnIndices ) {
596+ groupKey += `${ columnSchemas [ groupIndex ] . name } :${ row [ groupIndex ] } ;` ;
597+ }
598+
599+ // Initialize the series entry if it doesn't exist
600+ if ( ! seriesMap [ groupKey ] ) {
601+ seriesMap [ groupKey ] = Array . from ( { length : numCols } , ( ) => [ ] ) ;
602+ }
603+
604+ // Populate the series data
605+ for ( let colIndex = 0 ; colIndex < numCols ; colIndex ++ ) {
606+ const colSchema = columnSchemas [ colIndex ] ;
607+ const grafanaDataType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
608+
609+ if ( grafanaDataType === FieldType . time ) {
610+ seriesMap [ groupKey ] [ colIndex ] . push ( toMs ( row [ colIndex ] , colSchema . data_type as GreptimeTimeType ) ) ;
611+ } else {
612+ seriesMap [ groupKey ] [ colIndex ] . push ( row [ colIndex ] ) ;
604613 }
605- const columnValueArrays = seriesMap [ groupKey ] ;
606- const fields : Field [ ] = columnSchemas . map ( ( colSchema , i ) => {
607- const fieldName = colSchema . name || `column_${ i + 1 } ` ;
608- const fieldType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
609- const values = columnValueArrays [ i ] ;
610-
611- const config : FieldConfig = {
612- displayName : fieldName + '_' + groupKey ,
613- } ;
614-
615- return {
616- name : fieldName ,
617- type : fieldType ,
618- config : config ,
619- values : values ,
620- } ;
621- } ) ;
622-
623- const frame : DataFrame = {
624- name : groupKey , // Use the group key as the frame name
625- refId : refId ,
626- fields : fields ,
627- length : columnValueArrays [ 0 ] ?. length || 0 ,
628- } ;
629- dataFrames . push ( frame ) ;
630614 }
615+ }
616+ // --- Create Grafana DataFrames from Series ---
617+ for ( const groupKey in seriesMap ) {
618+ if ( ! Object . prototype . hasOwnProperty . call ( seriesMap , groupKey ) ) {
619+ continue ;
620+ }
621+ const columnValueArrays = seriesMap [ groupKey ] ;
622+ const fields : Field [ ] = columnSchemas . map ( ( colSchema , i ) => {
623+ const fieldName = colSchema . name || `column_${ i + 1 } ` ;
624+ const fieldType = mapGreptimeTypeToGrafana ( colSchema . data_type ) ;
625+ const values = columnValueArrays [ i ] ;
626+
627+ const config : FieldConfig = {
628+ displayName : fieldName + '_' + groupKey ,
629+ } ;
630+
631+ return {
632+ name : fieldName ,
633+ type : fieldType ,
634+ config : config ,
635+ values : values ,
636+ } ;
637+ } ) ;
638+
639+ const frame : DataFrame = {
640+ name : groupKey , // Use the group key as the frame name
641+ refId : refId ,
642+ fields : fields ,
643+ length : columnValueArrays [ 0 ] ?. length || 0 ,
644+ } ;
645+ dataFrames . push ( frame ) ;
646+ }
631647 }
632648 } ) ;
633649
0 commit comments