2022-03-04 02:42:18 -06:00
import { cloneDeep } from 'lodash' ;
2022-05-11 02:29:04 -05:00
import { ArrayVector , DataFrame , DataQueryResponse , Field , FieldType } from '@grafana/data' ;
2022-04-22 08:33:13 -05:00
2022-03-04 02:42:18 -06:00
import { transformBackendResult } from './backendResultTransformer' ;
2022-05-11 02:29:04 -05:00
// needed because the derived-fields functionality calls it
jest . mock ( '@grafana/runtime' , ( ) = > ( {
// @ts-ignore
. . . jest . requireActual ( '@grafana/runtime' ) ,
getDataSourceSrv : ( ) = > {
return {
getInstanceSettings : ( ) = > {
return { name : 'Loki1' } ;
} ,
} ;
} ,
} ) ) ;
2022-04-12 04:58:48 -05:00
const LOKI_EXPR = '{level="info"} |= "thing1"' ;
const inputFrame : DataFrame = {
2022-03-04 02:42:18 -06:00
refId : 'A' ,
meta : {
2022-04-12 04:58:48 -05:00
executedQueryString : LOKI_EXPR ,
2022-05-16 06:38:05 -05:00
custom : {
frameType : 'LabeledTimeValues' ,
} ,
2022-03-04 02:42:18 -06:00
} ,
fields : [
{
2022-06-08 01:14:34 -05:00
name : 'Time' ,
2022-03-04 02:42:18 -06:00
type : FieldType . time ,
config : { } ,
2022-05-03 01:03:25 -05:00
values : new ArrayVector ( [ 1645030244810 , 1645030247027 ] ) ,
2022-03-04 02:42:18 -06:00
} ,
{
2022-06-08 01:14:34 -05:00
name : 'Line' ,
2022-04-12 04:58:48 -05:00
type : FieldType . string ,
config : { } ,
2022-05-03 01:03:25 -05:00
values : new ArrayVector ( [ 'line1' , 'line2' ] ) ,
2022-04-12 04:58:48 -05:00
} ,
{
name : 'labels' ,
2022-06-08 01:14:34 -05:00
type : FieldType . other ,
2022-05-16 01:29:46 -05:00
config : { } ,
values : new ArrayVector ( [
{ level : 'info' , code : '41🌙' } ,
{ level : 'error' , code : '41🌙' } ,
] ) ,
2022-03-04 02:42:18 -06:00
} ,
{
name : 'tsNs' ,
2022-05-03 01:03:25 -05:00
type : FieldType . string ,
2022-04-12 04:58:48 -05:00
config : { } ,
2022-05-03 01:03:25 -05:00
values : new ArrayVector ( [ '1645030244810757120' , '1645030247027735040' ] ) ,
2022-04-12 04:58:48 -05:00
} ,
{
name : 'id' ,
2022-03-04 02:42:18 -06:00
type : FieldType . string ,
config : { } ,
2022-05-03 01:03:25 -05:00
values : new ArrayVector ( [ 'id1' , 'id2' ] ) ,
2022-03-04 02:42:18 -06:00
} ,
] ,
2022-04-12 04:58:48 -05:00
length : 5 ,
2022-03-04 02:42:18 -06:00
} ;
describe ( 'loki backendResultTransformer' , ( ) = > {
it ( 'processes a logs-dataframe correctly' , ( ) = > {
2022-04-12 04:58:48 -05:00
const response : DataQueryResponse = { data : [ cloneDeep ( inputFrame ) ] } ;
2022-03-04 02:42:18 -06:00
2022-04-12 04:58:48 -05:00
const expectedFrame = cloneDeep ( inputFrame ) ;
2022-03-04 02:42:18 -06:00
expectedFrame . meta = {
2022-04-12 04:58:48 -05:00
. . . expectedFrame . meta ,
2022-03-04 02:42:18 -06:00
preferredVisualisationType : 'logs' ,
searchWords : [ 'thing1' ] ,
2022-03-31 10:50:27 -05:00
custom : {
2022-05-16 06:38:05 -05:00
. . . expectedFrame . meta ? . custom ,
2022-03-31 10:50:27 -05:00
lokiQueryStatKey : 'Summary: total bytes processed' ,
} ,
2022-03-04 02:42:18 -06:00
} ;
const expected : DataQueryResponse = { data : [ expectedFrame ] } ;
2022-05-11 02:29:04 -05:00
const result = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : LOKI_EXPR ,
} ,
] ,
[ ]
) ;
2022-03-04 02:42:18 -06:00
expect ( result ) . toEqual ( expected ) ;
} ) ;
2022-05-11 02:29:04 -05:00
2022-05-12 01:56:09 -05:00
it ( 'applies maxLines correctly' , ( ) = > {
const response : DataQueryResponse = { data : [ cloneDeep ( inputFrame ) ] } ;
const frame1 : DataFrame = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : LOKI_EXPR ,
} ,
] ,
[ ]
) . data [ 0 ] ;
expect ( frame1 . meta ? . limit ) . toBeUndefined ( ) ;
const frame2 = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : LOKI_EXPR ,
maxLines : 42 ,
} ,
] ,
[ ]
) . data [ 0 ] ;
expect ( frame2 . meta ? . limit ) . toBe ( 42 ) ;
} ) ;
2022-05-11 02:29:04 -05:00
it ( 'processed derived fields correctly' , ( ) = > {
const input : DataFrame = {
length : 1 ,
fields : [
{
name : 'time' ,
config : { } ,
values : new ArrayVector ( [ 1 ] ) ,
type : FieldType . time ,
} ,
{
name : 'line' ,
config : { } ,
values : new ArrayVector ( [ 'line1' ] ) ,
type : FieldType . string ,
} ,
] ,
} ;
const response : DataQueryResponse = { data : [ input ] } ;
const result = transformBackendResult (
response ,
[ { refId : 'A' , expr : '' } ] ,
[
{
matcherRegex : 'trace=(w+)' ,
name : 'derived1' ,
url : 'example.com' ,
} ,
]
) ;
expect (
result . data [ 0 ] . fields . filter ( ( field : Field ) = > field . name === 'derived1' && field . type === 'string' ) . length
) . toBe ( 1 ) ;
} ) ;
2022-05-16 01:29:46 -05:00
it ( 'handle loki parsing errors' , ( ) = > {
const clonedFrame = cloneDeep ( inputFrame ) ;
clonedFrame . fields [ 2 ] = {
name : 'labels' ,
type : FieldType . string ,
config : { } ,
values : new ArrayVector ( [
{ level : 'info' , code : '41🌙' , __error__ : 'LogfmtParserErr' } ,
{ level : 'error' , code : '41🌙' } ,
] ) ,
} ;
const response : DataQueryResponse = { data : [ clonedFrame ] } ;
const result = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : LOKI_EXPR ,
} ,
] ,
[ ]
) ;
expect ( result . data [ 0 ] ? . meta ? . custom ? . error ) . toBe ( 'Error when parsing some of the logs' ) ;
} ) ;
2022-06-08 08:27:58 -05:00
it ( 'improve loki escaping error message when query contains escape' , ( ) = > {
const response : DataQueryResponse = {
data : [ ] ,
error : {
refId : 'A' ,
message : 'parse error at line 1, col 2: invalid char escape' ,
} ,
} ;
const result = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : '{place="g\\arden"}' ,
} ,
] ,
[ ]
) ;
expect ( result . error ? . message ) . toBe (
` parse error at line 1, col 2: invalid char escape. Make sure that all special characters are escaped with \\ . For more information on escaping of special characters visit LogQL documentation at https://grafana.com/docs/loki/latest/logql/. `
) ;
} ) ;
it ( 'do not change loki escaping error message when query does not contain escape' , ( ) = > {
const response : DataQueryResponse = {
data : [ ] ,
error : {
refId : 'A' ,
message : 'parse error at line 1, col 2: invalid char escape' ,
} ,
} ;
const result = transformBackendResult (
response ,
[
{
refId : 'A' ,
expr : '{place="garden"}' ,
} ,
] ,
[ ]
) ;
expect ( result . error ? . message ) . toBe ( 'parse error at line 1, col 2: invalid char escape' ) ;
} ) ;
2022-03-04 02:42:18 -06:00
} ) ;