Prometheus: Fixes so results in Panel always are sorted by query order (#19597)

Fixes #19529
This commit is contained in:
Hugo Häggmark 2019-10-03 05:15:59 -07:00 committed by GitHub
parent 2fb301ccaf
commit f9611250ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 5 deletions

View File

@ -1,6 +1,6 @@
import { PrometheusDatasource } from './datasource';
import { DataSourceInstanceSettings } from '@grafana/ui';
import { PromOptions } from './types';
import { PromContext, PromOptions } from './types';
import { dateTime, LoadingState } from '@grafana/data';
const defaultInstanceSettings: DataSourceInstanceSettings<PromOptions> = {
@ -67,11 +67,11 @@ describe('datasource', () => {
});
});
it('with 2 queries, waits for all to finish until sending Done status', done => {
it('with 2 queries and used from Explore, sends results as they arrive', done => {
expect.assertions(4);
backendSrvMock.datasourceRequest.mockReturnValue(Promise.resolve(makePromResponse()));
const responseStatus = [LoadingState.Loading, LoadingState.Done];
ds.query(makeQuery([{}, {}])).subscribe({
ds.query(makeQuery([{ context: PromContext.Explore }, { context: PromContext.Explore }])).subscribe({
next(next) {
expect(next.data.length).not.toBe(0);
expect(next.state).toBe(responseStatus.shift());
@ -81,6 +81,20 @@ describe('datasource', () => {
},
});
});
it('with 2 queries and used from Panel, waits for all to finish until sending Done status', done => {
expect.assertions(2);
backendSrvMock.datasourceRequest.mockReturnValue(Promise.resolve(makePromResponse()));
ds.query(makeQuery([{ context: PromContext.Panel }, { context: PromContext.Panel }])).subscribe({
next(next) {
expect(next.data.length).not.toBe(0);
expect(next.state).toBe(LoadingState.Done);
},
complete() {
done();
},
});
});
});
});
@ -92,6 +106,7 @@ function makeQuery(targets: any[]): any {
start: dateTime().subtract(5, 'minutes'),
end: dateTime(),
expr: 'test',
showingGraph: true,
...t,
};
}),

View File

@ -3,8 +3,8 @@ import _ from 'lodash';
import $ from 'jquery';
// Services & Utils
import kbn from 'app/core/utils/kbn';
import { AnnotationEvent, dateMath, DateTime, LoadingState, TimeRange } from '@grafana/data';
import { from, merge, Observable, of } from 'rxjs';
import { AnnotationEvent, dateMath, DateTime, LoadingState, TimeRange, TimeSeries } from '@grafana/data';
import { from, merge, Observable, of, forkJoin } from 'rxjs';
import { filter, map, tap } from 'rxjs/operators';
import PrometheusMetricFindQuery from './metric_find_query';
@ -28,6 +28,7 @@ import { safeStringifyValue } from 'app/core/utils/explore';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { ExploreUrlState } from 'app/types';
import TableModel from 'app/core/table_model';
export interface PromDataQueryResponse {
data: {
@ -221,6 +222,18 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
};
};
calledFromExplore = (options: DataQueryRequest<PromQuery>): boolean => {
let exploreTargets = 0;
for (let index = 0; index < options.targets.length; index++) {
const target = options.targets[index];
if (target.context === PromContext.Explore) {
exploreTargets++;
}
}
return exploreTargets === options.targets.length;
};
query(options: DataQueryRequest<PromQuery>): Observable<DataQueryResponse> {
const start = this.getPrometheusTime(options.range.from, false);
const end = this.getPrometheusTime(options.range.to, true);
@ -234,6 +247,14 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
});
}
if (this.calledFromExplore(options)) {
return this.exploreQuery(queries, activeTargets, end);
}
return this.panelsQuery(queries, activeTargets, end, options.requestId);
}
private exploreQuery(queries: PromQueryRequest[], activeTargets: PromQuery[], end: number) {
let runningQueriesCount = queries.length;
const subQueries = queries.map((query, index) => {
const target = activeTargets[index];
@ -264,6 +285,40 @@ export class PrometheusDatasource extends DataSourceApi<PromQuery, PromOptions>
return merge(...subQueries);
}
private panelsQuery(queries: PromQueryRequest[], activeTargets: PromQuery[], end: number, requestId: string) {
const observables: Array<Observable<Array<TableModel | TimeSeries>>> = queries.map((query, index) => {
const target = activeTargets[index];
let observable: Observable<any> = null;
if (query.instant) {
observable = from(this.performInstantQuery(query, end));
} else {
observable = from(this.performTimeSeriesQuery(query, query.start, query.end));
}
return observable.pipe(
filter((response: any) => (response.cancelled ? false : true)),
map((response: any) => {
const data = this.processResult(response, query, target, queries.length);
return data;
})
);
});
return forkJoin(observables).pipe(
map((results: Array<Array<TableModel | TimeSeries>>) => {
const data = results.reduce((result, current) => {
return [...result, ...current];
}, []);
return {
data,
key: requestId,
state: LoadingState.Done,
};
})
);
}
createQuery(target: PromQuery, options: DataQueryRequest<PromQuery>, start: number, end: number) {
const query: PromQueryRequest = {
hinting: target.hinting,