mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Get query hints per query transaction
This commit is contained in:
parent
2e02a8c855
commit
fbed57ab43
@ -11,7 +11,6 @@ const DEFAULT_EXPLORE_STATE: ExploreState = {
|
|||||||
graphRange: DEFAULT_RANGE,
|
graphRange: DEFAULT_RANGE,
|
||||||
history: [],
|
history: [],
|
||||||
queries: [],
|
queries: [],
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: [],
|
queryTransactions: [],
|
||||||
range: DEFAULT_RANGE,
|
range: DEFAULT_RANGE,
|
||||||
showingGraph: true,
|
showingGraph: true,
|
||||||
|
@ -25,11 +25,11 @@ import { ensureQueries, generateQueryKey, hasQuery } from './utils/query';
|
|||||||
|
|
||||||
const MAX_HISTORY_ITEMS = 100;
|
const MAX_HISTORY_ITEMS = 100;
|
||||||
|
|
||||||
function makeHints(hints) {
|
function makeHints(transactions: QueryTransaction[]) {
|
||||||
const hintsByIndex = [];
|
const hintsByIndex = [];
|
||||||
hints.forEach(hint => {
|
transactions.forEach(qt => {
|
||||||
if (hint) {
|
if (qt.hints && qt.hints.length > 0) {
|
||||||
hintsByIndex[hint.index] = hint;
|
hintsByIndex[qt.rowIndex] = qt.hints[0];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return hintsByIndex;
|
return hintsByIndex;
|
||||||
@ -113,7 +113,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
graphRange: initialRange,
|
graphRange: initialRange,
|
||||||
history: [],
|
history: [],
|
||||||
queries: initialQueries,
|
queries: initialQueries,
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: [],
|
queryTransactions: [],
|
||||||
range: initialRange,
|
range: initialRange,
|
||||||
showingGraph: true,
|
showingGraph: true,
|
||||||
@ -246,7 +245,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
datasource: null,
|
datasource: null,
|
||||||
datasourceError: null,
|
datasourceError: null,
|
||||||
datasourceLoading: true,
|
datasourceLoading: true,
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: [],
|
queryTransactions: [],
|
||||||
});
|
});
|
||||||
const datasourceName = option.value;
|
const datasourceName = option.value;
|
||||||
@ -274,7 +272,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
queries: nextQueries,
|
queries: nextQueries,
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: nextQueryTransactions,
|
queryTransactions: nextQueryTransactions,
|
||||||
},
|
},
|
||||||
this.onSubmit
|
this.onSubmit
|
||||||
@ -295,7 +292,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
this.setState(
|
this.setState(
|
||||||
{
|
{
|
||||||
queries: ensureQueries(),
|
queries: ensureQueries(),
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: [],
|
queryTransactions: [],
|
||||||
},
|
},
|
||||||
this.saveState
|
this.saveState
|
||||||
@ -458,7 +454,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const nextQueryTransactions = [...remainingTransactions, transaction];
|
const nextQueryTransactions = [...remainingTransactions, transaction];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
queryHints: [],
|
|
||||||
queryTransactions: nextQueryTransactions,
|
queryTransactions: nextQueryTransactions,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -470,7 +465,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
transactionId: string,
|
transactionId: string,
|
||||||
result: any,
|
result: any,
|
||||||
latency: number,
|
latency: number,
|
||||||
hints: any[],
|
|
||||||
queries: string[],
|
queries: string[],
|
||||||
datasourceId: string
|
datasourceId: string
|
||||||
) {
|
) {
|
||||||
@ -484,15 +478,23 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const { history, queryTransactions } = state;
|
const { history, queryTransactions } = state;
|
||||||
|
|
||||||
// Transaction might have been discarded
|
// Transaction might have been discarded
|
||||||
if (!queryTransactions.find(qt => qt.id === transactionId)) {
|
const transaction = queryTransactions.find(qt => qt.id === transactionId);
|
||||||
|
if (!transaction) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get query hints
|
||||||
|
let hints;
|
||||||
|
if (datasource.getQueryHints) {
|
||||||
|
hints = datasource.getQueryHints(transaction.query, result);
|
||||||
|
}
|
||||||
|
|
||||||
// Mark transactions as complete
|
// Mark transactions as complete
|
||||||
const nextQueryTransactions = queryTransactions.map(qt => {
|
const nextQueryTransactions = queryTransactions.map(qt => {
|
||||||
if (qt.id === transactionId) {
|
if (qt.id === transactionId) {
|
||||||
return {
|
return {
|
||||||
...qt,
|
...qt,
|
||||||
|
hints,
|
||||||
latency,
|
latency,
|
||||||
result,
|
result,
|
||||||
done: true,
|
done: true,
|
||||||
@ -505,7 +507,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
history: nextHistory,
|
history: nextHistory,
|
||||||
queryHints: hints,
|
|
||||||
queryTransactions: nextQueryTransactions,
|
queryTransactions: nextQueryTransactions,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -562,8 +563,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const res = await datasource.query(transaction.options);
|
const res = await datasource.query(transaction.options);
|
||||||
const latency = Date.now() - now;
|
const latency = Date.now() - now;
|
||||||
const results = makeTimeSeriesList(res.data, transaction.options);
|
const results = makeTimeSeriesList(res.data, transaction.options);
|
||||||
const queryHints = res.hints ? makeHints(res.hints) : [];
|
this.completeQueryTransaction(transaction.id, results, latency, queries, datasourceId);
|
||||||
this.completeQueryTransaction(transaction.id, results, latency, queryHints, queries, datasourceId);
|
|
||||||
this.setState({ graphRange: transaction.options.range });
|
this.setState({ graphRange: transaction.options.range });
|
||||||
} catch (response) {
|
} catch (response) {
|
||||||
console.error(response);
|
console.error(response);
|
||||||
@ -590,7 +590,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const res = await datasource.query(transaction.options);
|
const res = await datasource.query(transaction.options);
|
||||||
const latency = Date.now() - now;
|
const latency = Date.now() - now;
|
||||||
const results = mergeTablesIntoModel(new TableModel(), ...res.data);
|
const results = mergeTablesIntoModel(new TableModel(), ...res.data);
|
||||||
this.completeQueryTransaction(transaction.id, results, latency, [], queries, datasourceId);
|
this.completeQueryTransaction(transaction.id, results, latency, queries, datasourceId);
|
||||||
} catch (response) {
|
} catch (response) {
|
||||||
console.error(response);
|
console.error(response);
|
||||||
const queryError = response.data ? response.data.error : response;
|
const queryError = response.data ? response.data.error : response;
|
||||||
@ -616,7 +616,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
const res = await datasource.query(transaction.options);
|
const res = await datasource.query(transaction.options);
|
||||||
const latency = Date.now() - now;
|
const latency = Date.now() - now;
|
||||||
const results = res.data;
|
const results = res.data;
|
||||||
this.completeQueryTransaction(transaction.id, results, latency, [], queries, datasourceId);
|
this.completeQueryTransaction(transaction.id, results, latency, queries, datasourceId);
|
||||||
} catch (response) {
|
} catch (response) {
|
||||||
console.error(response);
|
console.error(response);
|
||||||
const queryError = response.data ? response.data.error : response;
|
const queryError = response.data ? response.data.error : response;
|
||||||
@ -655,7 +655,6 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
graphRange,
|
graphRange,
|
||||||
history,
|
history,
|
||||||
queries,
|
queries,
|
||||||
queryHints,
|
|
||||||
queryTransactions,
|
queryTransactions,
|
||||||
range,
|
range,
|
||||||
showingGraph,
|
showingGraph,
|
||||||
@ -683,6 +682,7 @@ export class Explore extends React.PureComponent<ExploreProps, ExploreState> {
|
|||||||
queryTransactions.filter(qt => qt.resultType === 'Logs' && qt.done).map(qt => qt.result)
|
queryTransactions.filter(qt => qt.resultType === 'Logs' && qt.done).map(qt => qt.result)
|
||||||
);
|
);
|
||||||
const loading = queryTransactions.some(qt => !qt.done);
|
const loading = queryTransactions.some(qt => !qt.done);
|
||||||
|
const queryHints = makeHints(queryTransactions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={exploreClass} ref={this.getRef}>
|
<div className={exploreClass} ref={this.getRef}>
|
||||||
|
@ -176,7 +176,6 @@ export class PrometheusDatasource {
|
|||||||
|
|
||||||
return this.$q.all(allQueryPromise).then(responseList => {
|
return this.$q.all(allQueryPromise).then(responseList => {
|
||||||
let result = [];
|
let result = [];
|
||||||
let hints = [];
|
|
||||||
|
|
||||||
_.each(responseList, (response, index) => {
|
_.each(responseList, (response, index) => {
|
||||||
if (response.status === 'error') {
|
if (response.status === 'error') {
|
||||||
@ -196,19 +195,13 @@ export class PrometheusDatasource {
|
|||||||
end: queries[index].end,
|
end: queries[index].end,
|
||||||
query: queries[index].expr,
|
query: queries[index].expr,
|
||||||
responseListLength: responseList.length,
|
responseListLength: responseList.length,
|
||||||
responseIndex: index,
|
|
||||||
refId: activeTargets[index].refId,
|
refId: activeTargets[index].refId,
|
||||||
};
|
};
|
||||||
const series = this.resultTransformer.transform(response, transformerOptions);
|
const series = this.resultTransformer.transform(response, transformerOptions);
|
||||||
result = [...result, ...series];
|
result = [...result, ...series];
|
||||||
|
|
||||||
if (queries[index].hinting) {
|
|
||||||
const queryHints = getQueryHints(series, this);
|
|
||||||
hints = [...hints, ...queryHints];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { data: result, hints };
|
return { data: result };
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,6 +430,10 @@ export class PrometheusDatasource {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getQueryHints(query: string, result: any[]) {
|
||||||
|
return getQueryHints(query, result, this);
|
||||||
|
}
|
||||||
|
|
||||||
loadRules() {
|
loadRules() {
|
||||||
this.metadataRequest('/api/v1/rules')
|
this.metadataRequest('/api/v1/rules')
|
||||||
.then(res => res.data || res.json())
|
.then(res => res.data || res.json())
|
||||||
|
@ -1,100 +1,92 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
export function getQueryHints(series: any[], datasource?: any): any[] {
|
export function getQueryHints(query: string, series?: any[], datasource?: any): any[] {
|
||||||
const hints = series.map((s, i) => {
|
const hints = [];
|
||||||
const query: string = s.query;
|
|
||||||
const index: number = s.responseIndex;
|
|
||||||
if (query === undefined || index === undefined) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ..._bucket metric needs a histogram_quantile()
|
// ..._bucket metric needs a histogram_quantile()
|
||||||
const histogramMetric = query.trim().match(/^\w+_bucket$/);
|
const histogramMetric = query.trim().match(/^\w+_bucket$/);
|
||||||
if (histogramMetric) {
|
if (histogramMetric) {
|
||||||
const label = 'Time series has buckets, you probably wanted a histogram.';
|
const label = 'Time series has buckets, you probably wanted a histogram.';
|
||||||
return {
|
hints.push({
|
||||||
index,
|
type: 'HISTOGRAM_QUANTILE',
|
||||||
|
label,
|
||||||
|
fix: {
|
||||||
|
label: 'Fix by adding histogram_quantile().',
|
||||||
|
action: {
|
||||||
|
type: 'ADD_HISTOGRAM_QUANTILE',
|
||||||
|
query,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for monotony on series (table results are being ignored here)
|
||||||
|
if (series && series.length > 0) {
|
||||||
|
series.forEach(s => {
|
||||||
|
const datapoints: number[][] = s.datapoints;
|
||||||
|
if (query.indexOf('rate(') === -1 && datapoints.length > 1) {
|
||||||
|
let increasing = false;
|
||||||
|
const nonNullData = datapoints.filter(dp => dp[0] !== null);
|
||||||
|
const monotonic = nonNullData.every((dp, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
increasing = increasing || dp[0] > nonNullData[index - 1][0];
|
||||||
|
// monotonic?
|
||||||
|
return dp[0] >= nonNullData[index - 1][0];
|
||||||
|
});
|
||||||
|
if (increasing && monotonic) {
|
||||||
|
const simpleMetric = query.trim().match(/^\w+$/);
|
||||||
|
let label = 'Time series is monotonously increasing.';
|
||||||
|
let fix;
|
||||||
|
if (simpleMetric) {
|
||||||
|
fix = {
|
||||||
|
label: 'Fix by adding rate().',
|
||||||
|
action: {
|
||||||
|
type: 'ADD_RATE',
|
||||||
|
query,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
label = `${label} Try applying a rate() function.`;
|
||||||
|
}
|
||||||
|
hints.push({
|
||||||
|
type: 'APPLY_RATE',
|
||||||
|
label,
|
||||||
|
fix,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for recording rules expansion
|
||||||
|
if (datasource && datasource.ruleMappings) {
|
||||||
|
const mapping = datasource.ruleMappings;
|
||||||
|
const mappingForQuery = Object.keys(mapping).reduce((acc, ruleName) => {
|
||||||
|
if (query.search(ruleName) > -1) {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[ruleName]: mapping[ruleName],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
if (_.size(mappingForQuery) > 0) {
|
||||||
|
const label = 'Query contains recording rules.';
|
||||||
|
hints.push({
|
||||||
|
type: 'EXPAND_RULES',
|
||||||
label,
|
label,
|
||||||
fix: {
|
fix: {
|
||||||
label: 'Fix by adding histogram_quantile().',
|
label: 'Expand rules',
|
||||||
action: {
|
action: {
|
||||||
type: 'ADD_HISTOGRAM_QUANTILE',
|
type: 'EXPAND_RULES',
|
||||||
query,
|
query,
|
||||||
index,
|
mapping: mappingForQuery,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for monotony
|
|
||||||
const datapoints: number[][] = s.datapoints;
|
|
||||||
if (query.indexOf('rate(') === -1 && datapoints.length > 1) {
|
|
||||||
let increasing = false;
|
|
||||||
const nonNullData = datapoints.filter(dp => dp[0] !== null);
|
|
||||||
const monotonic = nonNullData.every((dp, index) => {
|
|
||||||
if (index === 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
increasing = increasing || dp[0] > nonNullData[index - 1][0];
|
|
||||||
// monotonic?
|
|
||||||
return dp[0] >= nonNullData[index - 1][0];
|
|
||||||
});
|
});
|
||||||
if (increasing && monotonic) {
|
|
||||||
const simpleMetric = query.trim().match(/^\w+$/);
|
|
||||||
let label = 'Time series is monotonously increasing.';
|
|
||||||
let fix;
|
|
||||||
if (simpleMetric) {
|
|
||||||
fix = {
|
|
||||||
label: 'Fix by adding rate().',
|
|
||||||
action: {
|
|
||||||
type: 'ADD_RATE',
|
|
||||||
query,
|
|
||||||
index,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
label = `${label} Try applying a rate() function.`;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
label,
|
|
||||||
index,
|
|
||||||
fix,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Check for recording rules expansion
|
return hints.length > 0 ? hints : null;
|
||||||
if (datasource && datasource.ruleMappings) {
|
|
||||||
const mapping = datasource.ruleMappings;
|
|
||||||
const mappingForQuery = Object.keys(mapping).reduce((acc, ruleName) => {
|
|
||||||
if (query.search(ruleName) > -1) {
|
|
||||||
return {
|
|
||||||
...acc,
|
|
||||||
[ruleName]: mapping[ruleName],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
if (_.size(mappingForQuery) > 0) {
|
|
||||||
const label = 'Query contains recording rules.';
|
|
||||||
return {
|
|
||||||
label,
|
|
||||||
index,
|
|
||||||
fix: {
|
|
||||||
label: 'Expand rules',
|
|
||||||
action: {
|
|
||||||
type: 'EXPAND_RULES',
|
|
||||||
query,
|
|
||||||
index,
|
|
||||||
mapping: mappingForQuery,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No hint found
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return hints;
|
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,6 @@ export class ResultTransformer {
|
|||||||
return {
|
return {
|
||||||
datapoints: dps,
|
datapoints: dps,
|
||||||
query: options.query,
|
query: options.query,
|
||||||
responseIndex: options.responseIndex,
|
|
||||||
target: metricLabel,
|
target: metricLabel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2,34 +2,31 @@ import { getQueryHints } from '../query_hints';
|
|||||||
|
|
||||||
describe('getQueryHints()', () => {
|
describe('getQueryHints()', () => {
|
||||||
it('returns no hints for no series', () => {
|
it('returns no hints for no series', () => {
|
||||||
expect(getQueryHints([])).toEqual([]);
|
expect(getQueryHints('', [])).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns no hints for empty series', () => {
|
it('returns no hints for empty series', () => {
|
||||||
expect(getQueryHints([{ datapoints: [], query: '' }])).toEqual([null]);
|
expect(getQueryHints('', [{ datapoints: [] }])).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns no hint for a monotonously decreasing series', () => {
|
it('returns no hint for a monotonously decreasing series', () => {
|
||||||
const series = [{ datapoints: [[23, 1000], [22, 1001]], query: 'metric', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000], [22, 1001]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('metric', series);
|
||||||
expect(hints).toEqual([null]);
|
expect(hints).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns no hint for a flat series', () => {
|
it('returns no hint for a flat series', () => {
|
||||||
const series = [
|
const series = [{ datapoints: [[null, 1000], [23, 1001], [null, 1002], [23, 1003]] }];
|
||||||
{ datapoints: [[null, 1000], [23, 1001], [null, 1002], [23, 1003]], query: 'metric', responseIndex: 0 },
|
const hints = getQueryHints('metric', series);
|
||||||
];
|
expect(hints).toEqual(null);
|
||||||
const hints = getQueryHints(series);
|
|
||||||
expect(hints).toEqual([null]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a rate hint for a monotonously increasing series', () => {
|
it('returns a rate hint for a monotonously increasing series', () => {
|
||||||
const series = [{ datapoints: [[23, 1000], [24, 1001]], query: 'metric', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000], [24, 1001]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('metric', series);
|
||||||
expect(hints.length).toBe(1);
|
expect(hints.length).toBe(1);
|
||||||
expect(hints[0]).toMatchObject({
|
expect(hints[0]).toMatchObject({
|
||||||
label: 'Time series is monotonously increasing.',
|
label: 'Time series is monotonously increasing.',
|
||||||
index: 0,
|
|
||||||
fix: {
|
fix: {
|
||||||
action: {
|
action: {
|
||||||
type: 'ADD_RATE',
|
type: 'ADD_RATE',
|
||||||
@ -40,26 +37,25 @@ describe('getQueryHints()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns no rate hint for a monotonously increasing series that already has a rate', () => {
|
it('returns no rate hint for a monotonously increasing series that already has a rate', () => {
|
||||||
const series = [{ datapoints: [[23, 1000], [24, 1001]], query: 'rate(metric[1m])', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000], [24, 1001]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('rate(metric[1m])', series);
|
||||||
expect(hints).toEqual([null]);
|
expect(hints).toEqual(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a rate hint w/o action for a complex monotonously increasing series', () => {
|
it('returns a rate hint w/o action for a complex monotonously increasing series', () => {
|
||||||
const series = [{ datapoints: [[23, 1000], [24, 1001]], query: 'sum(metric)', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000], [24, 1001]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('sum(metric)', series);
|
||||||
expect(hints.length).toBe(1);
|
expect(hints.length).toBe(1);
|
||||||
expect(hints[0].label).toContain('rate()');
|
expect(hints[0].label).toContain('rate()');
|
||||||
expect(hints[0].fix).toBeUndefined();
|
expect(hints[0].fix).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('returns a rate hint for a monotonously increasing series with missing data', () => {
|
it('returns a rate hint for a monotonously increasing series with missing data', () => {
|
||||||
const series = [{ datapoints: [[23, 1000], [null, 1001], [24, 1002]], query: 'metric', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000], [null, 1001], [24, 1002]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('metric', series);
|
||||||
expect(hints.length).toBe(1);
|
expect(hints.length).toBe(1);
|
||||||
expect(hints[0]).toMatchObject({
|
expect(hints[0]).toMatchObject({
|
||||||
label: 'Time series is monotonously increasing.',
|
label: 'Time series is monotonously increasing.',
|
||||||
index: 0,
|
|
||||||
fix: {
|
fix: {
|
||||||
action: {
|
action: {
|
||||||
type: 'ADD_RATE',
|
type: 'ADD_RATE',
|
||||||
@ -70,12 +66,11 @@ describe('getQueryHints()', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('returns a histogram hint for a bucket series', () => {
|
it('returns a histogram hint for a bucket series', () => {
|
||||||
const series = [{ datapoints: [[23, 1000]], query: 'metric_bucket', responseIndex: 0 }];
|
const series = [{ datapoints: [[23, 1000]] }];
|
||||||
const hints = getQueryHints(series);
|
const hints = getQueryHints('metric_bucket', series);
|
||||||
expect(hints.length).toBe(1);
|
expect(hints.length).toBe(1);
|
||||||
expect(hints[0]).toMatchObject({
|
expect(hints[0]).toMatchObject({
|
||||||
label: 'Time series has buckets, you probably wanted a histogram.',
|
label: 'Time series has buckets, you probably wanted a histogram.',
|
||||||
index: 0,
|
|
||||||
fix: {
|
fix: {
|
||||||
action: {
|
action: {
|
||||||
type: 'ADD_HISTOGRAM_QUANTILE',
|
type: 'ADD_HISTOGRAM_QUANTILE',
|
||||||
|
@ -22,6 +22,7 @@ export interface QueryTransaction {
|
|||||||
id: string;
|
id: string;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
error?: string;
|
error?: string;
|
||||||
|
hints?: any[];
|
||||||
latency: number;
|
latency: number;
|
||||||
options: any;
|
options: any;
|
||||||
query: string;
|
query: string;
|
||||||
@ -55,7 +56,6 @@ export interface ExploreState {
|
|||||||
/**
|
/**
|
||||||
* Hints gathered for the query row.
|
* Hints gathered for the query row.
|
||||||
*/
|
*/
|
||||||
queryHints: any[];
|
|
||||||
queryTransactions: QueryTransaction[];
|
queryTransactions: QueryTransaction[];
|
||||||
range: Range;
|
range: Range;
|
||||||
showingGraph: boolean;
|
showingGraph: boolean;
|
||||||
|
Loading…
Reference in New Issue
Block a user