completer.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { PrometheusDatasource } from './datasource';
  2. import _ from 'lodash';
  3. export class PromCompleter {
  4. labelQueryCache: any;
  5. labelNameCache: any;
  6. labelValueCache: any;
  7. identifierRegexps = [/\[/, /[a-zA-Z0-9_:]/];
  8. constructor(private datasource: PrometheusDatasource) {
  9. this.labelQueryCache = {};
  10. this.labelNameCache = {};
  11. this.labelValueCache = {};
  12. }
  13. getCompletions(editor, session, pos, prefix, callback) {
  14. let token = session.getTokenAt(pos.row, pos.column);
  15. var metricName;
  16. switch (token.type) {
  17. case 'entity.name.tag':
  18. metricName = this.findMetricName(session, pos.row, pos.column);
  19. if (!metricName) {
  20. callback(null, this.transformToCompletions(['__name__', 'instance', 'job'], 'label name'));
  21. return;
  22. }
  23. if (this.labelNameCache[metricName]) {
  24. callback(null, this.labelNameCache[metricName]);
  25. return;
  26. }
  27. return this.getLabelNameAndValueForMetric(metricName).then(result => {
  28. var labelNames = this.transformToCompletions(
  29. _.uniq(
  30. _.flatten(
  31. result.map(r => {
  32. return Object.keys(r.metric);
  33. })
  34. )
  35. ),
  36. 'label name'
  37. );
  38. this.labelNameCache[metricName] = labelNames;
  39. callback(null, labelNames);
  40. });
  41. case 'string.quoted':
  42. metricName = this.findMetricName(session, pos.row, pos.column);
  43. if (!metricName) {
  44. callback(null, []);
  45. return;
  46. }
  47. var labelNameToken = this.findToken(session, pos.row, pos.column, 'entity.name.tag', null, 'paren.lparen');
  48. if (!labelNameToken) {
  49. callback(null, []);
  50. return;
  51. }
  52. var labelName = labelNameToken.value;
  53. if (this.labelValueCache[metricName] && this.labelValueCache[metricName][labelName]) {
  54. callback(null, this.labelValueCache[metricName][labelName]);
  55. return;
  56. }
  57. return this.getLabelNameAndValueForMetric(metricName).then(result => {
  58. var labelValues = this.transformToCompletions(
  59. _.uniq(
  60. result.map(r => {
  61. return r.metric[labelName];
  62. })
  63. ),
  64. 'label value'
  65. );
  66. this.labelValueCache[metricName] = this.labelValueCache[metricName] || {};
  67. this.labelValueCache[metricName][labelName] = labelValues;
  68. callback(null, labelValues);
  69. });
  70. }
  71. if (token.type === 'paren.lparen' && token.value === '[') {
  72. var vectors = [];
  73. for (let unit of ['s', 'm', 'h']) {
  74. for (let value of [1, 5, 10, 30]) {
  75. vectors.push({
  76. caption: value + unit,
  77. value: '[' + value + unit,
  78. meta: 'range vector',
  79. });
  80. }
  81. }
  82. vectors.unshift({
  83. caption: '$__interval_ms',
  84. value: '[$__interval_ms',
  85. meta: 'range vector',
  86. });
  87. vectors.unshift({
  88. caption: '$__interval',
  89. value: '[$__interval',
  90. meta: 'range vector',
  91. });
  92. callback(null, vectors);
  93. return;
  94. }
  95. var query = prefix;
  96. return this.datasource.performSuggestQuery(query, true).then(metricNames => {
  97. callback(
  98. null,
  99. metricNames.map(name => {
  100. let value = name;
  101. if (prefix === '(') {
  102. value = '(' + name;
  103. }
  104. return {
  105. caption: name,
  106. value: value,
  107. meta: 'metric',
  108. };
  109. })
  110. );
  111. });
  112. }
  113. getLabelNameAndValueForMetric(metricName) {
  114. if (this.labelQueryCache[metricName]) {
  115. return Promise.resolve(this.labelQueryCache[metricName]);
  116. }
  117. var op = '=~';
  118. if (/[a-zA-Z_:][a-zA-Z0-9_:]*/.test(metricName)) {
  119. op = '=';
  120. }
  121. var expr = '{__name__' + op + '"' + metricName + '"}';
  122. return this.datasource.performInstantQuery({ expr: expr }, new Date().getTime() / 1000).then(response => {
  123. this.labelQueryCache[metricName] = response.data.data.result;
  124. return response.data.data.result;
  125. });
  126. }
  127. transformToCompletions(words, meta) {
  128. return words.map(name => {
  129. return {
  130. caption: name,
  131. value: name,
  132. meta: meta,
  133. score: Number.MAX_VALUE,
  134. };
  135. });
  136. }
  137. findMetricName(session, row, column) {
  138. var metricName = '';
  139. var tokens;
  140. var nameLabelNameToken = this.findToken(session, row, column, 'entity.name.tag', '__name__', 'paren.lparen');
  141. if (nameLabelNameToken) {
  142. tokens = session.getTokens(nameLabelNameToken.row);
  143. var nameLabelValueToken = tokens[nameLabelNameToken.index + 2];
  144. if (nameLabelValueToken && nameLabelValueToken.type === 'string.quoted') {
  145. metricName = nameLabelValueToken.value.slice(1, -1); // cut begin/end quotation
  146. }
  147. } else {
  148. var metricNameToken = this.findToken(session, row, column, 'identifier', null, null);
  149. if (metricNameToken) {
  150. tokens = session.getTokens(metricNameToken.row);
  151. if (tokens[metricNameToken.index + 1].type === 'paren.lparen') {
  152. metricName = metricNameToken.value;
  153. }
  154. }
  155. }
  156. return metricName;
  157. }
  158. findToken(session, row, column, target, value, guard) {
  159. var tokens, idx;
  160. for (var r = row; r >= 0; r--) {
  161. tokens = session.getTokens(r);
  162. if (r === row) {
  163. // current row
  164. var c = 0;
  165. for (idx = 0; idx < tokens.length; idx++) {
  166. c += tokens[idx].value.length;
  167. if (c >= column) {
  168. break;
  169. }
  170. }
  171. } else {
  172. idx = tokens.length - 1;
  173. }
  174. for (; idx >= 0; idx--) {
  175. if (tokens[idx].type === guard) {
  176. return null;
  177. }
  178. if (tokens[idx].type === target && (!value || tokens[idx].value === value)) {
  179. tokens[idx].row = r;
  180. tokens[idx].index = idx;
  181. return tokens[idx];
  182. }
  183. }
  184. }
  185. return null;
  186. }
  187. }