diff --git a/ui/packages/consul-ui/.eslintrc.js b/ui/packages/consul-ui/.eslintrc.js
index ce7e9cee4a..c5aba82625 100644
--- a/ui/packages/consul-ui/.eslintrc.js
+++ b/ui/packages/consul-ui/.eslintrc.js
@@ -5,8 +5,8 @@ module.exports = {
ecmaVersion: 2018,
sourceType: 'module',
ecmaFeatures: {
- legacyDecorators: true
- }
+ legacyDecorators: true,
+ },
},
plugins: ['ember'],
extends: ['eslint:recommended', 'plugin:ember/recommended'],
@@ -17,7 +17,7 @@ module.exports = {
'no-unused-vars': ['error', { args: 'none' }],
'ember/no-new-mixins': ['warn'],
'ember/no-jquery': 'warn',
- 'ember/no-global-jquery': 'warn'
+ 'ember/no-global-jquery': 'warn',
},
overrides: [
// node files
@@ -31,14 +31,14 @@ module.exports = {
'blueprints/*/index.js',
'config/**/*.js',
'lib/*/index.js',
- 'server/**/*.js'
+ 'server/**/*.js',
],
parserOptions: {
- sourceType: 'script'
+ sourceType: 'script',
},
env: {
browser: false,
- node: true
+ node: true,
},
plugins: ['node'],
rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, {
@@ -46,8 +46,8 @@ module.exports = {
// this can be removed once the following is fixed
// https://github.com/mysticatea/eslint-plugin-node/issues/77
- 'node/no-unpublished-require': 'off'
- })
- }
- ]
+ 'node/no-unpublished-require': 'off',
+ }),
+ },
+ ],
};
diff --git a/ui/packages/consul-ui/.template-lintrc.js b/ui/packages/consul-ui/.template-lintrc.js
index a87bfda6cc..df2f4f9e07 100644
--- a/ui/packages/consul-ui/.template-lintrc.js
+++ b/ui/packages/consul-ui/.template-lintrc.js
@@ -14,7 +14,7 @@ module.exports = {
'no-nested-interactive': false,
'block-indentation': false,
- 'quotes': false,
+ quotes: false,
'no-inline-styles': false,
'no-triple-curlies': false,
@@ -29,6 +29,6 @@ module.exports = {
'no-invalid-role': false,
'no-unnecessary-component-helper': false,
- 'link-href-attributes': false
+ 'link-href-attributes': false,
},
};
diff --git a/ui/packages/consul-ui/app/components/consul/intention/list/index.js b/ui/packages/consul-ui/app/components/consul/intention/list/index.js
index 167ea1730e..01d0181bac 100644
--- a/ui/packages/consul-ui/app/components/consul/intention/list/index.js
+++ b/ui/packages/consul-ui/app/components/consul/intention/list/index.js
@@ -5,7 +5,6 @@ import { tracked } from '@glimmer/tracking';
import { sort } from '@ember/object/computed';
export default class ConsulIntentionList extends Component {
-
@service('filter') filter;
@service('sort') sort;
@service('search') search;
@@ -24,10 +23,10 @@ export default class ConsulIntentionList extends Component {
}
get filtered() {
const predicate = this.filter.predicate('intention');
- return this.args.items.filter(predicate(this.args.filters))
+ return this.args.items.filter(predicate(this.args.filters));
}
get searched() {
- if(typeof this.args.search === 'undefined') {
+ if (typeof this.args.search === 'undefined') {
return this.filtered;
}
const predicate = this.search.predicate('intention');
@@ -37,7 +36,7 @@ export default class ConsulIntentionList extends Component {
return [this.args.sort];
}
get checkedItem() {
- if(this.searched.length === 1) {
+ if (this.searched.length === 1) {
return this.searched[0].SourceName === this.args.search ? this.searched[0] : null;
}
return null;
diff --git a/ui/packages/consul-ui/app/components/consul/intention/list/pageobject.js b/ui/packages/consul-ui/app/components/consul/intention/list/pageobject.js
index 3159a09f57..c8c60d6f43 100644
--- a/ui/packages/consul-ui/app/components/consul/intention/list/pageobject.js
+++ b/ui/packages/consul-ui/app/components/consul/intention/list/pageobject.js
@@ -1,4 +1,6 @@
-export default (collection, clickable, attribute, isPresent, deletable) => (scope = '.consul-intention-list') => {
+export default (collection, clickable, attribute, isPresent, deletable) => (
+ scope = '.consul-intention-list'
+) => {
const row = {
source: attribute('data-test-intention-source', '[data-test-intention-source]'),
destination: attribute('data-test-intention-destination', '[data-test-intention-destination]'),
@@ -10,6 +12,6 @@ export default (collection, clickable, attribute, isPresent, deletable) => (scop
return {
scope: scope,
customResourceNotice: isPresent('.consul-intention-notice-custom-resource'),
- intentions: collection('[data-test-tabular-row]', row)
- }
+ intentions: collection('[data-test-tabular-row]', row),
+ };
};
diff --git a/ui/packages/consul-ui/app/search/predicates/intention.js b/ui/packages/consul-ui/app/search/predicates/intention.js
index 43fa80528a..12da95a264 100644
--- a/ui/packages/consul-ui/app/search/predicates/intention.js
+++ b/ui/packages/consul-ui/app/search/predicates/intention.js
@@ -1,4 +1,4 @@
-export default () => (term) => (item) => {
+export default () => term => item => {
const source = item.SourceName.toLowerCase();
const destination = item.DestinationName.toLowerCase();
const allLabel = 'All Services (*)'.toLowerCase();
@@ -9,4 +9,4 @@ export default () => (term) => (item) => {
(source === '*' && allLabel.indexOf(lowerTerm) !== -1) ||
(destination === '*' && allLabel.indexOf(lowerTerm) !== -1)
);
-}
+};
diff --git a/ui/packages/consul-ui/app/services/repository/intention.js b/ui/packages/consul-ui/app/services/repository/intention.js
index 1c4d627dd3..7489b3bebc 100644
--- a/ui/packages/consul-ui/app/services/repository/intention.js
+++ b/ui/packages/consul-ui/app/services/repository/intention.js
@@ -4,7 +4,6 @@ import { PRIMARY_KEY } from 'consul-ui/models/intention';
const modelName = 'intention';
export default class IntentionRepository extends RepositoryService {
-
managedByCRDs = false;
getModelName() {
@@ -24,9 +23,11 @@ export default class IntentionRepository extends RepositoryService {
}
isManagedByCRDs() {
- if(!this.managedByCRDs) {
- this.managedByCRDs = this.store.peekAll(this.getModelName())
- .toArray().some(item => item.IsManagedByCRD);
+ if (!this.managedByCRDs) {
+ this.managedByCRDs = this.store
+ .peekAll(this.getModelName())
+ .toArray()
+ .some(item => item.IsManagedByCRD);
}
return this.managedByCRDs;
}
diff --git a/ui/packages/consul-ui/ember-cli-build.js b/ui/packages/consul-ui/ember-cli-build.js
index 3df8ce3808..ab756fc284 100644
--- a/ui/packages/consul-ui/ember-cli-build.js
+++ b/ui/packages/consul-ui/ember-cli-build.js
@@ -8,18 +8,15 @@ module.exports = function(defaults) {
const isProdLike = prodlike.indexOf(env) > -1;
const sourcemaps = !isProd;
let trees = {};
- if(isProdLike) {
+ if (isProdLike) {
// exclude any component/pageobject.js files from production-like environments
- trees.app = new Funnel(
- 'app',
- {
- exclude: [
- 'components/**/pageobject.js',
- 'components/**/*.test-support.js',
- 'components/**/*.test.js'
- ]
- }
- );
+ trees.app = new Funnel('app', {
+ exclude: [
+ 'components/**/pageobject.js',
+ 'components/**/*.test-support.js',
+ 'components/**/*.test.js',
+ ],
+ });
}
let app = new EmberApp(
Object.assign({}, defaults, {
@@ -31,14 +28,7 @@ module.exports = function(defaults) {
includePolyfill: true,
},
'ember-cli-string-helpers': {
- only: [
- 'capitalize',
- 'lowercase',
- 'truncate',
- 'uppercase',
- 'humanize',
- 'titleize'
- ],
+ only: ['capitalize', 'lowercase', 'truncate', 'uppercase', 'humanize', 'titleize'],
},
'ember-cli-math-helpers': {
only: ['div'],
diff --git a/ui/packages/consul-ui/package.json b/ui/packages/consul-ui/package.json
index 84f74b2dc0..eb6226a972 100644
--- a/ui/packages/consul-ui/package.json
+++ b/ui/packages/consul-ui/package.json
@@ -15,7 +15,7 @@
"lint:dev:js": "eslint -c .dev.eslintrc.js --fix ./*.js ./.*.js app config lib server tests",
"lint:hbs": "ember-template-lint .",
"lint:js": "eslint .",
- "format:js": "prettier --write \"{app,config,lib,server,tests}/**/*.js\" ./*.js ./.*.js",
+ "format:js": "prettier --write \"{app,config,lib,server,vendor,tests}/**/*.js\" ./*.js ./.*.js",
"format:css": "prettier --write \"app/styles/**/*.*\"",
"start": "ember serve --port=${EMBER_SERVE_PORT:-4200} --live-reload-port=${EMBER_LIVE_RELOAD_PORT:-7020}",
"start:staging": "ember serve --port=${EMBER_SERVE_PORT:-4200} --live-reload-port=${EMBER_LIVE_RELOAD_PORT:-7020} --environment staging",
@@ -42,7 +42,7 @@
}
},
"lint-staged": {
- "{app,config,lib,server,tests}/**/*.js": [
+ "{app,config,lib,server,vendor,tests}/**/*.js": [
"prettier --write"
],
"app/styles/**/*.*": [
diff --git a/ui/packages/consul-ui/testem.js b/ui/packages/consul-ui/testem.js
index 88ff011ccc..3a84839e85 100644
--- a/ui/packages/consul-ui/testem.js
+++ b/ui/packages/consul-ui/testem.js
@@ -1,12 +1,8 @@
module.exports = {
test_page: 'tests/index.html?hidepassed',
disable_watching: true,
- launch_in_ci: [
- 'Chrome'
- ],
- launch_in_dev: [
- 'Chrome'
- ],
+ launch_in_ci: ['Chrome'],
+ launch_in_dev: ['Chrome'],
browser_start_timeout: 120,
browser_args: {
Chrome: {
@@ -39,5 +35,5 @@ if (process.env.EMBER_TEST_REPORT) {
* https://github.com/trentmwillis/ember-exam/issues/108
*/
if (process.env.EMBER_EXAM_PARALLEL) {
- module.exports.parallel = -1
+ module.exports.parallel = -1;
}
diff --git a/ui/packages/consul-ui/tests/pages/dc/intentions/index.js b/ui/packages/consul-ui/tests/pages/dc/intentions/index.js
index 65b3b8bdaf..9e3b1176ba 100644
--- a/ui/packages/consul-ui/tests/pages/dc/intentions/index.js
+++ b/ui/packages/consul-ui/tests/pages/dc/intentions/index.js
@@ -3,6 +3,6 @@ export default function(visitable, creatable, clickable, intentions, popoverSele
visit: visitable('/:dc/intentions'),
intentionList: intentions(),
sort: popoverSelect('[data-test-sort-control]'),
- ...creatable({})
- }
+ ...creatable({}),
+ };
}
diff --git a/ui/packages/consul-ui/tests/steps/assertions/model.js b/ui/packages/consul-ui/tests/steps/assertions/model.js
index 227f39ed2b..220bdfc163 100644
--- a/ui/packages/consul-ui/tests/steps/assertions/model.js
+++ b/ui/packages/consul-ui/tests/steps/assertions/model.js
@@ -11,7 +11,11 @@ export default function(scenario, assert, find, currentPage, pauseUntil, plurali
return retry();
}, `Expected ${num} ${model}s`);
})
- .then('pause until I see $number $model model[s]? on the $component component', function(num, model, component) {
+ .then('pause until I see $number $model model[s]? on the $component component', function(
+ num,
+ model,
+ component
+ ) {
return pauseUntil(function(resolve, reject, retry) {
const obj = find(component);
const len = obj[pluralize(model)].filter(function(item) {
diff --git a/ui/packages/consul-ui/tests/steps/doubles/model.js b/ui/packages/consul-ui/tests/steps/doubles/model.js
index f02bdbf50a..75a0cb981e 100644
--- a/ui/packages/consul-ui/tests/steps/doubles/model.js
+++ b/ui/packages/consul-ui/tests/steps/doubles/model.js
@@ -14,7 +14,8 @@ export default function(scenario, create) {
function(number, model, data) {
return create(number, model, data);
}
- ).given(['settings from yaml\n$yaml'], function(data) {
+ )
+ .given(['settings from yaml\n$yaml'], function(data) {
return Object.keys(data).forEach(function(key) {
window.localStorage[key] = JSON.stringify(data[key]);
});
diff --git a/ui/packages/consul-ui/tests/steps/interactions/click.js b/ui/packages/consul-ui/tests/steps/interactions/click.js
index 65a93f8ec1..d1ef934f43 100644
--- a/ui/packages/consul-ui/tests/steps/interactions/click.js
+++ b/ui/packages/consul-ui/tests/steps/interactions/click.js
@@ -4,22 +4,21 @@ export default function(scenario, find, click) {
return click(selector);
})
// TODO: Probably nicer to think of better vocab than having the 'without " rule'
- .when([
- 'I click (?!")$property(?!")',
- 'I click $property on the $component',
- 'I click $property on the $component component'
- ], function(
- property,
- component,
- next
- ) {
- try {
- if (typeof component === 'string') {
- property = `${component}.${property}`;
+ .when(
+ [
+ 'I click (?!")$property(?!")',
+ 'I click $property on the $component',
+ 'I click $property on the $component component',
+ ],
+ function(property, component, next) {
+ try {
+ if (typeof component === 'string') {
+ property = `${component}.${property}`;
+ }
+ return find(property)();
+ } catch (e) {
+ throw e;
}
- return find(property)();
- } catch (e) {
- throw e;
}
- });
+ );
}
diff --git a/ui/packages/consul-ui/tests/unit/helpers/selectable-key-values-test.js b/ui/packages/consul-ui/tests/unit/helpers/selectable-key-values-test.js
index 76090b3072..82ef447811 100644
--- a/ui/packages/consul-ui/tests/unit/helpers/selectable-key-values-test.js
+++ b/ui/packages/consul-ui/tests/unit/helpers/selectable-key-values-test.js
@@ -3,21 +3,36 @@ import { module, test } from 'qunit';
module('Unit | Helper | selectable-key-values', function() {
test('it turns arrays into key values and selects the first item by default', function(assert) {
- const actual = selectableKeyValues([['key-1', 'value-1'], ['key-2', 'value-2']]);
+ const actual = selectableKeyValues([
+ ['key-1', 'value-1'],
+ ['key-2', 'value-2'],
+ ]);
assert.equal(actual.items.length, 2);
assert.deepEqual(actual.selected, { key: 'key-1', value: 'value-1' });
});
test('it turns arrays into key values and selects the defined key', function(assert) {
- const actual = selectableKeyValues([['key-1', 'value-1'], ['key-2', 'value-2']], {
- selected: 'key-2',
- });
+ const actual = selectableKeyValues(
+ [
+ ['key-1', 'value-1'],
+ ['key-2', 'value-2'],
+ ],
+ {
+ selected: 'key-2',
+ }
+ );
assert.equal(actual.items.length, 2);
assert.deepEqual(actual.selected, { key: 'key-2', value: 'value-2' });
});
test('it turns arrays into key values and selects the defined index', function(assert) {
- const actual = selectableKeyValues([['key-1', 'value-1'], ['key-2', 'value-2']], {
- selected: 1,
- });
+ const actual = selectableKeyValues(
+ [
+ ['key-1', 'value-1'],
+ ['key-2', 'value-2'],
+ ],
+ {
+ selected: 1,
+ }
+ );
assert.equal(actual.items.length, 2);
assert.deepEqual(actual.selected, { key: 'key-2', value: 'value-2' });
});
diff --git a/ui/packages/consul-ui/vendor/metrics-providers/consul.js b/ui/packages/consul-ui/vendor/metrics-providers/consul.js
index 9ba2bdc9f2..a77f64e907 100644
--- a/ui/packages/consul-ui/vendor/metrics-providers/consul.js
+++ b/ui/packages/consul-ui/vendor/metrics-providers/consul.js
@@ -1,51 +1,47 @@
-(
- function(global) {
- // Current interface is these three methods.
- const requiredMethods = [
- 'init',
- 'serviceRecentSummarySeries',
- 'serviceRecentSummaryStats',
- 'upstreamRecentSummaryStats',
- 'downstreamRecentSummaryStats',
- ];
+(function(global) {
+ // Current interface is these three methods.
+ const requiredMethods = [
+ 'init',
+ 'serviceRecentSummarySeries',
+ 'serviceRecentSummaryStats',
+ 'upstreamRecentSummaryStats',
+ 'downstreamRecentSummaryStats',
+ ];
- // This is a bit gross but we want to support simple extensibility by
- // including JS in the browser without forcing operators to setup a whole
- // transpiling stack. So for now we use a window global as a thin registry for
- // these providers.
- class Consul {
- constructor() {
- this.registry = {};
- this.providers = {};
- }
-
- registerMetricsProvider(name, provider) {
- // Basic check that it matches the type we expect
- for (var m of requiredMethods) {
- if (typeof provider[m] !== 'function') {
- throw new Error(`Can't register metrics provider '${name}': missing ${m} method.`);
- }
- }
- this.registry[name] = provider;
- }
-
- getMetricsProvider(name, options) {
- if (!(name in this.registry)) {
- throw new Error(`Metrics Provider '${name}' is not registered.`);
- }
- if (name in this.providers) {
- return this.providers[name];
- }
-
- this.providers[name] = Object.create(this.registry[name]);
- this.providers[name].init(options);
-
- return this.providers[name];
- }
+ // This is a bit gross but we want to support simple extensibility by
+ // including JS in the browser without forcing operators to setup a whole
+ // transpiling stack. So for now we use a window global as a thin registry for
+ // these providers.
+ class Consul {
+ constructor() {
+ this.registry = {};
+ this.providers = {};
}
- global.consul = new Consul();
+ registerMetricsProvider(name, provider) {
+ // Basic check that it matches the type we expect
+ for (var m of requiredMethods) {
+ if (typeof provider[m] !== 'function') {
+ throw new Error(`Can't register metrics provider '${name}': missing ${m} method.`);
+ }
+ }
+ this.registry[name] = provider;
+ }
+ getMetricsProvider(name, options) {
+ if (!(name in this.registry)) {
+ throw new Error(`Metrics Provider '${name}' is not registered.`);
+ }
+ if (name in this.providers) {
+ return this.providers[name];
+ }
+
+ this.providers[name] = Object.create(this.registry[name]);
+ this.providers[name].init(options);
+
+ return this.providers[name];
+ }
}
-)(window);
+ global.consul = new Consul();
+})(window);
diff --git a/ui/packages/consul-ui/vendor/metrics-providers/prometheus.js b/ui/packages/consul-ui/vendor/metrics-providers/prometheus.js
index d48f2a9a5e..586edbef48 100644
--- a/ui/packages/consul-ui/vendor/metrics-providers/prometheus.js
+++ b/ui/packages/consul-ui/vendor/metrics-providers/prometheus.js
@@ -1,6 +1,6 @@
/*eslint no-console: "off"*/
-(function () {
- var emptySeries = { unitSuffix: "", labels: {}, data: [] }
+(function() {
+ var emptySeries = { unitSuffix: '', labels: {}, data: [] };
var prometheusProvider = {
options: {},
@@ -26,7 +26,9 @@
init: function(options) {
this.options = options;
if (!this.options.metrics_proxy_enabled) {
- throw new Error("prometheus metrics provider currently requires the ui_config.metrics_proxy to be configured in the Consul agent.");
+ throw new Error(
+ 'prometheus metrics provider currently requires the ui_config.metrics_proxy to be configured in the Consul agent.'
+ );
}
},
@@ -36,26 +38,24 @@
httpGet: function(url, queryParams, headers) {
if (queryParams) {
var separator = url.indexOf('?') !== -1 ? '&' : '?';
- var qs = Object.keys(queryParams).
- map(function(key) {
- return encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key]);
- }).
- join("&");
+ var qs = Object.keys(queryParams)
+ .map(function(key) {
+ return encodeURIComponent(key) + '=' + encodeURIComponent(queryParams[key]);
+ })
+ .join('&');
url = url + separator + qs;
}
// fetch the url along with any headers
- return this.options.fetch(url, {headers: headers || {}}).then(
- function(response) {
- if(response.ok) {
- return response.json();
- } else {
- // throw a statusCode error if any errors are received
- var e = new Error('HTTP Error: ' + response.statusText);
- e.statusCode = response.status;
- throw e;
- }
+ return this.options.fetch(url, { headers: headers || {} }).then(function(response) {
+ if (response.ok) {
+ return response.json();
+ } else {
+ // throw a statusCode error if any errors are received
+ var e = new Error('HTTP Error: ' + response.statusText);
+ e.statusCode = response.status;
+ throw e;
}
- );
+ });
},
/**
@@ -114,13 +114,13 @@
*/
serviceRecentSummarySeries: function(serviceDC, namespace, serviceName, protocol, options) {
// Fetch time-series
- var series = []
- var labels = []
+ var series = [];
+ var labels = [];
// Set the start and end range here so that all queries end up with
// identical time axes. Later we might accept these as options.
- var now = (new Date()).getTime()/1000;
- options.start = now - (15*60);
+ var now = new Date().getTime() / 1000;
+ options.start = now - 15 * 60;
options.end = now;
if (this.hasL7Metrics(protocol)) {
@@ -169,18 +169,18 @@
// Fetch stats
var stats = [];
if (this.hasL7Metrics(protocol)) {
- stats.push(this.fetchRPS(serviceName, "service", options))
- stats.push(this.fetchER(serviceName, "service", options))
- stats.push(this.fetchPercentile(50, serviceName, "service", options))
- stats.push(this.fetchPercentile(99, serviceName, "service", options))
+ stats.push(this.fetchRPS(serviceName, 'service', options));
+ stats.push(this.fetchER(serviceName, 'service', options));
+ stats.push(this.fetchPercentile(50, serviceName, 'service', options));
+ stats.push(this.fetchPercentile(99, serviceName, 'service', options));
} else {
// Fallback to just L4 metrics.
- stats.push(this.fetchConnRate(serviceName, "service", options))
- stats.push(this.fetchServiceRx(serviceName, "service", options))
- stats.push(this.fetchServiceTx(serviceName, "service", options))
- stats.push(this.fetchServiceNoRoute(serviceName, "service", options))
+ stats.push(this.fetchConnRate(serviceName, 'service', options));
+ stats.push(this.fetchServiceRx(serviceName, 'service', options));
+ stats.push(this.fetchServiceTx(serviceName, 'service', options));
+ stats.push(this.fetchServiceNoRoute(serviceName, 'service', options));
}
- return this.fetchStats(stats)
+ return this.fetchStats(stats);
},
/**
@@ -217,7 +217,7 @@
* }
*/
upstreamRecentSummaryStats: function(serviceDC, namespace, serviceName, upstreamName, options) {
- return this.fetchRecentSummaryStats(serviceName, "upstream", options)
+ return this.fetchRecentSummaryStats(serviceName, 'upstream', options);
},
/**
@@ -260,7 +260,7 @@
* }
*/
downstreamRecentSummaryStats: function(serviceDC, namespace, serviceName, options) {
- return this.fetchRecentSummaryStats(serviceName, "downstream", options)
+ return this.fetchRecentSummaryStats(serviceName, 'downstream', options);
},
fetchRecentSummaryStats: function(serviceName, type, options) {
@@ -270,74 +270,76 @@
// We don't know which upstreams are HTTP/TCP so just fetch all of them.
// HTTP
- stats.push(this.fetchRPS(serviceName, type, options))
- stats.push(this.fetchER(serviceName, type, options))
- stats.push(this.fetchPercentile(50, serviceName, type, options))
- stats.push(this.fetchPercentile(99, serviceName, type, options))
+ stats.push(this.fetchRPS(serviceName, type, options));
+ stats.push(this.fetchER(serviceName, type, options));
+ stats.push(this.fetchPercentile(50, serviceName, type, options));
+ stats.push(this.fetchPercentile(99, serviceName, type, options));
// L4
- stats.push(this.fetchConnRate(serviceName, type, options))
- stats.push(this.fetchServiceRx(serviceName, type, options))
- stats.push(this.fetchServiceTx(serviceName, type, options))
- stats.push(this.fetchServiceNoRoute(serviceName, type, options))
+ stats.push(this.fetchConnRate(serviceName, type, options));
+ stats.push(this.fetchServiceRx(serviceName, type, options));
+ stats.push(this.fetchServiceTx(serviceName, type, options));
+ stats.push(this.fetchServiceNoRoute(serviceName, type, options));
- return this.fetchStatsGrouped(stats)
+ return this.fetchStatsGrouped(stats);
},
hasL7Metrics: function(protocol) {
- return protocol === "http" || protocol === "http2" || protocol === "grpc"
+ return protocol === 'http' || protocol === 'http2' || protocol === 'grpc';
},
fetchStats: function(statsPromises) {
- var all = Promise.all(statsPromises).
- then(function(results){
+ var all = Promise.all(statsPromises).then(function(results) {
var data = {
- stats: []
- }
+ stats: [],
+ };
// Add all non-empty stats
for (var i = 0; i < statsPromises.length; i++) {
if (results[i].value) {
data.stats.push(results[i]);
}
}
- return data
- })
+ return data;
+ });
// Fetch the metrics async, and return a promise to the result.
- return all
+ return all;
},
fetchStatsGrouped: function(statsPromises) {
- var all = Promise.all(statsPromises).
- then(function(results){
+ var all = Promise.all(statsPromises).then(function(results) {
var data = {
- stats: {}
- }
+ stats: {},
+ };
// Add all non-empty stats
for (var i = 0; i < statsPromises.length; i++) {
if (results[i]) {
for (var group in results[i]) {
if (!results[i].hasOwnProperty(group)) continue;
if (!data.stats[group]) {
- data.stats[group] = []
+ data.stats[group] = [];
}
- data.stats[group].push(results[i][group])
+ data.stats[group].push(results[i][group]);
}
}
}
- return data
- })
+ return data;
+ });
// Fetch the metrics async, and return a promise to the result.
- return all
+ return all;
},
reformatSeries: function(unitSuffix, labelMap) {
return function(response) {
// Handle empty result sets gracefully.
- if (!response.data || !response.data.result || response.data.result.length == 0
- || !response.data.result[0].values
- || response.data.result[0].values.length == 0) {
+ if (
+ !response.data ||
+ !response.data.result ||
+ response.data.result.length == 0 ||
+ !response.data.result[0].values ||
+ response.data.result[0].values.length == 0
+ ) {
return emptySeries;
}
// Reformat the prometheus data to be the format we want with stacked
@@ -362,306 +364,315 @@
return {
unitSuffix: unitSuffix,
labels: labelMap,
- data: series
+ data: series,
};
};
},
- fetchRequestRateSeries: function(serviceName, options){
+ fetchRequestRateSeries: function(serviceName, options) {
// We need the sum of all non-500 error rates as one value and the 500
// error rate as a separate series so that they stack to show the full
// request rate. Some creative label replacement makes this possible in
// one query.
- var q = `sum by (label) (`+
+ var q =
+ `sum by (label) (` +
// The outer label_replace catches 5xx error and relabels them as
// err=yes
- `label_replace(`+
- // The inner label_replace relabels all !5xx rates as err=no so they
- // will get summed together.
- `label_replace(`+
- // Get rate of requests to the service
- `irate(envoy_listener_http_downstream_rq_xx{local_cluster="${serviceName}",envoy_http_conn_manager_prefix="public_listener_http"}[10m])`+
- // ... inner replacement matches all code classes except "5" and
- // applies err=no
- `, "label", "Successes", "envoy_response_code_class", "[^5]")`+
- // ... outer replacement matches code=5 and applies err=yes
- `, "label", "Errors", "envoy_response_code_class", "5")`+
- `)`
+ `label_replace(` +
+ // The inner label_replace relabels all !5xx rates as err=no so they
+ // will get summed together.
+ `label_replace(` +
+ // Get rate of requests to the service
+ `irate(envoy_listener_http_downstream_rq_xx{local_cluster="${serviceName}",envoy_http_conn_manager_prefix="public_listener_http"}[10m])` +
+ // ... inner replacement matches all code classes except "5" and
+ // applies err=no
+ `, "label", "Successes", "envoy_response_code_class", "[^5]")` +
+ // ... outer replacement matches code=5 and applies err=yes
+ `, "label", "Errors", "envoy_response_code_class", "5")` +
+ `)`;
var labelMap = {
Total: 'Total inbound requests per second',
- Successes: 'Successful responses (with an HTTP response code not in the 5xx range) per second.',
+ Successes:
+ 'Successful responses (with an HTTP response code not in the 5xx range) per second.',
Errors: 'Error responses (with an HTTP response code in the 5xx range) per second.',
};
- return this.fetchSeries(q, options)
- .then(this.reformatSeries(" rps", labelMap))
+ return this.fetchSeries(q, options).then(this.reformatSeries(' rps', labelMap));
},
- fetchDataRateSeries: function(serviceName, options){
+ fetchDataRateSeries: function(serviceName, options) {
// 8 * converts from bytes/second to bits/second
- var q = `8 * sum by (label) (`+
+ var q =
+ `8 * sum by (label) (` +
// Label replace generates a unique label per rx/tx metric to stop them
// being summed together.
- `label_replace(`+
- // Get the tx rate
- `irate(envoy_tcp_downstream_cx_tx_bytes_total{local_cluster="${serviceName}",envoy_tcp_prefix="public_listener_tcp"}[10m])`+
- // Match all and apply the tx label
- `, "label", "Outbound", "__name__", ".*"`+
+ `label_replace(` +
+ // Get the tx rate
+ `irate(envoy_tcp_downstream_cx_tx_bytes_total{local_cluster="${serviceName}",envoy_tcp_prefix="public_listener_tcp"}[10m])` +
+ // Match all and apply the tx label
+ `, "label", "Outbound", "__name__", ".*"` +
// Union those vectors with the RX ones
- `) or label_replace(`+
- // Get the rx rate
- `irate(envoy_tcp_downstream_cx_rx_bytes_total{local_cluster="${serviceName}",envoy_tcp_prefix="public_listener_tcp"}[10m])`+
- // Match all and apply the rx label
- `, "label", "Inbound", "__name__", ".*"`+
- `)`+
- `)`
+ `) or label_replace(` +
+ // Get the rx rate
+ `irate(envoy_tcp_downstream_cx_rx_bytes_total{local_cluster="${serviceName}",envoy_tcp_prefix="public_listener_tcp"}[10m])` +
+ // Match all and apply the rx label
+ `, "label", "Inbound", "__name__", ".*"` +
+ `)` +
+ `)`;
var labelMap = {
Total: 'Total bandwidth',
Inbound: 'Inbound data rate (data recieved) from the network in bits per second.',
Outbound: 'Outbound data rate (data transmitted) from the network in bits per second.',
};
- return this.fetchSeries(q, options)
- .then(this.reformatSeries("bps", labelMap))
+ return this.fetchSeries(q, options).then(this.reformatSeries('bps', labelMap));
},
makeSubject: function(serviceName, type) {
- if (type == "upstream") {
+ if (type == 'upstream') {
// {{GROUP}} is a placeholder that is replaced by the upstream name
return `${serviceName} → {{GROUP}}`;
}
- if (type == "downstream") {
+ if (type == 'downstream') {
// {{GROUP}} is a placeholder that is replaced by the downstream name
return `{{GROUP}} → ${serviceName}`;
}
- return serviceName
+ return serviceName;
},
makeHTTPSelector: function(serviceName, type) {
// Downstreams are totally different
- if (type == "downstream") {
- return `consul_service="${serviceName}"`
+ if (type == 'downstream') {
+ return `consul_service="${serviceName}"`;
}
- var lc = `local_cluster="${serviceName}"`
- if (type == "upstream") {
+ var lc = `local_cluster="${serviceName}"`;
+ if (type == 'upstream') {
lc += `,envoy_http_conn_manager_prefix=~"upstream_.*"`;
} else {
// Only care about inbound public listener
- lc += `,envoy_http_conn_manager_prefix="public_listener_http"`
+ lc += `,envoy_http_conn_manager_prefix="public_listener_http"`;
}
- return lc
+ return lc;
},
makeTCPSelector: function(serviceName, type) {
// Downstreams are totally different
- if (type == "downstream") {
- return `consul_service="${serviceName}"`
+ if (type == 'downstream') {
+ return `consul_service="${serviceName}"`;
}
- var lc = `local_cluster="${serviceName}"`
- if (type == "upstream") {
+ var lc = `local_cluster="${serviceName}"`;
+ if (type == 'upstream') {
lc += `,envoy_tcp_prefix=~"upstream_.*"`;
} else {
// Only care about inbound public listener
- lc += `,envoy_tcp_prefix="public_listener_tcp"`
+ lc += `,envoy_tcp_prefix="public_listener_tcp"`;
}
- return lc
+ return lc;
},
groupQueryHTTP: function(type, q) {
- if (type == "upstream") {
- q += " by (envoy_http_conn_manager_prefix)"
+ if (type == 'upstream') {
+ q += ' by (envoy_http_conn_manager_prefix)';
// Extract the raw upstream service name to group results by
- q = this.upstreamRelabelQueryHTTP(q)
- } else if (type == "downstream") {
- q += " by (local_cluster)"
- q = this.downstreamRelabelQuery(q)
+ q = this.upstreamRelabelQueryHTTP(q);
+ } else if (type == 'downstream') {
+ q += ' by (local_cluster)';
+ q = this.downstreamRelabelQuery(q);
}
- return q
+ return q;
},
groupQueryTCP: function(type, q) {
- if (type == "upstream") {
- q += " by (envoy_tcp_prefix)"
+ if (type == 'upstream') {
+ q += ' by (envoy_tcp_prefix)';
// Extract the raw upstream service name to group results by
- q = this.upstreamRelabelQueryTCP(q)
- } else if (type == "downstream") {
- q += " by (local_cluster)"
- q = this.downstreamRelabelQuery(q)
+ q = this.upstreamRelabelQueryTCP(q);
+ } else if (type == 'downstream') {
+ q += ' by (local_cluster)';
+ q = this.downstreamRelabelQuery(q);
}
- return q
+ return q;
},
upstreamRelabelQueryHTTP: function(q) {
- return `label_replace(${q}, "upstream", "$1", "envoy_http_conn_manager_prefix", "upstream_(.*)_http")`
+ return `label_replace(${q}, "upstream", "$1", "envoy_http_conn_manager_prefix", "upstream_(.*)_http")`;
},
upstreamRelabelQueryTCP: function(q) {
- return `label_replace(${q}, "upstream", "$1", "envoy_tcp_prefix", "upstream_(.*)_tcp")`
+ return `label_replace(${q}, "upstream", "$1", "envoy_tcp_prefix", "upstream_(.*)_tcp")`;
},
downstreamRelabelQuery: function(q) {
- return `label_replace(${q}, "downstream", "$1", "local_cluster", "(.*)")`
+ return `label_replace(${q}, "downstream", "$1", "local_cluster", "(.*)")`;
},
groupBy: function(type) {
- if (type == "service") {
- return false
+ if (type == 'service') {
+ return false;
}
return type;
},
metricPrefixHTTP: function(type) {
- if (type == "downstream") {
- return "envoy_cluster_upstream_rq"
+ if (type == 'downstream') {
+ return 'envoy_cluster_upstream_rq';
}
- return "envoy_http_downstream_rq";
+ return 'envoy_http_downstream_rq';
},
metricPrefixTCP: function(type) {
- if (type == "downstream") {
- return "envoy_cluster_upstream_cx"
+ if (type == 'downstream') {
+ return 'envoy_cluster_upstream_cx';
}
- return "envoy_tcp_downstream_cx";
+ return 'envoy_tcp_downstream_cx';
},
- fetchRPS: function(serviceName, type, options){
- var sel = this.makeHTTPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var metricPfx = this.metricPrefixHTTP(type)
- var q = `sum(rate(${metricPfx}_completed{${sel}}[15m]))`
- return this.fetchStat(this.groupQueryHTTP(type, q),
- "RPS",
+ fetchRPS: function(serviceName, type, options) {
+ var sel = this.makeHTTPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var metricPfx = this.metricPrefixHTTP(type);
+ var q = `sum(rate(${metricPfx}_completed{${sel}}[15m]))`;
+ return this.fetchStat(
+ this.groupQueryHTTP(type, q),
+ 'RPS',
`${subject} request rate averaged over the last 15 minutes`,
shortNumStr,
this.groupBy(type)
- )
+ );
},
- fetchER: function(serviceName, type, options){
- var sel = this.makeHTTPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var groupBy = ""
- if (type == "upstream") {
- groupBy += " by (envoy_http_conn_manager_prefix)"
- } else if (type == "downstream") {
- groupBy += " by (local_cluster)"
+ fetchER: function(serviceName, type, options) {
+ var sel = this.makeHTTPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var groupBy = '';
+ if (type == 'upstream') {
+ groupBy += ' by (envoy_http_conn_manager_prefix)';
+ } else if (type == 'downstream') {
+ groupBy += ' by (local_cluster)';
}
- var metricPfx = this.metricPrefixHTTP(type)
- var q = `sum(rate(${metricPfx}_xx{${sel},envoy_response_code_class="5"}[15m]))${groupBy}/sum(rate(${metricPfx}_xx{${sel}}[15m]))${groupBy}`
- if (type == "upstream") {
- q = this.upstreamRelabelQueryHTTP(q)
- } else if (type == "downstream") {
- q = this.downstreamRelabelQuery(q)
+ var metricPfx = this.metricPrefixHTTP(type);
+ var q = `sum(rate(${metricPfx}_xx{${sel},envoy_response_code_class="5"}[15m]))${groupBy}/sum(rate(${metricPfx}_xx{${sel}}[15m]))${groupBy}`;
+ if (type == 'upstream') {
+ q = this.upstreamRelabelQueryHTTP(q);
+ } else if (type == 'downstream') {
+ q = this.downstreamRelabelQuery(q);
}
- return this.fetchStat(q,
- "ER",
+ return this.fetchStat(
+ q,
+ 'ER',
`Percentage of ${subject} requests which were 5xx status over the last 15 minutes`,
- function(val){
- return shortNumStr(val)+"%"
+ function(val) {
+ return shortNumStr(val) + '%';
},
this.groupBy(type)
- )
+ );
},
- fetchPercentile: function(percentile, serviceName, type, options){
- var sel = this.makeHTTPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var groupBy = "le"
- if (type == "upstream") {
- groupBy += ",envoy_http_conn_manager_prefix"
- } else if (type == "downstream") {
- groupBy += ",local_cluster"
+ fetchPercentile: function(percentile, serviceName, type, options) {
+ var sel = this.makeHTTPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var groupBy = 'le';
+ if (type == 'upstream') {
+ groupBy += ',envoy_http_conn_manager_prefix';
+ } else if (type == 'downstream') {
+ groupBy += ',local_cluster';
}
- var metricPfx = this.metricPrefixHTTP(type)
- var q = `histogram_quantile(${percentile/100}, sum by(${groupBy}) (rate(${metricPfx}_time_bucket{${sel}}[15m])))`
- if (type == "upstream") {
- q = this.upstreamRelabelQueryHTTP(q)
- } else if (type == "downstream") {
- q = this.downstreamRelabelQuery(q)
+ var metricPfx = this.metricPrefixHTTP(type);
+ var q = `histogram_quantile(${percentile /
+ 100}, sum by(${groupBy}) (rate(${metricPfx}_time_bucket{${sel}}[15m])))`;
+ if (type == 'upstream') {
+ q = this.upstreamRelabelQueryHTTP(q);
+ } else if (type == 'downstream') {
+ q = this.downstreamRelabelQuery(q);
}
- return this.fetchStat(q,
+ return this.fetchStat(
+ q,
`P${percentile}`,
`${subject} ${percentile}th percentile request service time over the last 15 minutes`,
shortTimeStr,
this.groupBy(type)
- )
+ );
},
fetchConnRate: function(serviceName, type, options) {
- var sel = this.makeTCPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var metricPfx = this.metricPrefixTCP(type)
- var q = `sum(rate(${metricPfx}_total{${sel}}[15m]))`
- return this.fetchStat(this.groupQueryTCP(type, q),
- "CR",
+ var sel = this.makeTCPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var metricPfx = this.metricPrefixTCP(type);
+ var q = `sum(rate(${metricPfx}_total{${sel}}[15m]))`;
+ return this.fetchStat(
+ this.groupQueryTCP(type, q),
+ 'CR',
`${subject} inbound TCP connections per second averaged over the last 15 minutes`,
shortNumStr,
this.groupBy(type)
- )
+ );
},
fetchServiceRx: function(serviceName, type, options) {
- var sel = this.makeTCPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var metricPfx = this.metricPrefixTCP(type)
- var q = `8 * sum(rate(${metricPfx}_rx_bytes_total{${sel}}[15m]))`
- return this.fetchStat(this.groupQueryTCP(type, q),
- "RX",
+ var sel = this.makeTCPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var metricPfx = this.metricPrefixTCP(type);
+ var q = `8 * sum(rate(${metricPfx}_rx_bytes_total{${sel}}[15m]))`;
+ return this.fetchStat(
+ this.groupQueryTCP(type, q),
+ 'RX',
`${subject} received bits per second averaged over the last 15 minutes`,
shortNumStr,
this.groupBy(type)
- )
+ );
},
fetchServiceTx: function(serviceName, type, options) {
- var sel = this.makeTCPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var metricPfx = this.metricPrefixTCP(type)
- var q = `8 * sum(rate(${metricPfx}_tx_bytes_total{${sel}}[15m]))`
- var self = this
- return this.fetchStat(this.groupQueryTCP(type, q),
- "TX",
+ var sel = this.makeTCPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var metricPfx = this.metricPrefixTCP(type);
+ var q = `8 * sum(rate(${metricPfx}_tx_bytes_total{${sel}}[15m]))`;
+ var self = this;
+ return this.fetchStat(
+ this.groupQueryTCP(type, q),
+ 'TX',
`${subject} transmitted bits per second averaged over the last 15 minutes`,
shortNumStr,
this.groupBy(type)
- )
+ );
},
fetchServiceNoRoute: function(serviceName, type, options) {
- var sel = this.makeTCPSelector(serviceName, type)
- var subject = this.makeSubject(serviceName, type)
- var metricPfx = this.metricPrefixTCP(type)
- var metric = "_no_route"
- if (type == "downstream") {
- metric = "_connect_fail"
+ var sel = this.makeTCPSelector(serviceName, type);
+ var subject = this.makeSubject(serviceName, type);
+ var metricPfx = this.metricPrefixTCP(type);
+ var metric = '_no_route';
+ if (type == 'downstream') {
+ metric = '_connect_fail';
}
- var q = `sum(rate(${metricPfx}${metric}{${sel}}[15m]))`
- return this.fetchStat(this.groupQueryTCP(type, q),
- "NR",
+ var q = `sum(rate(${metricPfx}${metric}{${sel}}[15m]))`;
+ return this.fetchStat(
+ this.groupQueryTCP(type, q),
+ 'NR',
`${subject} unroutable (failed) connections per second averaged over the last 15 minutes`,
shortNumStr,
this.groupBy(type)
- )
+ );
},
fetchStat: function(promql, label, desc, formatter, groupBy) {
if (!groupBy) {
// If we don't have a grouped result and its just a single stat, return
// no result as a zero not a missing stat.
- promql += " OR on() vector(0)";
+ promql += ' OR on() vector(0)';
}
//console.log(promql)
var params = {
query: promql,
- time: (new Date).getTime()/1000
- }
- return this.httpGet("/api/v1/query", params).then(function(response){
+ time: new Date().getTime() / 1000,
+ };
+ return this.httpGet('/api/v1/query', params).then(function(response) {
if (!groupBy) {
// Not grouped, expect just one stat value return that
- var v = parseFloat(response.data.result[0].value[1])
+ var v = parseFloat(response.data.result[0].value[1]);
return {
label: label,
desc: desc,
- value: formatter(v)
- }
+ value: formatter(v),
+ };
}
var data = {};
@@ -672,11 +683,11 @@
data[groupName] = {
label: label,
desc: desc.replace('{{GROUP}}', groupName),
- value: formatter(v)
- }
+ value: formatter(v),
+ };
}
return data;
- })
+ });
},
fetchSeries: function(promql, options) {
@@ -684,23 +695,23 @@
query: promql,
start: options.start,
end: options.end,
- step: "10s",
- timeout: "8s"
- }
- return this.httpGet("/api/v1/query_range", params)
+ step: '10s',
+ timeout: '8s',
+ };
+ return this.httpGet('/api/v1/query_range', params);
},
-
- }
+ };
// Helper functions
function shortNumStr(n) {
if (n < 1e3) {
- if (Number.isInteger(n)) return ""+n
+ if (Number.isInteger(n)) return '' + n;
if (n >= 100) {
// Go to 3 significant figures but wrap it in Number to avoid scientific
// notation lie 2.3e+2 for 230.
- return Number(n.toPrecision(3))
- } if (n < 1) {
+ return Number(n.toPrecision(3));
+ }
+ if (n < 1) {
// Very small numbers show with limited precision to prevent long string
// of 0.000000.
return Number(n.toFixed(2));
@@ -709,29 +720,28 @@
return Number(n.toPrecision(2));
}
}
- if (n >= 1e3 && n < 1e6) return +(n / 1e3).toPrecision(3) + "k";
- if (n >= 1e6 && n < 1e9) return +(n / 1e6).toPrecision(3) + "m";
- if (n >= 1e9 && n < 1e12) return +(n / 1e9).toPrecision(3) + "g";
- if (n >= 1e12) return +(n / 1e12).toFixed(0) + "t";
+ if (n >= 1e3 && n < 1e6) return +(n / 1e3).toPrecision(3) + 'k';
+ if (n >= 1e6 && n < 1e9) return +(n / 1e6).toPrecision(3) + 'm';
+ if (n >= 1e9 && n < 1e12) return +(n / 1e9).toPrecision(3) + 'g';
+ if (n >= 1e12) return +(n / 1e12).toFixed(0) + 't';
}
function shortTimeStr(n) {
- if (n < 1e3) return Math.round(n) + "ms";
+ if (n < 1e3) return Math.round(n) + 'ms';
- var secs = n / 1e3
- if (secs < 60) return secs.toFixed(1) + "s"
+ var secs = n / 1e3;
+ if (secs < 60) return secs.toFixed(1) + 's';
- var mins = secs/60
- if (mins < 60) return mins.toFixed(1) + "m"
+ var mins = secs / 60;
+ if (mins < 60) return mins.toFixed(1) + 'm';
- var hours = mins/60
- if (hours < 24) return hours.toFixed(1) + "h"
+ var hours = mins / 60;
+ if (hours < 24) return hours.toFixed(1) + 'h';
- var days = hours/24
- return days.toFixed(1) + "d"
+ var days = hours / 24;
+ return days.toFixed(1) + 'd';
}
/* global consul:writable */
- window.consul.registerMetricsProvider("prometheus", prometheusProvider)
-
-}());
+ window.consul.registerMetricsProvider('prometheus', prometheusProvider);
+})();