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

pull/20215/head
Ivana Huckova 6 years ago committed by GitHub
parent 0f709cffbc
commit 08f7edbf5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      public/app/plugins/datasource/loki/datasource.test.ts
  2. 37
      public/app/plugins/datasource/loki/datasource.ts

@ -4,6 +4,7 @@ import { getQueryOptions } from 'test/helpers/getQueryOptions';
import { AnnotationQueryRequest, DataSourceApi, DataFrame, dateTime } from '@grafana/data';
import { BackendSrv } from 'app/core/services/backend_srv';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { CustomVariable } from 'app/features/templating/custom_variable';
describe('LokiDatasource', () => {
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', () => {
let ds: DataSourceApi<any, any>;
let result: any;

@ -1,5 +1,5 @@
// Libraries
import { isEmpty, isString, fromPairs } from 'lodash';
import { isEmpty, isString, fromPairs, map as lodashMap } from 'lodash';
// Services & Utils
import {
dateMath,
@ -88,7 +88,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
}
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 refId = target.refId;
const baseUrl = this.instanceSettings.url;
@ -105,7 +105,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
}
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 start = this.getTime(options.range.from, false);
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.',
refId: target.refId,
};
if (err.data) {
if (typeof err.data === 'string') {
error.message = err.data;
@ -239,7 +238,7 @@ export class LokiDatasource extends DataSourceApi<LokiQuery, LokiOptions> {
const expandedQuery = {
...query,
datasource: this.name,
expr: this.templateSrv.replace(query.expr),
expr: this.templateSrv.replace(query.expr, {}, this.interpolateQueryExpr),
};
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 {
const parsed = parseQuery(query.expr || '');
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;

Loading…
Cancel
Save