Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prometheus: Incremental querying option for to: now dashboards #62932

Merged
merged 149 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
149 commits
Select commit Hold shift + click to select a range
92db19b
Add first poc of json query transformer
NiklasCi Nov 8, 2022
10deb41
Small fixes
NiklasCi Nov 8, 2022
ddbbbf7
Adapt transformer to real data
NiklasCi Nov 9, 2022
66c1d28
Query on click or on change
NiklasCi Nov 21, 2022
e234d22
Added new extractJSONPath transformer
NiklasCi Nov 28, 2022
1a29d56
Add test for new transformer
NiklasCi Nov 28, 2022
c5c186c
Fixed lint errors of test
NiklasCi Nov 28, 2022
99d252f
Remove unused jsonpath-plus
NiklasCi Nov 28, 2022
d50a843
Merge branch 'main' into feat/json-query-transformer
NiklasCi Nov 28, 2022
51996d1
Fix tests
NiklasCi Nov 28, 2022
cb32446
Merge remote-tracking branch 'upstream/main' into feat/json-query-tra…
NiklasCi Dec 9, 2022
de62d6a
Merge branch 'main' into feat/json-query-transformer
NiklasCi Jan 9, 2023
b54e866
Merge branch 'main' into feat/json-query-transformer
NiklasCi Jan 11, 2023
76fceb4
Added JSONTransformer to ExtractFields Transformer
NiklasCi Jan 11, 2023
24fc89b
Review suggestions
NiklasCi Jan 12, 2023
af61be0
Remove not used id
NiklasCi Jan 12, 2023
a7a9127
updating gdev dashboard to use gdev-testdata datasource
gtk-grafana Jan 12, 2023
b76d105
updating gdev dashboard to use gdev-testdata datasource
gtk-grafana Jan 12, 2023
f58a7e3
add simple extract fields usage
gtk-grafana Jan 12, 2023
e7f5c3c
Merge branch 'gtk-grafana/extract-fields-transformation-gdev-dashbora…
gtk-grafana Jan 12, 2023
628c589
WIP
gtk-grafana Jan 17, 2023
3c4566a
WIP: need whole response
gtk-grafana Jan 18, 2023
1e700de
WIP
gtk-grafana Jan 19, 2023
be42b56
WIP
gtk-grafana Jan 23, 2023
e81b4b0
WIP: first working example
gtk-grafana Jan 24, 2023
9e567a1
temporarily abandoning exemplar support, lots of refactor, cleaning u…
gtk-grafana Jan 26, 2023
1f4cd53
reverting more extra changes before merging main
gtk-grafana Jan 26, 2023
3572858
merge main and resolve conflicts
gtk-grafana Jan 26, 2023
182b402
provide slightly better debug output
gtk-grafana Jan 26, 2023
006f0c5
remove commit from wrong branch
gtk-grafana Jan 26, 2023
19f9197
changes from main
gtk-grafana Jan 26, 2023
c1c9467
undo weird whitespace
gtk-grafana Jan 26, 2023
d06854e
tuck away debugs so we can test performance
gtk-grafana Jan 26, 2023
6b13900
continued refactor, and added initial dataframe backfilling implement…
gtk-grafana Jan 27, 2023
5f270fc
refactor preprocess, fix off by one error somehow
gtk-grafana Jan 30, 2023
34dd4cb
document, refactor, cleanup, still some bugs with switching query int…
gtk-grafana Jan 30, 2023
8c045ef
uhh, changes dissapeared on last commit, committing again?
gtk-grafana Jan 30, 2023
01ca72e
WIP
gtk-grafana Jan 31, 2023
7012e09
Merge remote-tracking branch 'origin/main' into gtk-grafana/streaming…
gtk-grafana Jan 31, 2023
1dfc167
add eviction unit test, add unit test helper functions, add assertion…
gtk-grafana Jan 31, 2023
5a046f7
WIP
gtk-grafana Jan 31, 2023
a1f5b74
make trouble function static, fix warning
gtk-grafana Jan 31, 2023
8d8587f
interpolate variables
gtk-grafana Feb 1, 2023
dad77dd
refactor, rewrite, and optimize merging algorithm
gtk-grafana Feb 1, 2023
c7b3c11
Clean up
gtk-grafana Feb 1, 2023
9582fa6
remove old todos, uneccesary changes, remove type assertions
gtk-grafana Feb 1, 2023
3a9d322
more cleanup and refactor, trying to remove junk data from mock data …
gtk-grafana Feb 1, 2023
a609a2e
refactoring and cleaning up
gtk-grafana Feb 1, 2023
1ed7ad9
refactoring and cleaning up
gtk-grafana Feb 1, 2023
678c859
work on new test case to try to reproduce bug with multiple series wi…
gtk-grafana Feb 1, 2023
0de966a
remove debug flag
gtk-grafana Feb 1, 2023
0e0df9e
fix bug introduced by using the response data to calculate the max nu…
gtk-grafana Feb 2, 2023
028bbb0
Fix problem where time series with missing values sent from the backe…
gtk-grafana Feb 2, 2023
2500eec
add more test cases
gtk-grafana Feb 2, 2023
59cc6de
clean up some prometheus specific refernces, add loki types
gtk-grafana Feb 2, 2023
2b534ec
clean up and misc documentation
gtk-grafana Feb 2, 2023
b982d48
Merge branch 'main' into gtk-grafana/streaming-prom-frontend-client-poc
leeoniya Feb 2, 2023
c1d8e28
Merge branch 'main' into gtk-grafana/streaming-prom-frontend-client-poc
leeoniya Feb 3, 2023
0cb223c
fix error being thrown when no data is returned from prometheus
gtk-grafana Feb 3, 2023
072bc57
adding stub options
gtk-grafana Feb 3, 2023
e55b9c4
fix eviction bug in which evicted frames would mutate the current tim…
gtk-grafana Feb 3, 2023
227f845
Refactor and clean up and document
gtk-grafana Feb 3, 2023
4b762e0
clean up and document
gtk-grafana Feb 3, 2023
60cfec7
refactor, document, continued
gtk-grafana Feb 3, 2023
86fb780
clean up
gtk-grafana Feb 3, 2023
d01564d
fix bug in which absolute queries querying old prometheus data were s…
gtk-grafana Feb 3, 2023
54d17ee
fix bug in which absolute queries querying old prometheus data were s…
gtk-grafana Feb 3, 2023
2e1ee7d
fix edge case where queries shorter then lookback time are requesting…
gtk-grafana Feb 3, 2023
64b657a
Merge remote-tracking branch 'origin/main' into gtk-grafana/streaming…
gtk-grafana Feb 3, 2023
80ddc47
fix unit test ts error
gtk-grafana Feb 3, 2023
aedadb6
Prometheus: Incremental querying PoC
leeoniya Feb 6, 2023
48264ba
fix bug with table responses that dont have labels, and make sure to …
gtk-grafana Feb 6, 2023
53d818f
turn off debug flag
gtk-grafana Feb 6, 2023
608df3a
fix for empty frames
leeoniya Feb 6, 2023
4390a47
WIP
gtk-grafana Feb 7, 2023
140a9d8
wip
leeoniya Feb 8, 2023
8281ef5
more wip
leeoniya Feb 8, 2023
723f09b
handle this.timeSrv.refresh === false
leeoniya Feb 8, 2023
82f6355
WIP
gtk-grafana Feb 8, 2023
52d5b0e
clone cached/amended frames before transformV2
leeoniya Feb 8, 2023
c0e8655
wip
leeoniya Feb 9, 2023
1f32e29
could be it!
leeoniya Feb 9, 2023
4111163
fix field config shallow clone
leeoniya Feb 9, 2023
45981c5
simplify & fixups
leeoniya Feb 9, 2023
acef50e
keep it classy
leeoniya Feb 10, 2023
1dcc720
Merge branch 'main' into leeoniya/prom-incr-query
leeoniya Feb 25, 2023
ee577b0
add comment about query range interval/step alignment
leeoniya Feb 25, 2023
9864f13
Merge branch 'gtk-grafana/streaming-prom-frontend-client-poc' into le…
gtk-grafana Feb 27, 2023
2cd4d7d
tests WIP
gtk-grafana Feb 28, 2023
4bb2de6
adding unit test that asserts that the returned fields all have the s…
gtk-grafana Mar 1, 2023
12dfe43
only compare fields within the same frame
gtk-grafana Mar 1, 2023
ef3c408
add tests for dataframes with gaps in values, clean up second test stub
gtk-grafana Mar 1, 2023
b00a679
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-qu…
gtk-grafana Mar 1, 2023
1435bf7
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 1, 2023
da87541
Merge branch 'leeoniya/prom-incr-query' into leeoniya/prom-incr-query…
gtk-grafana Mar 1, 2023
5544e69
clean up
gtk-grafana Mar 9, 2023
01dec57
Prometheus: incremental querying - unit tests (#63966)
gtk-grafana Mar 9, 2023
94ae474
add new header value to modified queries to report the modified durat…
gtk-grafana Mar 9, 2023
ec4f1b6
clean up unit tests a tad
gtk-grafana Mar 9, 2023
606e477
updating tests, and committing type assertions
gtk-grafana Mar 9, 2023
5d4e9b1
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-qu…
gtk-grafana Mar 9, 2023
18f5a13
Merge branch 'leeoniya/prom-incr-query__unit-tests' into leeoniya/pro…
gtk-grafana Mar 9, 2023
729461f
refactor everything
gtk-grafana Mar 9, 2023
ac4b6c8
clean up some confusion
gtk-grafana Mar 9, 2023
18e09a1
clean up some more confusion
gtk-grafana Mar 9, 2023
68e0f9e
remove accidentally changes file
gtk-grafana Mar 9, 2023
0bc62ed
Merge branch 'main' into leeoniya/prom-incr-query
leeoniya Mar 10, 2023
0090d6f
different telemetry?
leeoniya Mar 10, 2023
ffb424e
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 10, 2023
d660f34
remove console.log possibly breaking e2e tests
gtk-grafana Mar 10, 2023
96deaa6
add exemplar to signature, remove telemetry poc code
gtk-grafana Mar 10, 2023
9988244
add datasource config flag
gtk-grafana Mar 10, 2023
62df73e
reverting unidentified change
gtk-grafana Mar 10, 2023
3ad7dde
remove todo comments after adding to design doc
gtk-grafana Mar 10, 2023
609dee3
add documentation
gtk-grafana Mar 10, 2023
fb45c7f
add user configurable overlap window in seconds
gtk-grafana Mar 20, 2023
b0c8440
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 20, 2023
314f828
fix refactor bugs
gtk-grafana Mar 21, 2023
130308c
Change type of incrementalQueryOverlapWindow JSON field to durationut…
gtk-grafana Mar 21, 2023
06140e5
remove unused function
gtk-grafana Mar 22, 2023
4eda9eb
Merge branch 'main' into leeoniya/prom-incr-query
leeoniya Mar 22, 2023
979fc8d
remove period from copy
gtk-grafana Mar 28, 2023
48d0316
merge main, add documentation
gtk-grafana Mar 28, 2023
14c489e
fix version target
gtk-grafana Mar 28, 2023
d9da46f
add eslint-ignore-next-line even though it doesn't appear to do anything
gtk-grafana Mar 28, 2023
99ba1fb
fix bug when query target overrides default interval in request
gtk-grafana Mar 28, 2023
ae12095
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 28, 2023
03a47c9
add test that asserts that target interval overrides request interval
gtk-grafana Mar 29, 2023
414ccfd
update betterer and add more unit test coverage
gtk-grafana Mar 29, 2023
7c6831a
remove whitespace refactor
gtk-grafana Mar 29, 2023
56ae70a
running prettier
gtk-grafana Mar 29, 2023
7e9343e
clean up
gtk-grafana Mar 31, 2023
0d2bd2a
remove old comment
gtk-grafana Mar 31, 2023
3eda2f6
remove optional
gtk-grafana Mar 31, 2023
77e396f
remove console.logs
gtk-grafana Mar 31, 2023
2cb5e78
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 31, 2023
52aed84
add requestId
gtk-grafana Mar 31, 2023
7b8c0c6
remove requestId which was accidentally added
gtk-grafana Mar 31, 2023
bc2bd82
refactor to hint numeric type in variable name
gtk-grafana Mar 31, 2023
fdb1749
refactor to avoid merge conflicts
gtk-grafana Mar 31, 2023
5d0cc3a
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Mar 31, 2023
5d5025a
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Apr 3, 2023
751bf9f
tmp change
gtk-grafana Apr 3, 2023
d696ade
remove uncessary comment
gtk-grafana Apr 3, 2023
1357d8a
Update docs/sources/datasources/prometheus/_index.md
gtk-grafana Apr 3, 2023
60d0dab
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Apr 4, 2023
91d6ca7
Merge remote-tracking branch 'origin/main' into leeoniya/prom-incr-query
gtk-grafana Apr 6, 2023
7a5ba95
Update docs/sources/datasources/prometheus/_index.md
gtk-grafana Apr 11, 2023
739974f
add todo
gtk-grafana Apr 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 53 additions & 51 deletions docs/sources/administration/provisioning/index.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions docs/sources/datasources/prometheus/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ datasources:
manageAlerts: true
prometheusType: Prometheus
prometheusVersion: 2.37.0
incrementalQuerying: true
incrementalQueryOverlapWindow: 10m
cacheLevel: 'High'
exemplarTraceIdDestinations:
# Field with internal link pointing to data source in Grafana.
Expand Down Expand Up @@ -175,3 +177,11 @@ Grafana lists these variables in dropdown select boxes at the top of the dashboa
Grafana refers to such variables as template variables.

For details, see the [template variables documentation]({{< relref "./template-variables/" >}}).

## Incremental Dashboard Queries (beta)

As of Grafana 10, the Prometheus data source can be configured to query live dashboards incrementally, instead of re-querying the entire duration on each dashboard refresh.
This can be toggled on or off in the datasource configuration or provisioning file (under `incrementalQuerying` in jsonData).
Additionally, the amount of overlap between incremental queries can be configured using the `incrementalQueryOverlapWindow` jsonData field, the default value is 10m (10 minutes).

Increasing the duration of the `incrementalQueryOverlapWindow` will increase the size of every incremental query, but might be helpful for instances that have inconsistent results for recent data.
93 changes: 93 additions & 0 deletions public/app/features/live/data/amendTimeSeries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { closestIdx } from "./StreamingDataFrame";

export type Table = [times: number[], ...values: any[][]];

// prevTable and nextTable are assumed sorted ASC on reference [0] arrays
// nextTable is assumed to be contiguous, only edges are checked for overlap
// ...so prev: [1,2,5] + next: [3,4,6] -> [1,2,3,4,6]
export function amendTable(prevTable: Table, nextTable: Table): Table {
let [prevTimes] = prevTable;
let [nextTimes] = nextTable;

let pLen = prevTimes.length;
let pStart = prevTimes[0];
let pEnd = prevTimes[pLen - 1];

let nLen = nextTimes.length;
let nStart = nextTimes[0];
let nEnd = nextTimes[nLen - 1];

let outTable: Table;

if (pLen) {
if (nLen) {
// append, no overlap
if (nStart > pEnd) {
outTable = prevTable.map((_, i) => prevTable[i].concat(nextTable[i])) as Table;
}
// prepend, no overlap
else if (nEnd < pStart) {
outTable = nextTable.map((_, i) => nextTable[i].concat(prevTable[i])) as Table;
}
// full replace
else if (nStart <= pStart && nEnd >= pEnd) {
outTable = nextTable;
}
// partial replace
else if (nStart > pStart && nEnd < pEnd) {
}
// append, with overlap
else if (nStart >= pStart) {
let idx = closestIdx(nStart, prevTimes);
idx = prevTimes[idx] < nStart ? idx - 1 : idx;
outTable = prevTable.map((_, i) => prevTable[i].slice(0, idx).concat(nextTable[i])) as Table;
}
// prepend, with overlap
else if (nEnd >= pStart) {
let idx = closestIdx(nEnd, prevTimes);
idx = prevTimes[idx] < nEnd ? idx : idx + 1;
outTable = nextTable.map((_, i) => nextTable[i].concat(prevTable[i].slice(idx))) as Table;
}
} else {
outTable = prevTable;
}
} else {
if (nLen) {
outTable = nextTable;
} else {
outTable = [[]];
}
}

return outTable!;
}

export function trimTable(table: Table, fromTime: number, toTime: number): Table {
let [times, ...vals] = table;
let fromIdx: number | undefined;
let toIdx: number | undefined;

// trim to bounds
if (times[0] < fromTime) {
fromIdx = closestIdx(fromTime, times);

if (times[fromIdx] < fromTime) {
fromIdx++;
}
}

if (times[times.length - 1] > toTime) {
toIdx = closestIdx(toTime, times);

if (times[toIdx] > toTime) {
toIdx--;
}
}

if (fromIdx != null || toIdx != null) {
times = times.slice(fromIdx ?? 0, toIdx);
vals = vals.map(vals2 => vals2.slice(fromIdx ?? 0, toIdx));
}

return [times, ...vals];
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import semver from 'semver/preload';
import {
DataSourcePluginOptionsEditorProps,
DataSourceSettings as DataSourceSettingsType,
isValidDuration,
onUpdateDatasourceJsonDataOptionChecked,
SelectableValue,
updateDatasourcePluginJsonDataOption,
Expand All @@ -23,6 +24,7 @@ import config from '../../../../core/config';
import { useUpdateDatasource } from '../../../../features/datasources/state';
import { PromApplication, PromBuildInfoResponse } from '../../../../types/unified-alerting-dto';
import { QueryEditorMode } from '../querybuilder/shared/types';
import { defaultPrometheusQueryOverlapWindow } from '../querycache/QueryCache';
import { PrometheusCacheLevel, PromOptions } from '../types';

import { ExemplarsSettings } from './ExemplarsSettings';
Expand Down Expand Up @@ -362,6 +364,50 @@ export const PromSettings = (props: Props) => {
</div>
</div>
)}

<div className="gf-form-inline">
<div className="gf-form max-width-30">
<FormField
label="Incremental querying (beta)"
gtk-grafana marked this conversation as resolved.
Show resolved Hide resolved
labelWidth={14}
tooltip="This feature will change the default behavior of relative queries to always request fresh data from the prometheus instance, instead query results will be cached, and only new records are requested. Turn this on to decrease database and network load."
inputEl={
<InlineSwitch
value={options.jsonData.incrementalQuerying ?? false}
onChange={onUpdateDatasourceJsonDataOptionChecked(props, 'incrementalQuerying')}
disabled={options.readOnly}
/>
}
/>
</div>
</div>

<div className="gf-form-inline">
{options.jsonData.incrementalQuerying && (
<FormField
label="Query overlap window"
labelWidth={14}
tooltip="Set a duration like 10m or 120s or 0s. Default of 10 minutes. This duration will be added to the duration of each incremental request."
inputEl={
<Input
validationEvents={{
onBlur: [
{
rule: (value) => isValidDuration(value),
errorMessage: 'Invalid duration. Example values: 100s, 10m',
},
],
}}
className="width-25"
value={options.jsonData.incrementalQueryOverlapWindow ?? defaultPrometheusQueryOverlapWindow}
onChange={onChangeHandler('incrementalQueryOverlapWindow', options, onOptionsChange)}
spellCheck={false}
disabled={options.readOnly}
/>
}
/>
)}
</div>
</div>
<ExemplarsSettings
options={options.jsonData.exemplarTraceIdDestinations}
Expand Down
32 changes: 27 additions & 5 deletions public/app/plugins/datasource/prometheus/datasource.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { renderLegendFormat } from './legend';
import PrometheusMetricFindQuery from './metric_find_query';
import { getInitHints, getQueryHints } from './query_hints';
import { QueryEditorMode } from './querybuilder/shared/types';
import { CacheRequestInfo, defaultPrometheusQueryOverlapWindow, QueryCache } from './querycache/QueryCache';
import { getOriginalMetricName, transform, transformV2 } from './result_transformer';
import { trackQuery } from './tracking';
import {
Expand Down Expand Up @@ -84,6 +85,7 @@ export class PrometheusDatasource
{
type: string;
ruleMappings: { [index: string]: string };
hasIncrementalQuery: boolean;
url: string;
id: number;
directUrl: string;
Expand All @@ -105,6 +107,7 @@ export class PrometheusDatasource
subType: PromApplication;
rulerEnabled: boolean;
cacheLevel: PrometheusCacheLevel;
cache: QueryCache;

constructor(
instanceSettings: DataSourceInstanceSettings<PromOptions>,
Expand All @@ -129,6 +132,7 @@ export class PrometheusDatasource
// here we "fall back" to this.url to make typescript happy, but it should never happen
this.directUrl = instanceSettings.jsonData.directUrl ?? this.url;
this.exemplarTraceIdDestinations = instanceSettings.jsonData.exemplarTraceIdDestinations;
this.hasIncrementalQuery = instanceSettings.jsonData.incrementalQuerying ?? false;
this.ruleMappings = {};
this.languageProvider = languageProvider ?? new PrometheusLanguageProvider(this);
this.lookupsDisabled = instanceSettings.jsonData.disableMetricsLookup ?? false;
Expand All @@ -139,6 +143,9 @@ export class PrometheusDatasource
this.variables = new PrometheusVariableSupport(this, this.templateSrv, this.timeSrv);
this.exemplarsAvailable = true;
this.cacheLevel = instanceSettings.jsonData.cacheLevel ?? PrometheusCacheLevel.Low;
this.cache = new QueryCache(
instanceSettings.jsonData.incrementalQueryOverlapWindow ?? defaultPrometheusQueryOverlapWindow
);

// This needs to be here and cannot be static because of how annotations typing affects casting of data source
// objects to DataSourceApi types.
Expand Down Expand Up @@ -447,12 +454,27 @@ export class PrometheusDatasource

query(request: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
if (this.access === 'proxy') {
const targets = request.targets.map((target) => this.processTargetV2(target, request));
let fullOrPartialRequest: DataQueryRequest<PromQuery>;
let requestInfo: CacheRequestInfo | undefined = undefined;
if (this.hasIncrementalQuery) {
requestInfo = this.cache.requestInfo(request, this.interpolateString.bind(this));
fullOrPartialRequest = requestInfo.requests[0];
} else {
fullOrPartialRequest = request;
}

const targets = fullOrPartialRequest.targets.map((target) => this.processTargetV2(target, fullOrPartialRequest));
const startTime = new Date();
return super.query({ ...request, targets: targets.flat() }).pipe(
map((response) =>
transformV2(response, request, { exemplarTraceIdDestinations: this.exemplarTraceIdDestinations })
),
return super.query({ ...fullOrPartialRequest, targets: targets.flat() }).pipe(
map((response) => {
const amendedResponse = {
...response,
data: this.cache.procFrames(request, requestInfo, response.data),
};
return transformV2(amendedResponse, request, {
exemplarTraceIdDestinations: this.exemplarTraceIdDestinations,
});
}),
tap((response: DataQueryResponse) => {
trackQuery(response, request, startTime);
})
Expand Down
Loading