mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Logs Panel: Generate valid logQL for multi-select template variable (#20200)
This commit is contained in:
parent
0f709cffbc
commit
08f7edbf5a
@ -4,6 +4,7 @@ import { getQueryOptions } from 'test/helpers/getQueryOptions';
|
|||||||
import { AnnotationQueryRequest, DataSourceApi, DataFrame, dateTime } from '@grafana/data';
|
import { AnnotationQueryRequest, DataSourceApi, DataFrame, dateTime } from '@grafana/data';
|
||||||
import { BackendSrv } from 'app/core/services/backend_srv';
|
import { BackendSrv } from 'app/core/services/backend_srv';
|
||||||
import { TemplateSrv } from 'app/features/templating/template_srv';
|
import { TemplateSrv } from 'app/features/templating/template_srv';
|
||||||
|
import { CustomVariable } from 'app/features/templating/custom_variable';
|
||||||
|
|
||||||
describe('LokiDatasource', () => {
|
describe('LokiDatasource', () => {
|
||||||
const instanceSettings: any = {
|
const instanceSettings: any = {
|
||||||
@ -80,6 +81,54 @@ describe('LokiDatasource', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('When interpolating variables', () => {
|
||||||
|
let ds: any = {};
|
||||||
|
let variable: any = {};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
const customData = { ...(instanceSettings.jsonData || {}), maxLines: 20 };
|
||||||
|
const customSettings = { ...instanceSettings, jsonData: customData };
|
||||||
|
ds = new LokiDatasource(customSettings, backendSrv, templateSrvMock);
|
||||||
|
variable = new CustomVariable({}, {} as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should only escape single quotes', () => {
|
||||||
|
expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", variable)).toEqual("abc\\\\'$^*{}[]+?.()|");
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a number', () => {
|
||||||
|
expect(ds.interpolateQueryExpr(1000, variable)).toEqual(1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and variable allows multi-value', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
variable.multi = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should regex escape values if the value is a string', () => {
|
||||||
|
expect(ds.interpolateQueryExpr('looking*glass', variable)).toEqual('looking\\\\*glass');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return pipe separated values if the value is an array of strings', () => {
|
||||||
|
expect(ds.interpolateQueryExpr(['a|bc', 'de|f'], variable)).toEqual('a\\\\|bc|de\\\\|f');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('and variable allows all', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
variable.includeAll = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should regex escape values if the array is a string', () => {
|
||||||
|
expect(ds.interpolateQueryExpr('looking*glass', variable)).toEqual('looking\\\\*glass');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return pipe separated values if the value is an array of strings', () => {
|
||||||
|
expect(ds.interpolateQueryExpr(['a|bc', 'de|f'], variable)).toEqual('a\\\\|bc|de\\\\|f');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('when performing testDataSource', () => {
|
describe('when performing testDataSource', () => {
|
||||||
let ds: DataSourceApi<any, any>;
|
let ds: DataSourceApi<any, any>;
|
||||||
let result: any;
|
let result: any;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Libraries
|
// Libraries
|
||||||
import { isEmpty, isString, fromPairs } from 'lodash';
|
import { isEmpty, isString, fromPairs, map as lodashMap } from 'lodash';
|
||||||
// Services & Utils
|
// Services & Utils
|
||||||
import {
|
import {
|
||||||
dateMath,
|
dateMath,
|
||||||
@ -88,7 +88,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepareLiveTarget(target: LokiQuery, options: DataQueryRequest<LokiQuery>): LiveTarget {
|
prepareLiveTarget(target: LokiQuery, options: DataQueryRequest<LokiQuery>): LiveTarget {
|
||||||
const interpolated = this.templateSrv.replace(target.expr);
|
const interpolated = this.templateSrv.replace(target.expr, {}, this.interpolateQueryExpr);
|
||||||
const { query, regexp } = parseQuery(interpolated);
|
const { query, regexp } = parseQuery(interpolated);
|
||||||
const refId = target.refId;
|
const refId = target.refId;
|
||||||
const baseUrl = this.instanceSettings.url;
|
const baseUrl = this.instanceSettings.url;
|
||||||
@ -105,7 +105,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepareQueryTarget(target: LokiQuery, options: DataQueryRequest<LokiQuery>) {
|
prepareQueryTarget(target: LokiQuery, options: DataQueryRequest<LokiQuery>) {
|
||||||
const interpolated = this.templateSrv.replace(target.expr);
|
const interpolated = this.templateSrv.replace(target.expr, {}, this.interpolateQueryExpr);
|
||||||
const { query, regexp } = parseQuery(interpolated);
|
const { query, regexp } = parseQuery(interpolated);
|
||||||
const start = this.getTime(options.range.from, false);
|
const start = this.getTime(options.range.from, false);
|
||||||
const end = this.getTime(options.range.to, true);
|
const end = this.getTime(options.range.to, true);
|
||||||
@ -126,7 +126,6 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|||||||
message: (err && err.statusText) || 'Unknown error during query transaction. Please check JS console logs.',
|
message: (err && err.statusText) || 'Unknown error during query transaction. Please check JS console logs.',
|
||||||
refId: target.refId,
|
refId: target.refId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (err.data) {
|
if (err.data) {
|
||||||
if (typeof err.data === 'string') {
|
if (typeof err.data === 'string') {
|
||||||
error.message = err.data;
|
error.message = err.data;
|
||||||
@ -239,7 +238,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|||||||
const expandedQuery = {
|
const expandedQuery = {
|
||||||
...query,
|
...query,
|
||||||
datasource: this.name,
|
datasource: this.name,
|
||||||
expr: this.templateSrv.replace(query.expr),
|
expr: this.templateSrv.replace(query.expr, {}, this.interpolateQueryExpr),
|
||||||
};
|
};
|
||||||
return expandedQuery;
|
return expandedQuery;
|
||||||
});
|
});
|
||||||
@ -260,6 +259,20 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interpolateQueryExpr(value: any, variable: any) {
|
||||||
|
// if no multi or include all do not regexEscape
|
||||||
|
if (!variable.multi && !variable.includeAll) {
|
||||||
|
return lokiRegularEscape(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return lokiSpecialRegexEscape(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const escapedValues = lodashMap(value, lokiSpecialRegexEscape);
|
||||||
|
return escapedValues.join('|');
|
||||||
|
}
|
||||||
|
|
||||||
modifyQuery(query: LokiQuery, action: any): LokiQuery {
|
modifyQuery(query: LokiQuery, action: any): LokiQuery {
|
||||||
const parsed = parseQuery(query.expr || '');
|
const parsed = parseQuery(query.expr || '');
|
||||||
let { query: selector } = parsed;
|
let { query: selector } = parsed;
|
||||||
@ -481,4 +494,18 @@ function queryRequestFromAnnotationOptions(options: AnnotationQueryRequest<LokiQ
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function lokiRegularEscape(value: any) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return value.replace(/'/g, "\\\\'");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function lokiSpecialRegexEscape(value: any) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return lokiRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&'));
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
export default LokiDatasource;
|
export default LokiDatasource;
|
||||||
|
Loading…
Reference in New Issue
Block a user