Loki: Track obfuscated query (#61325)

* obfuscate query

* also conver numbers and comments

* query obfuscation: simplify obfuscation and keep some identifiers

* Query obfuscation: replace placeholder string with node name

Co-authored-by: Matias Chomicki <matyax@gmail.com>
matyax/snapping-test
Sven Grossmann 2 years ago committed by GitHub
parent ce3a96abec
commit 5fe23b4964
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      public/app/plugins/datasource/loki/queryUtils.test.ts
  2. 16
      public/app/plugins/datasource/loki/queryUtils.ts
  3. 3
      public/app/plugins/datasource/loki/tracking.ts

@ -7,6 +7,7 @@ import {
isValidQuery,
parseToNodeNamesArray,
getParserFromQuery,
obfuscate,
} from './queryUtils';
import { LokiQuery, LokiQueryType } from './types';
@ -168,7 +169,7 @@ describe('isValidQuery', () => {
});
});
describe('parseToArray', () => {
describe('parseToNodeNamesArray', () => {
it('returns on empty query', () => {
expect(parseToNodeNamesArray('{}')).toEqual(['LogQL', 'Expr', 'LogExpr', 'Selector', '⚠']);
});
@ -201,6 +202,34 @@ describe('parseToArray', () => {
});
});
describe('obfuscate', () => {
it('obfuscates on invalid query', () => {
expect(obfuscate('{job="grafana"')).toEqual('{Identifier=String');
});
it('obfuscates on valid query', () => {
expect(
obfuscate('sum(sum_over_time({test="test"} |= `` | logfmt | __error__=`` | unwrap test | __error__=`` [10m]))')
).toEqual(
'sum(sum_over_time({Identifier=String} |= String | logfmt | __error__=String | unwrap Identifier | __error__=String [10m]))'
);
});
it('obfuscates on arithmetic operation', () => {
expect(obfuscate('2 + 3')).toEqual('Number + Number');
});
it('obfuscates a comment', () => {
expect(obfuscate('{job="grafana"} # test comment')).toEqual('{Identifier=String} LineComment');
});
it('does not obfuscate interval variables', () => {
expect(
obfuscate(
'sum(quantile_over_time(0.5, {label="$var"} | logfmt | __error__=`` | unwrap latency | __error__=`` [$__interval]))'
)
).toEqual(
'sum(quantile_over_time(Number, {Identifier=String} | logfmt | __error__=String | unwrap Identifier | __error__=String [$__interval]))'
);
});
});
describe('isLogsQuery', () => {
it('returns false if metrics query', () => {
expect(isLogsQuery('rate({job="grafana"}[5m])')).toBe(false);

@ -108,6 +108,22 @@ export function getNormalizedLokiQuery(query: LokiQuery): LokiQuery {
return { ...rest, queryType: LokiQueryType.Range };
}
const tagsToObscure = ['String', 'Identifier', 'LineComment', 'Number'];
const partsToKeep = ['__error__', '__interval', '__interval_ms'];
export function obfuscate(query: string): string {
let obfuscatedQuery: string = query;
const tree = parser.parse(query);
tree.iterate({
enter: ({ name, from, to }): false | void => {
const queryPart = query.substring(from, to);
if (tagsToObscure.includes(name) && !partsToKeep.includes(queryPart)) {
obfuscatedQuery = obfuscatedQuery.replace(queryPart, name);
}
},
});
return obfuscatedQuery;
}
export function parseToNodeNamesArray(query: string): string[] {
const queryParts: string[] = [];
const tree = parser.parse(query);

@ -11,7 +11,7 @@ import {
REF_ID_STARTER_LOG_VOLUME,
} from './datasource';
import pluginJson from './plugin.json';
import { getNormalizedLokiQuery, isLogsQuery, parseToNodeNamesArray } from './queryUtils';
import { getNormalizedLokiQuery, isLogsQuery, obfuscate, parseToNodeNamesArray } from './queryUtils';
import { LokiQuery, LokiQueryType } from './types';
type LokiOnDashboardLoadedTrackingEvent = {
@ -167,6 +167,7 @@ export function trackQuery(
legend: query.legendFormat,
line_limit: query.maxLines,
parsed_query: parseToNodeNamesArray(query.expr).join(','),
obfuscated_query: obfuscate(query.expr),
query_type: isLogsQuery(query.expr) ? 'logs' : 'metric',
query_vector_type: query.queryType,
resolution: query.resolution,

Loading…
Cancel
Save