query_hints.ts 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import _ from 'lodash';
  2. import { QueryHint } from 'app/types/explore';
  3. export function getQueryHints(query: string, series?: any[], datasource?: any): QueryHint[] {
  4. const hints = [];
  5. // ..._bucket metric needs a histogram_quantile()
  6. const histogramMetric = query.trim().match(/^\w+_bucket$/);
  7. if (histogramMetric) {
  8. const label = 'Time series has buckets, you probably wanted a histogram.';
  9. hints.push({
  10. type: 'HISTOGRAM_QUANTILE',
  11. label,
  12. fix: {
  13. label: 'Fix by adding histogram_quantile().',
  14. action: {
  15. type: 'ADD_HISTOGRAM_QUANTILE',
  16. query,
  17. },
  18. },
  19. });
  20. }
  21. // Check for monotony on series (table results are being ignored here)
  22. if (series && series.length > 0) {
  23. series.forEach(s => {
  24. const datapoints: number[][] = s.datapoints;
  25. if (query.indexOf('rate(') === -1 && datapoints.length > 1) {
  26. let increasing = false;
  27. const nonNullData = datapoints.filter(dp => dp[0] !== null);
  28. const monotonic = nonNullData.every((dp, index) => {
  29. if (index === 0) {
  30. return true;
  31. }
  32. increasing = increasing || dp[0] > nonNullData[index - 1][0];
  33. // monotonic?
  34. return dp[0] >= nonNullData[index - 1][0];
  35. });
  36. if (increasing && monotonic) {
  37. const simpleMetric = query.trim().match(/^\w+$/);
  38. let label = 'Time series is monotonously increasing.';
  39. let fix;
  40. if (simpleMetric) {
  41. fix = {
  42. label: 'Fix by adding rate().',
  43. action: {
  44. type: 'ADD_RATE',
  45. query,
  46. },
  47. };
  48. } else {
  49. label = `${label} Try applying a rate() function.`;
  50. }
  51. hints.push({
  52. type: 'APPLY_RATE',
  53. label,
  54. fix,
  55. });
  56. }
  57. }
  58. });
  59. }
  60. // Check for recording rules expansion
  61. if (datasource && datasource.ruleMappings) {
  62. const mapping = datasource.ruleMappings;
  63. const mappingForQuery = Object.keys(mapping).reduce((acc, ruleName) => {
  64. if (query.search(ruleName) > -1) {
  65. return {
  66. ...acc,
  67. [ruleName]: mapping[ruleName],
  68. };
  69. }
  70. return acc;
  71. }, {});
  72. if (_.size(mappingForQuery) > 0) {
  73. const label = 'Query contains recording rules.';
  74. hints.push({
  75. type: 'EXPAND_RULES',
  76. label,
  77. fix: {
  78. label: 'Expand rules',
  79. action: {
  80. type: 'EXPAND_RULES',
  81. query,
  82. mapping: mappingForQuery,
  83. },
  84. },
  85. });
  86. }
  87. }
  88. return hints.length > 0 ? hints : null;
  89. }