prometheus.ts 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. export const RATE_RANGES = ['1m', '5m', '10m', '30m', '1h'];
  2. export function processLabels(labels, withName = false) {
  3. const values = {};
  4. labels.forEach(l => {
  5. const { __name__, ...rest } = l;
  6. if (withName) {
  7. values['__name__'] = values['__name__'] || [];
  8. if (values['__name__'].indexOf(__name__) === -1) {
  9. values['__name__'].push(__name__);
  10. }
  11. }
  12. Object.keys(rest).forEach(key => {
  13. if (!values[key]) {
  14. values[key] = [];
  15. }
  16. if (values[key].indexOf(rest[key]) === -1) {
  17. values[key].push(rest[key]);
  18. }
  19. });
  20. });
  21. return { values, keys: Object.keys(values) };
  22. }
  23. // Strip syntax chars
  24. export const cleanText = s => s.replace(/[{}[\]="(),!~+\-*/^%]/g, '').trim();
  25. // const cleanSelectorRegexp = /\{(\w+="[^"\n]*?")(,\w+="[^"\n]*?")*\}/;
  26. const selectorRegexp = /\{[^}]*?\}/;
  27. const labelRegexp = /\b\w+="[^"\n]*?"/g;
  28. export function parseSelector(query: string, cursorOffset = 1): { labelKeys: any[]; selector: string } {
  29. if (!query.match(selectorRegexp)) {
  30. // Special matcher for metrics
  31. if (query.match(/^[A-Za-z:][\w:]*$/)) {
  32. return {
  33. selector: `{__name__="${query}"}`,
  34. labelKeys: ['__name__'],
  35. };
  36. }
  37. throw new Error('Query must contain a selector: ' + query);
  38. }
  39. // Check if inside a selector
  40. const prefix = query.slice(0, cursorOffset);
  41. const prefixOpen = prefix.lastIndexOf('{');
  42. const prefixClose = prefix.lastIndexOf('}');
  43. if (prefixOpen === -1) {
  44. throw new Error('Not inside selector, missing open brace: ' + prefix);
  45. }
  46. if (prefixClose > -1 && prefixClose > prefixOpen) {
  47. throw new Error('Not inside selector, previous selector already closed: ' + prefix);
  48. }
  49. const suffix = query.slice(cursorOffset);
  50. const suffixCloseIndex = suffix.indexOf('}');
  51. const suffixClose = suffixCloseIndex + cursorOffset;
  52. const suffixOpenIndex = suffix.indexOf('{');
  53. const suffixOpen = suffixOpenIndex + cursorOffset;
  54. if (suffixClose === -1) {
  55. throw new Error('Not inside selector, missing closing brace in suffix: ' + suffix);
  56. }
  57. if (suffixOpenIndex > -1 && suffixOpen < suffixClose) {
  58. throw new Error('Not inside selector, next selector opens before this one closed: ' + suffix);
  59. }
  60. // Extract clean labels to form clean selector, incomplete labels are dropped
  61. const selector = query.slice(prefixOpen, suffixClose);
  62. const labels = {};
  63. selector.replace(labelRegexp, match => {
  64. const delimiterIndex = match.indexOf('=');
  65. const key = match.slice(0, delimiterIndex);
  66. const value = match.slice(delimiterIndex + 1, match.length);
  67. labels[key] = value;
  68. return '';
  69. });
  70. // Add metric if there is one before the selector
  71. const metricPrefix = query.slice(0, prefixOpen);
  72. const metricMatch = metricPrefix.match(/[A-Za-z:][\w:]*$/);
  73. if (metricMatch) {
  74. labels['__name__'] = `"${metricMatch[0]}"`;
  75. }
  76. // Build sorted selector
  77. const labelKeys = Object.keys(labels).sort();
  78. const cleanSelector = labelKeys.map(key => `${key}=${labels[key]}`).join(',');
  79. const selectorString = ['{', cleanSelector, '}'].join('');
  80. return { labelKeys, selector: selectorString };
  81. }