From 560c77390550e12e8c0be507c00f27cde0aa31e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Mon, 7 Feb 2022 08:43:48 +0100 Subject: [PATCH] loki: run some queries through the backend (#44729) --- .../src/types/featureToggles.gen.ts | 1 + pkg/services/featuremgmt/registry.go | 6 ++ pkg/services/featuremgmt/toggles_gen.go | 4 ++ .../app/plugins/datasource/loki/datasource.ts | 64 ++++++++++++++++--- 4 files changed, 65 insertions(+), 10 deletions(-) diff --git a/packages/grafana-data/src/types/featureToggles.gen.ts b/packages/grafana-data/src/types/featureToggles.gen.ts index a3f86909bee..a3e25ab89a4 100644 --- a/packages/grafana-data/src/types/featureToggles.gen.ts +++ b/packages/grafana-data/src/types/featureToggles.gen.ts @@ -29,6 +29,7 @@ export interface FeatureToggles { tempoSearch?: boolean; tempoBackendSearch?: boolean; tempoServiceGraph?: boolean; + lokiBackendMode?: boolean; fullRangeLogsVolume?: boolean; accesscontrol?: boolean; prometheus_azure_auth?: boolean; diff --git a/pkg/services/featuremgmt/registry.go b/pkg/services/featuremgmt/registry.go index 9a5a487cbf7..8a4f30a4854 100644 --- a/pkg/services/featuremgmt/registry.go +++ b/pkg/services/featuremgmt/registry.go @@ -72,6 +72,12 @@ var ( State: FeatureStateBeta, FrontendOnly: true, }, + { + Name: "lokiBackendMode", + Description: "Loki datasource works as backend datasource", + State: FeatureStateAlpha, + FrontendOnly: true, + }, { Name: "fullRangeLogsVolume", Description: "Show full range logs volume in explore", diff --git a/pkg/services/featuremgmt/toggles_gen.go b/pkg/services/featuremgmt/toggles_gen.go index 49faad2bd17..b95fddff591 100644 --- a/pkg/services/featuremgmt/toggles_gen.go +++ b/pkg/services/featuremgmt/toggles_gen.go @@ -55,6 +55,10 @@ const ( // show service FlagTempoServiceGraph = "tempoServiceGraph" + // FlagLokiBackendMode + // Loki datasource works as backend datasource + FlagLokiBackendMode = "lokiBackendMode" + // FlagFullRangeLogsVolume // Show full range logs volume in explore FlagFullRangeLogsVolume = "fullRangeLogsVolume" diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 9c14d7a87a0..99e3b8503be 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -8,12 +8,12 @@ import Prism from 'prismjs'; import { AnnotationEvent, AnnotationQueryRequest, + CoreApp, DataFrame, DataFrameView, DataQueryError, DataQueryRequest, DataQueryResponse, - DataSourceApi, DataSourceInstanceSettings, DataSourceWithLogsContextSupport, DataSourceWithLogsVolumeSupport, @@ -33,7 +33,7 @@ import { ScopedVars, TimeRange, } 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 { addLabelToQuery } from './add_label_to_query'; import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv'; @@ -44,7 +44,7 @@ import { lokiStreamsToDataFrames, processRangeQueryResponse, } from './result_transformer'; -import { addParsedLabelToQuery, queryHasPipeParser } from './query_utils'; +import { addParsedLabelToQuery, getNormalizedLokiQuery, queryHasPipeParser } from './query_utils'; import { LokiOptions, @@ -86,7 +86,7 @@ const DEFAULT_QUERY_PARAMS: Partial = { }; export class LokiDatasource - extends DataSourceApi + extends DataSourceWithBackend implements DataSourceWithLogsContextSupport, DataSourceWithLogsVolumeSupport, @@ -157,13 +157,37 @@ export class LokiDatasource }); } - query(options: DataQueryRequest): Observable { + query(request: DataQueryRequest): Observable { const subQueries: Array> = []; const scopedVars = { - ...options.scopedVars, - ...this.getRangeScopedVars(options.range), + ...request.scopedVars, + ...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) .map((target) => { const expr = this.addAdHocFilters(target.expr); @@ -175,9 +199,9 @@ export class LokiDatasource for (const target of filteredTargets) { if (target.instant || target.queryType === LokiQueryType.Instant) { - subQueries.push(this.runInstantQuery(target, options, filteredTargets.length)); + subQueries.push(this.runInstantQuery(target, request, filteredTargets.length)); } 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 { + // 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) { return this.templateSrv.replace(string, undefined, this.interpolateQueryExpr); }