From ae05c6180c0681d8eda15763dbf0e0102de2e82b Mon Sep 17 00:00:00 2001 From: Sven Grossmann Date: Thu, 15 Dec 2022 09:59:50 +0100 Subject: [PATCH] Loki/ES: Add further items to query tracking (#60347) * add more tracking to queries from ES and Loki * improve tracking elasticsearch * update type assertion * remove unused import --- .../datasource/elasticsearch/datasource.ts | 6 +++-- .../datasource/elasticsearch/tracking.ts | 15 ++++++++--- .../app/plugins/datasource/loki/datasource.ts | 5 ++-- .../app/plugins/datasource/loki/tracking.ts | 27 ++++++++++++++++--- 4 files changed, 43 insertions(+), 10 deletions(-) diff --git a/public/app/plugins/datasource/elasticsearch/datasource.ts b/public/app/plugins/datasource/elasticsearch/datasource.ts index 49e775194c9..bc3dd846317 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.ts +++ b/public/app/plugins/datasource/elasticsearch/datasource.ts @@ -638,7 +638,8 @@ export class ElasticDatasource const shouldRunTroughBackend = request.app === CoreApp.Explore && config.featureToggles.elasticsearchBackendMigration; if (shouldRunTroughBackend) { - return super.query(request).pipe(tap((response) => trackQuery(response, request.targets, request.app))); + const start = new Date(); + return super.query(request).pipe(tap((response) => trackQuery(response, request, start))); } let payload = ''; const targets = this.interpolateVariablesInQueries(cloneDeep(request.targets), request.scopedVars); @@ -705,6 +706,7 @@ export class ElasticDatasource const url = this.getMultiSearchUrl(); + const start = new Date(); return this.post(url, payload).pipe( map((res) => { const er = new ElasticResponse(sentTargets, res); @@ -721,7 +723,7 @@ export class ElasticDatasource return er.getTimeSeries(); }), - tap((response) => trackQuery(response, request.targets, request.app)) + tap((response) => trackQuery(response, request, start)) ); } diff --git a/public/app/plugins/datasource/elasticsearch/tracking.ts b/public/app/plugins/datasource/elasticsearch/tracking.ts index 733d946eba7..ac14a4a1ed1 100644 --- a/public/app/plugins/datasource/elasticsearch/tracking.ts +++ b/public/app/plugins/datasource/elasticsearch/tracking.ts @@ -1,5 +1,5 @@ -import { CoreApp, DashboardLoadedEvent, DataQueryResponse } from '@grafana/data'; -import { reportInteraction } from '@grafana/runtime'; +import { CoreApp, DashboardLoadedEvent, DataQueryRequest, DataQueryResponse } from '@grafana/data'; +import { config, reportInteraction } from '@grafana/runtime'; import { variableRegex } from 'app/features/variables/utils'; import { REF_ID_STARTER_LOG_VOLUME } from './datasource'; @@ -110,7 +110,12 @@ const shouldNotReportBasedOnRefId = (refId: string): boolean => { return false; }; -export function trackQuery(response: DataQueryResponse, queries: ElasticsearchQuery[], app: string): void { +export function trackQuery( + response: DataQueryResponse, + request: DataQueryRequest & { targets: ElasticsearchQuery[] }, + startTime: Date +): void { + const { targets: queries, app } = request; if (app === CoreApp.Dashboard || app === CoreApp.PanelViewer) { return; } @@ -121,6 +126,7 @@ export function trackQuery(response: DataQueryResponse, queries: ElasticsearchQu } reportInteraction('grafana_elasticsearch_query_executed', { app, + grafana_version: config.buildInfo.version, with_lucene_query: query.query ? true : false, query_type: getQueryType(query), line_limit: getLineLimit(query), @@ -128,6 +134,9 @@ export function trackQuery(response: DataQueryResponse, queries: ElasticsearchQu has_error: response.error !== undefined, has_data: response.data.some((frame) => frame.length > 0), simultaneously_sent_query_count: queries.length, + time_range_from: request?.range?.from?.toISOString(), + time_range_to: request?.range?.to?.toISOString(), + time_taken: Date.now() - startTime.getTime(), }); } } diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 17de51538eb..890e4eba390 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -170,7 +170,7 @@ export class LokiDatasource .map(getNormalizedLokiQuery) // "fix" the `.queryType` prop .map((q) => ({ ...q, maxLines: q.maxLines || this.maxLines })); // set maxLines if not set - const fixedRequest = { + const fixedRequest: DataQueryRequest & { targets: LokiQuery[] } = { ...request, targets: queries, }; @@ -197,12 +197,13 @@ export class LokiDatasource if (fixedRequest.liveStreaming) { return this.runLiveQueryThroughBackend(fixedRequest); } else { + const startTime = new Date(); return super.query(fixedRequest).pipe( // in case of an empty query, this is somehow run twice. `share()` is no workaround here as the observable is generated from `of()`. map((response) => transformBackendResult(response, fixedRequest.targets, this.instanceSettings.jsonData.derivedFields ?? []) ), - tap((response) => trackQuery(response, fixedRequest.targets, fixedRequest.app)) + tap((response) => trackQuery(response, fixedRequest, startTime)) ); } } diff --git a/public/app/plugins/datasource/loki/tracking.ts b/public/app/plugins/datasource/loki/tracking.ts index eb3eaf4c233..37237178221 100644 --- a/public/app/plugins/datasource/loki/tracking.ts +++ b/public/app/plugins/datasource/loki/tracking.ts @@ -1,5 +1,5 @@ -import { CoreApp, DashboardLoadedEvent, DataQueryResponse } from '@grafana/data'; -import { reportInteraction } from '@grafana/runtime'; +import { CoreApp, DashboardLoadedEvent, DataQueryRequest, DataQueryResponse } from '@grafana/data'; +import { reportInteraction, config } from '@grafana/runtime'; import { variableRegex } from 'app/features/variables/utils'; import { QueryEditorMode } from '../prometheus/querybuilder/shared/types'; @@ -132,18 +132,35 @@ const shouldNotReportBasedOnRefId = (refId: string): boolean => { return false; }; -export function trackQuery(response: DataQueryResponse, queries: LokiQuery[], app: string): void { +export function trackQuery( + response: DataQueryResponse, + request: DataQueryRequest & { targets: LokiQuery[] }, + startTime: Date +): void { // We only want to track usage for these specific apps + const { app, targets: queries } = request; + if (app === CoreApp.Dashboard || app === CoreApp.PanelViewer) { return; } + let totalBytes = 0; + for (const frame of response.data) { + const byteKey = frame.meta?.custom?.lokiQueryStatKey; + if (byteKey) { + totalBytes += + frame.meta?.stats?.find((stat: { displayName: string }) => stat.displayName === byteKey)?.value ?? 0; + } + } + for (const query of queries) { if (shouldNotReportBasedOnRefId(query.refId)) { return; } + reportInteraction('grafana_loki_query_executed', { app, + grafana_version: config.buildInfo.version, editor_mode: query.editorMode, has_data: response.data.some((frame) => frame.length > 0), has_error: response.error !== undefined, @@ -154,6 +171,10 @@ export function trackQuery(response: DataQueryResponse, queries: LokiQuery[], ap query_vector_type: query.queryType, resolution: query.resolution, simultaneously_sent_query_count: queries.length, + time_range_from: request?.range?.from?.toISOString(), + time_range_to: request?.range?.to?.toISOString(), + time_taken: Date.now() - startTime.getTime(), + bytes_processed: totalBytes, }); } }