mirror of
https://github.com/grafana/grafana.git
synced 2025-02-14 17:43:35 -06:00
118 lines
3.2 KiB
TypeScript
118 lines
3.2 KiB
TypeScript
import _ from 'lodash';
|
|
import { QueryHint } from '@grafana/ui/src/types';
|
|
|
|
/**
|
|
* Number of time series results needed before starting to suggest sum aggregation hints
|
|
*/
|
|
export const SUM_HINT_THRESHOLD_COUNT = 20;
|
|
|
|
export function getQueryHints(query: string, series?: any[], datasource?: any): QueryHint[] {
|
|
const hints = [];
|
|
|
|
// ..._bucket metric needs a histogram_quantile()
|
|
const histogramMetric = query.trim().match(/^\w+_bucket$/);
|
|
if (histogramMetric) {
|
|
const label = 'Time series has buckets, you probably wanted a histogram.';
|
|
hints.push({
|
|
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,
|
|
fix: {
|
|
label: 'Expand rules',
|
|
action: {
|
|
type: 'EXPAND_RULES',
|
|
query,
|
|
mapping: mappingForQuery,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
if (series && series.length >= SUM_HINT_THRESHOLD_COUNT) {
|
|
const simpleMetric = query.trim().match(/^\w+$/);
|
|
if (simpleMetric) {
|
|
hints.push({
|
|
type: 'ADD_SUM',
|
|
label: 'Many time series results returned.',
|
|
fix: {
|
|
label: 'Consider aggregating with sum().',
|
|
action: {
|
|
type: 'ADD_SUM',
|
|
query: query,
|
|
preventSubmit: true,
|
|
},
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
return hints.length > 0 ? hints : null;
|
|
}
|