fieldExtractors.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Registry, RegistryItem } from '@grafana/data';
  2. export enum FieldExtractorID {
  3. JSON = 'json',
  4. KeyValues = 'kvp',
  5. Auto = 'auto',
  6. }
  7. export interface FieldExtractor extends RegistryItem {
  8. parse: (v: string) => Record<string, any> | undefined;
  9. }
  10. const extJSON: FieldExtractor = {
  11. id: FieldExtractorID.JSON,
  12. name: 'JSON',
  13. description: 'Parse JSON string',
  14. parse: (v: string) => {
  15. return JSON.parse(v);
  16. },
  17. };
  18. function parseKeyValuePairs(raw: string): Record<string, string> {
  19. const buff: string[] = []; // array of characters
  20. let esc = '';
  21. let key = '';
  22. const obj: Record<string, string> = {};
  23. for (let i = 0; i < raw.length; i++) {
  24. let c = raw[i];
  25. if (c === esc) {
  26. esc = '';
  27. c = raw[++i];
  28. }
  29. const isEscaped = c === '\\';
  30. if (isEscaped) {
  31. c = raw[++i];
  32. }
  33. // When escaped just append
  34. if (isEscaped || esc.length) {
  35. buff.push(c);
  36. continue;
  37. }
  38. if (c === `"` || c === `'`) {
  39. esc = c;
  40. }
  41. switch (c) {
  42. case ':':
  43. case '=':
  44. if (buff.length) {
  45. if (key) {
  46. obj[key] = '';
  47. }
  48. key = buff.join('');
  49. buff.length = 0; // clear values
  50. }
  51. break;
  52. // escape chars
  53. case `"`:
  54. case `'`:
  55. // whitespace
  56. case ` `:
  57. case `\n`:
  58. case `\t`:
  59. case `\r`:
  60. case `\n`:
  61. if (buff.length && key === '') {
  62. obj[buff.join('')] = '';
  63. buff.length = 0;
  64. }
  65. // seperators
  66. case ',':
  67. case ';':
  68. case '&':
  69. case '{':
  70. case '}':
  71. if (buff.length) {
  72. const val = buff.join('');
  73. if (key.length) {
  74. obj[key] = val;
  75. key = '';
  76. } else {
  77. key = val;
  78. }
  79. buff.length = 0; // clear values
  80. }
  81. break;
  82. // append our buffer
  83. default:
  84. buff.push(c);
  85. if (i === raw.length - 1) {
  86. if (key === '' && buff.length) {
  87. obj[buff.join('')] = '';
  88. buff.length = 0;
  89. }
  90. }
  91. }
  92. }
  93. if (key.length) {
  94. obj[key] = buff.join('');
  95. }
  96. return obj;
  97. }
  98. const extLabels: FieldExtractor = {
  99. id: FieldExtractorID.KeyValues,
  100. name: 'Key+value pairs',
  101. description: 'Look for a=b, c: d values in the line',
  102. parse: parseKeyValuePairs,
  103. };
  104. const fmts = [extJSON, extLabels];
  105. const extAuto: FieldExtractor = {
  106. id: FieldExtractorID.Auto,
  107. name: 'Auto',
  108. description: 'parse new fields automatically',
  109. parse: (v: string) => {
  110. for (const f of fmts) {
  111. try {
  112. const r = f.parse(v);
  113. if (r != null) {
  114. return r;
  115. }
  116. } catch {} // ignore errors
  117. }
  118. return undefined;
  119. },
  120. };
  121. export const fieldExtractors = new Registry<FieldExtractor>(() => [...fmts, extAuto]);