Logs Panel: Generate valid logQL for multi-select template variable (#20200)

This commit is contained in:
Ivana Huckova 2019-11-06 17:29:44 +01:00 committed by GitHub
parent 0f709cffbc
commit 08f7edbf5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 5 deletions

View File

@ -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;

View File

@ -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;