| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- 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 monotonicity 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 monotonically 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;
- }
|