completer.ts 6.3 KB

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