completer.ts 5.9 KB

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