2022-07-07 08:49:31 -05:00
import { DataFrame , QueryHint } from '@grafana/data' ;
2023-01-05 07:56:31 -06:00
import {
isQueryWithLabelFilter ,
isQueryPipelineErrorFiltering ,
isQueryWithLabelFormat ,
isQueryWithParser ,
isQueryWithLineFilter ,
} from './queryUtils' ;
2022-07-22 09:59:25 -05:00
import {
dataFrameHasLevelLabel ,
extractHasErrorLabelFromDataFrame ,
extractLevelLikeLabelFromDataFrame ,
extractLogParserFromDataFrame ,
} from './responseUtils' ;
2022-07-07 08:49:31 -05:00
export function getQueryHints ( query : string , series : DataFrame [ ] ) : QueryHint [ ] {
2022-07-14 03:48:27 -05:00
if ( series . length === 0 ) {
return [ ] ;
}
2022-07-07 08:49:31 -05:00
const hints : QueryHint [ ] = [ ] ;
2022-07-14 03:48:27 -05:00
const { queryWithParser , parserCount } = isQueryWithParser ( query ) ;
2022-07-07 08:49:31 -05:00
2022-07-14 03:48:27 -05:00
if ( ! queryWithParser ) {
2023-03-30 08:18:02 -05:00
const { hasLogfmt , hasJSON , hasPack } = extractLogParserFromDataFrame ( series [ 0 ] ) ;
2022-07-14 03:48:27 -05:00
if ( hasJSON ) {
2023-03-30 08:18:02 -05:00
if ( hasPack ) {
hints . push ( {
type : 'ADD_UNPACK_PARSER' ,
label : 'Selected log stream selector has packed logs.' ,
fix : {
title : 'add unpack parser' ,
label : 'Consider using unpack parser.' ,
action : {
type : 'ADD_UNPACK_PARSER' ,
query ,
} ,
2022-07-07 08:49:31 -05:00
} ,
2023-03-30 08:18:02 -05:00
} ) ;
} else {
hints . push ( {
type : 'ADD_JSON_PARSER' ,
label : 'Selected log stream selector has JSON formatted logs.' ,
fix : {
title : 'add json parser' ,
label : 'Consider using JSON parser.' ,
action : {
type : 'ADD_JSON_PARSER' ,
query ,
} ,
} ,
} ) ;
}
2022-07-07 08:49:31 -05:00
}
2022-07-14 03:48:27 -05:00
if ( hasLogfmt ) {
2022-07-07 08:49:31 -05:00
hints . push ( {
type : 'ADD_LOGFMT_PARSER' ,
label : 'Selected log stream selector has logfmt formatted logs.' ,
fix : {
2022-12-19 10:28:46 -06:00
title : 'add logfmt parser' ,
2022-07-14 03:48:27 -05:00
label : 'Consider using logfmt parser to turn key-value pairs in your log lines to labels.' ,
2022-07-07 08:49:31 -05:00
action : {
type : 'ADD_LOGFMT_PARSER' ,
query ,
} ,
} ,
} ) ;
}
}
2022-07-14 03:48:27 -05:00
if ( queryWithParser ) {
// To keep this simple, we consider pipeline error filtering hint only is query has up to 1 parser
if ( parserCount === 1 ) {
const hasPipelineErrorFiltering = isQueryPipelineErrorFiltering ( query ) ;
const hasError = extractHasErrorLabelFromDataFrame ( series [ 0 ] ) ;
if ( hasError && ! hasPipelineErrorFiltering ) {
hints . push ( {
type : 'ADD_NO_PIPELINE_ERROR' ,
label : 'Some logs in your selected log streams have parsing error.' ,
fix : {
2022-12-19 10:28:46 -06:00
title : 'remove pipeline errors' ,
2022-07-14 03:48:27 -05:00
label : 'Consider filtering out logs with parsing errors.' ,
action : {
type : 'ADD_NO_PIPELINE_ERROR' ,
query ,
} ,
} ,
} ) ;
}
}
2023-01-05 07:56:31 -06:00
const hasLabelFilter = isQueryWithLabelFilter ( query ) ;
if ( ! hasLabelFilter ) {
hints . push ( {
type : 'ADD_LABEL_FILTER' ,
label : 'Consider filtering logs by their label and value.' ,
fix : {
title : 'add label filter' ,
label : '' ,
action : {
type : 'ADD_LABEL_FILTER' ,
query ,
} ,
} ,
} ) ;
}
2022-07-14 03:48:27 -05:00
}
2022-07-22 09:59:25 -05:00
const queryWithLabelFormat = isQueryWithLabelFormat ( query ) ;
if ( ! queryWithLabelFormat ) {
const hasLevel = dataFrameHasLevelLabel ( series [ 0 ] ) ;
const levelLikeLabel = extractLevelLikeLabelFromDataFrame ( series [ 0 ] ) ;
// Add hint only if we don't have "level" label and have level-like label
if ( ! hasLevel && levelLikeLabel ) {
hints . push ( {
type : 'ADD_LEVEL_LABEL_FORMAT' ,
label : ` Some logs in your selected log stream have " ${ levelLikeLabel } " label. ` ,
fix : {
2022-12-19 10:28:46 -06:00
title : 'add label level format' ,
2022-07-22 09:59:25 -05:00
label : ` If ${ levelLikeLabel } label has level values, consider using label_format to rename it to "level". Level label can be then visualized in log volumes. ` ,
action : {
type : 'ADD_LEVEL_LABEL_FORMAT' ,
query ,
options : {
renameTo : 'level' ,
originalLabel : levelLikeLabel ,
} ,
} ,
} ,
} ) ;
}
}
2023-01-05 07:56:31 -06:00
const hasLineFilter = isQueryWithLineFilter ( query ) ;
if ( ! hasLineFilter ) {
hints . push ( {
type : 'ADD_LINE_FILTER' ,
label : 'Consider filtering logs for specific string.' ,
fix : {
title : 'add line filter' ,
label : '' ,
action : {
type : 'ADD_LINE_FILTER' ,
query ,
} ,
} ,
} ) ;
}
2022-07-07 08:49:31 -05:00
return hints ;
}