query_hints.ts 2.6 KB

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