grafana/public/app/plugins/datasource/loki/queryUtils.ts

392 lines
10 KiB
TypeScript
Raw Normal View History

import { SyntaxNode } from '@lezer/common';
import { escapeRegExp } from 'lodash';
import {
ArrayVector,
DataFrame,
DataQueryResponse,
DataQueryResponseData,
Field,
QueryResultMetaStat,
} from '@grafana/data';
import {
parser,
LineFilter,
PipeExact,
PipeMatch,
Filter,
String,
LabelFormatExpr,
Selector,
PipelineExpr,
LabelParser,
JsonExpressionParser,
LabelFilter,
MetricExpr,
Matcher,
Identifier,
} from '@grafana/lezer-logql';
import { ErrorId } from '../prometheus/querybuilder/shared/parsingUtils';
import { getStreamSelectorPositions } from './modifyQuery';
import { LokiQuery, LokiQueryType } from './types';
export function formatQuery(selector: string | undefined): string {
return `${selector || ''}`.trim();
}
/**
* Returns search terms from a LogQL query.
* E.g., `{} |= foo |=bar != baz` returns `['foo', 'bar']`.
*/
export function getHighlighterExpressionsFromQuery(input: string): string[] {
const results = [];
const tree = parser.parse(input);
const filters: SyntaxNode[] = [];
tree.iterate({
enter: ({ type, node }): void => {
if (type.id === LineFilter) {
filters.push(node);
}
},
});
for (let filter of filters) {
const pipeExact = filter.getChild(Filter)?.getChild(PipeExact);
const pipeMatch = filter.getChild(Filter)?.getChild(PipeMatch);
const string = filter.getChild(String);
if ((!pipeExact && !pipeMatch) || !string) {
continue;
}
const filterTerm = input.substring(string.from, string.to).trim();
const backtickedTerm = filterTerm[0] === '`';
const unwrappedFilterTerm = filterTerm.substring(1, filterTerm.length - 1);
if (!unwrappedFilterTerm) {
continue;
}
let resultTerm = '';
// Only filter expressions with |~ operator are treated as regular expressions
if (pipeMatch) {
// When using backticks, Loki doesn't require to escape special characters and we can just push regular expression to highlights array
// When using quotes, we have extra backslash escaping and we need to replace \\ with \
resultTerm = backtickedTerm ? unwrappedFilterTerm : unwrappedFilterTerm.replace(/\\\\/g, '\\');
} else {
// We need to escape this string so it is not matched as regular expression
resultTerm = escapeRegExp(unwrappedFilterTerm);
}
if (resultTerm) {
results.push(resultTerm);
}
}
return results;
}
// we are migrating from `.instant` and `.range` to `.queryType`
// this function returns a new query object that:
// - has `.queryType`
// - does not have `.instant`
// - does not have `.range`
export function getNormalizedLokiQuery(query: LokiQuery): LokiQuery {
// if queryType field contains invalid data we behave as if the queryType is empty
const { queryType } = query;
const hasValidQueryType =
queryType === LokiQueryType.Range || queryType === LokiQueryType.Instant || queryType === LokiQueryType.Stream;
// if queryType exists, it is respected
if (hasValidQueryType) {
const { instant, range, ...rest } = query;
return rest;
}
// if no queryType, and instant===true, it's instant
if (query.instant === true) {
const { instant, range, ...rest } = query;
return { ...rest, queryType: LokiQueryType.Instant };
}
// otherwise it is range
const { instant, range, ...rest } = query;
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);
tree.iterate({
enter: ({ name }): false | void => {
queryParts.push(name);
},
});
return queryParts;
}
export function isValidQuery(query: string): boolean {
let isValid = true;
const tree = parser.parse(query);
tree.iterate({
enter: ({ type }): false | void => {
if (type.id === ErrorId) {
isValid = false;
}
},
});
return isValid;
}
export function isLogsQuery(query: string): boolean {
let isLogsQuery = true;
const tree = parser.parse(query);
tree.iterate({
enter: ({ type }): false | void => {
if (type.id === MetricExpr) {
isLogsQuery = false;
}
},
});
return isLogsQuery;
}
export function isQueryWithParser(query: string): { queryWithParser: boolean; parserCount: number } {
let parserCount = 0;
const tree = parser.parse(query);
tree.iterate({
enter: ({ type }): false | void => {
if (type.id === LabelParser || type.id === JsonExpressionParser) {
parserCount++;
}
},
});
return { queryWithParser: parserCount > 0, parserCount };
}
Loki Query Editor: Autocompletion and suggestions improvements (unwrap, parser, extracted labels) (#59103) * Chore: refactor test to improve internal categorization of scenarios * feat(loki-monaco-unwrap): add unwrap situation support * Chore: remove redundant path from aggregation situation * feat(loki-monaco-unwrap): add unwrap suggestions * feat(loki-monaco-autocomplete): rename IN_DURATION and add missing tests * feat(loki-monaco-autocomplete): detect parser and line filter * feat(loki-monaco-autocomplete): optionally suggest line filters and parsers * feat(loki-monaco-autocomplete): improve suggestions and update completions tests * feat(loki-monaco-autocomplete): allow for multiple line filters suggestions * Chore: update situations test * Chore: add test case for AFTER_UNWRAP completion * feat(loki-monaco-autocomplete): use logs query instead of labels for data sample * Chore: improve getParser function name and add tests * Chore: update test mock data * Update public/app/plugins/datasource/loki/components/monaco-query-field/monaco-completion-provider/situation.test.ts Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> * feat(loki-monaco-autocomplete): improve after unwrap detection * feat(loki-monaco-autocomplete): remove leftover parser detection * Chore: completely remove parser suggestion exclusion implementation It was correct to have more than one parser, so we don't need to exclude parsers if one is present. Co-authored-by: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com>
2022-12-14 10:37:08 -06:00
export function getParserFromQuery(query: string) {
const tree = parser.parse(query);
let logParser;
tree.iterate({
enter: (node: SyntaxNode): false | void => {
if (node.type.id === LabelParser || node.type.id === JsonExpressionParser) {
logParser = query.substring(node.from, node.to).trim();
return false;
}
},
});
return logParser;
}
export function isQueryPipelineErrorFiltering(query: string): boolean {
let isQueryPipelineErrorFiltering = false;
const tree = parser.parse(query);
tree.iterate({
enter: ({ type, node }): false | void => {
if (type.id === LabelFilter) {
const label = node.getChild(Matcher)?.getChild(Identifier);
if (label) {
const labelName = query.substring(label.from, label.to);
if (labelName === '__error__') {
isQueryPipelineErrorFiltering = true;
}
}
}
},
});
return isQueryPipelineErrorFiltering;
}
export function isQueryWithLabelFormat(query: string): boolean {
let queryWithLabelFormat = false;
const tree = parser.parse(query);
tree.iterate({
enter: ({ type }): false | void => {
if (type.id === LabelFormatExpr) {
queryWithLabelFormat = true;
}
},
});
return queryWithLabelFormat;
}
export function getLogQueryFromMetricsQuery(query: string): string {
if (isLogsQuery(query)) {
return query;
}
const tree = parser.parse(query);
// Log query in metrics query composes of Selector & PipelineExpr
let selector = '';
tree.iterate({
enter: ({ type, from, to }): false | void => {
if (type.id === Selector) {
selector = query.substring(from, to);
return false;
}
},
});
let pipelineExpr = '';
tree.iterate({
enter: ({ type, from, to }): false | void => {
if (type.id === PipelineExpr) {
pipelineExpr = query.substring(from, to);
return false;
}
},
});
return selector + pipelineExpr;
}
export function isQueryWithLabelFilter(query: string): boolean {
const tree = parser.parse(query);
let hasLabelFilter = false;
tree.iterate({
enter: ({ type, node }): false | void => {
if (type.id === LabelFilter) {
hasLabelFilter = true;
return;
}
},
});
return hasLabelFilter;
}
export function isQueryWithLineFilter(query: string): boolean {
const tree = parser.parse(query);
let queryWithLineFilter = false;
tree.iterate({
enter: ({ type }): false | void => {
if (type.id === LineFilter) {
queryWithLineFilter = true;
return;
}
},
});
return queryWithLineFilter;
}
export function getStreamSelectorsFromQuery(query: string): string[] {
const labelMatcherPositions = getStreamSelectorPositions(query);
const labelMatchers = labelMatcherPositions.map((labelMatcher) => {
return query.slice(labelMatcher.from, labelMatcher.to);
});
return labelMatchers;
}
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
export function requestSupportsPartitioning(allQueries: LokiQuery[]) {
const queries = allQueries.filter((query) => !query.hide);
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
/*
* For now, we will not split when more than 1 query is requested.
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
*/
if (queries.length > 1) {
return false;
}
if (queries[0].refId.includes('do-not-chunk')) {
return false;
}
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
return true;
}
export function combineResponses(currentResult: DataQueryResponse | null, newResult: DataQueryResponse) {
if (!currentResult) {
return cloneQueryResponse(newResult);
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
}
newResult.data.forEach((newFrame) => {
const currentFrame = currentResult.data.find((frame) => frame.name === newFrame.name);
if (!currentFrame) {
currentResult.data.push(cloneDataFrame(newFrame));
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
return;
}
combineFrames(currentFrame, newFrame);
});
return currentResult;
}
function combineFrames(dest: DataFrame, source: DataFrame) {
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
const totalFields = dest.fields.length;
for (let i = 0; i < totalFields; i++) {
dest.fields[i].values = new ArrayVector(
[].concat.apply(source.fields[i].values.toArray(), dest.fields[i].values.toArray())
);
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
}
dest.length += source.length;
combineMetadata(dest, source);
}
function combineMetadata(dest: DataFrame, source: DataFrame) {
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
if (!source.meta?.stats) {
return;
}
if (!dest.meta?.stats) {
if (!dest.meta) {
dest.meta = {};
}
Object.assign(dest.meta, { stats: source.meta.stats });
return;
}
dest.meta.stats.forEach((destStat: QueryResultMetaStat, i: number) => {
const sourceStat = source.meta?.stats?.find(
Loki Query Splitting: Split queries into sub-queries with smaller time interval (#62767) * Range splitting: range splitting function * Range splitting: experiment with 1 hour splits * Range splitting: reorganize code * Range splitting: improve code readability and meaning * Range splitting: add partition limit to prevent infinite loops * Range splitting: add error handling * Range splitting: disable for logs queries * Range splitting: support any arbitrary time splitting + respect original from/to in the partition * Chore: remove console logs * Chore: delete unused import * Range splitting: actually send requests in sequence * Range splitting: do not split when > 1 query * Range splitting: combine frames * Chore: rename function * split in reverse * polished reversing * keep reference to the right frame in the result * Range splitting: change request state to Streaming * Range splitting: fix moving only 1 unit of time instead of the provided one * Chore: change default parameter to timeShift = 1 * Range splitting: do not split for range queqries * Range splitting: add initial support for log queries * Range splitting: do not use MutableDataFrame It has bad performance and it's not required * Chore: remove unused export * Query Splitting: move to module * loki: split: fix off-by-one error (#62966) loki: split: fix off-by-one loop * Range splitting: disable for logs volume queries * Range splitting: combine any number of fields, not just hardcoded 2 * Range splitting: optimize frame-combining function * Range splitting: further optimize * Range splitting: combine frame length * Range splitting: combine stats * Range splitting: combine stats without assuming the same order * Query splitting: catch and raise errors * Range splitting: create feature flag * Range splitting: implement feature flag * Range splitting: add unit test for datasource query * Range splitting: add basic test for runPartitionedQuery * Range splitting: add unit test for resultLimitReached * Range splitting: test frame merging * Chore: fix unit test --------- Co-authored-by: Sven Grossmann <svennergr@gmail.com> Co-authored-by: Gábor Farkas <gabor.farkas@gmail.com>
2023-02-09 11:27:02 -06:00
(sourceStat: QueryResultMetaStat) => destStat.displayName === sourceStat.displayName
);
if (sourceStat) {
destStat.value += sourceStat.value;
}
});
}
/**
* Deep clones a DataQueryResponse
*/
export function cloneQueryResponse(response: DataQueryResponse): DataQueryResponse {
const newResponse = {
...response,
data: response.data.map(cloneDataFrame),
};
return newResponse;
}
function cloneDataFrame(frame: DataQueryResponseData): DataQueryResponseData {
return {
...frame,
fields: frame.fields.map((field: Field<unknown, ArrayVector>) => ({
...field,
values: new ArrayVector(field.values.buffer),
})),
};
}