loki: run some queries through the backend (#44729)

This commit is contained in:
Gábor Farkas 2022-02-07 08:43:48 +01:00 committed by GitHub
parent 3a2e3267ba
commit 560c773905
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 10 deletions

View File

@ -29,6 +29,7 @@ export interface FeatureToggles {
tempoSearch?: boolean; tempoSearch?: boolean;
tempoBackendSearch?: boolean; tempoBackendSearch?: boolean;
tempoServiceGraph?: boolean; tempoServiceGraph?: boolean;
lokiBackendMode?: boolean;
fullRangeLogsVolume?: boolean; fullRangeLogsVolume?: boolean;
accesscontrol?: boolean; accesscontrol?: boolean;
prometheus_azure_auth?: boolean; prometheus_azure_auth?: boolean;

View File

@ -72,6 +72,12 @@ var (
State: FeatureStateBeta, State: FeatureStateBeta,
FrontendOnly: true, FrontendOnly: true,
}, },
{
Name: "lokiBackendMode",
Description: "Loki datasource works as backend datasource",
State: FeatureStateAlpha,
FrontendOnly: true,
},
{ {
Name: "fullRangeLogsVolume", Name: "fullRangeLogsVolume",
Description: "Show full range logs volume in explore", Description: "Show full range logs volume in explore",

View File

@ -55,6 +55,10 @@ const (
// show service // show service
FlagTempoServiceGraph = "tempoServiceGraph" FlagTempoServiceGraph = "tempoServiceGraph"
// FlagLokiBackendMode
// Loki datasource works as backend datasource
FlagLokiBackendMode = "lokiBackendMode"
// FlagFullRangeLogsVolume // FlagFullRangeLogsVolume
// Show full range logs volume in explore // Show full range logs volume in explore
FlagFullRangeLogsVolume = "fullRangeLogsVolume" FlagFullRangeLogsVolume = "fullRangeLogsVolume"

View File

@ -8,12 +8,12 @@ import Prism from 'prismjs';
import { import {
AnnotationEvent, AnnotationEvent,
AnnotationQueryRequest, AnnotationQueryRequest,
CoreApp,
DataFrame, DataFrame,
DataFrameView, DataFrameView,
DataQueryError, DataQueryError,
DataQueryRequest, DataQueryRequest,
DataQueryResponse, DataQueryResponse,
DataSourceApi,
DataSourceInstanceSettings, DataSourceInstanceSettings,
DataSourceWithLogsContextSupport, DataSourceWithLogsContextSupport,
DataSourceWithLogsVolumeSupport, DataSourceWithLogsVolumeSupport,
@ -33,7 +33,7 @@ import {
ScopedVars, ScopedVars,
TimeRange, TimeRange,
} from '@grafana/data'; } from '@grafana/data';
import { BackendSrvRequest, FetchError, getBackendSrv } from '@grafana/runtime'; import { BackendSrvRequest, FetchError, getBackendSrv, DataSourceWithBackend } from '@grafana/runtime';
import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv'; import { getTemplateSrv, TemplateSrv } from 'app/features/templating/template_srv';
import { addLabelToQuery } from './add_label_to_query'; import { addLabelToQuery } from './add_label_to_query';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
@ -44,7 +44,7 @@ import {
lokiStreamsToDataFrames, lokiStreamsToDataFrames,
processRangeQueryResponse, processRangeQueryResponse,
} from './result_transformer'; } from './result_transformer';
import { addParsedLabelToQuery, queryHasPipeParser } from './query_utils'; import { addParsedLabelToQuery, getNormalizedLokiQuery, queryHasPipeParser } from './query_utils';
import { import {
LokiOptions, LokiOptions,
@ -86,7 +86,7 @@ const DEFAULT_QUERY_PARAMS: Partial<LokiRangeQueryRequest> = {
}; };
export class LokiDatasource export class LokiDatasource
extends DataSourceApi<LokiQuery, LokiOptions> extends DataSourceWithBackend<LokiQuery, LokiOptions>
implements implements
DataSourceWithLogsContextSupport, DataSourceWithLogsContextSupport,
DataSourceWithLogsVolumeSupport<LokiQuery>, DataSourceWithLogsVolumeSupport<LokiQuery>,
@ -157,13 +157,37 @@ export class LokiDatasource
}); });
} }
query(options: DataQueryRequest<LokiQuery>): Observable<DataQueryResponse> { query(request: DataQueryRequest<LokiQuery>): Observable<DataQueryResponse> {
const subQueries: Array<Observable<DataQueryResponse>> = []; const subQueries: Array<Observable<DataQueryResponse>> = [];
const scopedVars = { const scopedVars = {
...options.scopedVars, ...request.scopedVars,
...this.getRangeScopedVars(options.range), ...this.getRangeScopedVars(request.range),
}; };
const filteredTargets = options.targets
// if all these are true, run query through backend:
// - feature-flag is enabled
// - we are in explore-mode
// - for every query it is true that:
// - query is range query
// - and query is metric query
// - and query is not a log-volume-query (those need a custom http header)
const shouldRunBackendQuery =
config.featureToggles.lokiBackendMode &&
request.app === CoreApp.Explore &&
request.targets.every(
(query) => query.queryType === LokiQueryType.Range && isMetricsQuery(query.expr) && !query.volumeQuery
);
if (shouldRunBackendQuery) {
// we "fix" the loki queries to have `.queryType` and not have `.instant` and `.range`
const fixedRequest = {
...request,
targets: request.targets.map(getNormalizedLokiQuery),
};
return super.query(fixedRequest);
}
const filteredTargets = request.targets
.filter((target) => target.expr && !target.hide) .filter((target) => target.expr && !target.hide)
.map((target) => { .map((target) => {
const expr = this.addAdHocFilters(target.expr); const expr = this.addAdHocFilters(target.expr);
@ -175,9 +199,9 @@ export class LokiDatasource
for (const target of filteredTargets) { for (const target of filteredTargets) {
if (target.instant || target.queryType === LokiQueryType.Instant) { if (target.instant || target.queryType === LokiQueryType.Instant) {
subQueries.push(this.runInstantQuery(target, options, filteredTargets.length)); subQueries.push(this.runInstantQuery(target, request, filteredTargets.length));
} else { } else {
subQueries.push(this.runRangeQuery(target, options, filteredTargets.length)); subQueries.push(this.runRangeQuery(target, request, filteredTargets.length));
} }
} }
@ -755,6 +779,26 @@ export class LokiDatasource
} }
} }
// Used when running queries through backend
filterQuery(query: LokiQuery): boolean {
if (query.hide || query.expr === '') {
return false;
}
return true;
}
// Used when running queries through backend
applyTemplateVariables(target: LokiQuery, scopedVars: ScopedVars): Record<string, any> {
// We want to interpolate these variables on backend
const { __interval, __interval_ms, ...rest } = scopedVars;
return {
...target,
legendFormat: this.templateSrv.replace(target.legendFormat, rest),
expr: this.templateSrv.replace(target.expr, rest, this.interpolateQueryExpr),
};
}
interpolateString(string: string) { interpolateString(string: string) {
return this.templateSrv.replace(string, undefined, this.interpolateQueryExpr); return this.templateSrv.replace(string, undefined, this.interpolateQueryExpr);
} }