Browse Source

Extract query hints

David 7 years ago
parent
commit
b0172427b1

+ 2 - 99
public/app/plugins/datasource/prometheus/datasource.ts

@@ -8,6 +8,7 @@ import { ResultTransformer } from './result_transformer';
 import { BackendSrv } from 'app/core/services/backend_srv';
 
 import addLabelToQuery from './add_label_to_query';
+import { getQueryHints } from './query_hints';
 
 export function alignRange(start, end, step) {
   const alignedEnd = Math.ceil(end / step) * step;
@@ -18,104 +19,6 @@ export function alignRange(start, end, step) {
   };
 }
 
-export function determineQueryHints(series: any[], datasource?: any): any[] {
-  const hints = series.map((s, i) => {
-    const query: string = s.query;
-    const index: number = s.responseIndex;
-    if (query === undefined || index === undefined) {
-      return null;
-    }
-
-    // ..._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.';
-      return {
-        index,
-        label,
-        fix: {
-          label: 'Fix by adding histogram_quantile().',
-          action: {
-            type: 'ADD_HISTOGRAM_QUANTILE',
-            query,
-            index,
-          },
-        },
-      };
-    }
-
-    // Check for monotony
-    const datapoints: number[][] = s.datapoints;
-    if (query.indexOf('rate(') === -1 && datapoints.length > 1) {
-      let increasing = false;
-      const monotonic = datapoints.filter(dp => dp[0] !== null).every((dp, index) => {
-        if (index === 0) {
-          return true;
-        }
-        increasing = increasing || dp[0] > datapoints[index - 1][0];
-        // monotonic?
-        return dp[0] >= datapoints[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
-    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;
-}
-
 export function extractRuleMappingFromGroups(groups: any[]) {
   return groups.reduce(
     (mapping, group) =>
@@ -300,7 +203,7 @@ export class PrometheusDatasource {
         result = [...result, ...series];
 
         if (queries[index].hinting) {
-          const queryHints = determineQueryHints(series, this);
+          const queryHints = getQueryHints(series, this);
           hints = [...hints, ...queryHints];
         }
       });

+ 99 - 0
public/app/plugins/datasource/prometheus/query_hints.ts

@@ -0,0 +1,99 @@
+import _ from 'lodash';
+
+export function getQueryHints(series: any[], datasource?: any): any[] {
+  const hints = series.map((s, i) => {
+    const query: string = s.query;
+    const index: number = s.responseIndex;
+    if (query === undefined || index === undefined) {
+      return null;
+    }
+
+    // ..._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.';
+      return {
+        index,
+        label,
+        fix: {
+          label: 'Fix by adding histogram_quantile().',
+          action: {
+            type: 'ADD_HISTOGRAM_QUANTILE',
+            query,
+            index,
+          },
+        },
+      };
+    }
+
+    // Check for monotony
+    const datapoints: number[][] = s.datapoints;
+    if (query.indexOf('rate(') === -1 && datapoints.length > 1) {
+      let increasing = false;
+      const monotonic = datapoints.filter(dp => dp[0] !== null).every((dp, index) => {
+        if (index === 0) {
+          return true;
+        }
+        increasing = increasing || dp[0] > datapoints[index - 1][0];
+        // monotonic?
+        return dp[0] >= datapoints[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
+    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;
+}

+ 0 - 79
public/app/plugins/datasource/prometheus/specs/datasource.test.ts

@@ -3,7 +3,6 @@ import moment from 'moment';
 import q from 'q';
 import {
   alignRange,
-  determineQueryHints,
   extractRuleMappingFromGroups,
   PrometheusDatasource,
   prometheusSpecialRegexEscape,
@@ -216,84 +215,6 @@ describe('PrometheusDatasource', () => {
     });
   });
 
-  describe('determineQueryHints()', () => {
-    it('returns no hints for no series', () => {
-      expect(determineQueryHints([])).toEqual([]);
-    });
-
-    it('returns no hints for empty series', () => {
-      expect(determineQueryHints([{ datapoints: [], query: '' }])).toEqual([null]);
-    });
-
-    it('returns no hint for a monotonously decreasing series', () => {
-      const series = [{ datapoints: [[23, 1000], [22, 1001]], query: 'metric', responseIndex: 0 }];
-      const hints = determineQueryHints(series);
-      expect(hints).toEqual([null]);
-    });
-
-    it('returns a rate hint for a monotonously increasing series', () => {
-      const series = [{ datapoints: [[23, 1000], [24, 1001]], query: 'metric', responseIndex: 0 }];
-      const hints = determineQueryHints(series);
-      expect(hints.length).toBe(1);
-      expect(hints[0]).toMatchObject({
-        label: 'Time series is monotonously increasing.',
-        index: 0,
-        fix: {
-          action: {
-            type: 'ADD_RATE',
-            query: 'metric',
-          },
-        },
-      });
-    });
-
-    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 hints = determineQueryHints(series);
-      expect(hints).toEqual([null]);
-    });
-
-    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 hints = determineQueryHints(series);
-      expect(hints.length).toBe(1);
-      expect(hints[0].label).toContain('rate()');
-      expect(hints[0].fix).toBeUndefined();
-    });
-
-    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 hints = determineQueryHints(series);
-      expect(hints.length).toBe(1);
-      expect(hints[0]).toMatchObject({
-        label: 'Time series is monotonously increasing.',
-        index: 0,
-        fix: {
-          action: {
-            type: 'ADD_RATE',
-            query: 'metric',
-          },
-        },
-      });
-    });
-
-    it('returns a histogram hint for a bucket series', () => {
-      const series = [{ datapoints: [[23, 1000]], query: 'metric_bucket', responseIndex: 0 }];
-      const hints = determineQueryHints(series);
-      expect(hints.length).toBe(1);
-      expect(hints[0]).toMatchObject({
-        label: 'Time series has buckets, you probably wanted a histogram.',
-        index: 0,
-        fix: {
-          action: {
-            type: 'ADD_HISTOGRAM_QUANTILE',
-            query: 'metric_bucket',
-          },
-        },
-      });
-    });
-  });
-
   describe('extractRuleMappingFromGroups()', () => {
     it('returns empty mapping for no rule groups', () => {
       expect(extractRuleMappingFromGroups([])).toEqual({});

+ 79 - 0
public/app/plugins/datasource/prometheus/specs/query_hints.test.ts

@@ -0,0 +1,79 @@
+import { getQueryHints } from '../query_hints';
+
+describe('getQueryHints()', () => {
+  it('returns no hints for no series', () => {
+    expect(getQueryHints([])).toEqual([]);
+  });
+
+  it('returns no hints for empty series', () => {
+    expect(getQueryHints([{ datapoints: [], query: '' }])).toEqual([null]);
+  });
+
+  it('returns no hint for a monotonously decreasing series', () => {
+    const series = [{ datapoints: [[23, 1000], [22, 1001]], query: 'metric', responseIndex: 0 }];
+    const hints = getQueryHints(series);
+    expect(hints).toEqual([null]);
+  });
+
+  it('returns a rate hint for a monotonously increasing series', () => {
+    const series = [{ datapoints: [[23, 1000], [24, 1001]], query: 'metric', responseIndex: 0 }];
+    const hints = getQueryHints(series);
+    expect(hints.length).toBe(1);
+    expect(hints[0]).toMatchObject({
+      label: 'Time series is monotonously increasing.',
+      index: 0,
+      fix: {
+        action: {
+          type: 'ADD_RATE',
+          query: 'metric',
+        },
+      },
+    });
+  });
+
+  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 hints = getQueryHints(series);
+    expect(hints).toEqual([null]);
+  });
+
+  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 hints = getQueryHints(series);
+    expect(hints.length).toBe(1);
+    expect(hints[0].label).toContain('rate()');
+    expect(hints[0].fix).toBeUndefined();
+  });
+
+  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 hints = getQueryHints(series);
+    expect(hints.length).toBe(1);
+    expect(hints[0]).toMatchObject({
+      label: 'Time series is monotonously increasing.',
+      index: 0,
+      fix: {
+        action: {
+          type: 'ADD_RATE',
+          query: 'metric',
+        },
+      },
+    });
+  });
+
+  it('returns a histogram hint for a bucket series', () => {
+    const series = [{ datapoints: [[23, 1000]], query: 'metric_bucket', responseIndex: 0 }];
+    const hints = getQueryHints(series);
+    expect(hints.length).toBe(1);
+    expect(hints[0]).toMatchObject({
+      label: 'Time series has buckets, you probably wanted a histogram.',
+      index: 0,
+      fix: {
+        action: {
+          type: 'ADD_HISTOGRAM_QUANTILE',
+          query: 'metric_bucket',
+        },
+      },
+    });
+  });
+});