diff --git a/docs/migration/migrate_6_0.asciidoc b/docs/migration/migrate_6_0.asciidoc
index 27830c6f806f..b0122e66eb1e 100644
--- a/docs/migration/migrate_6_0.asciidoc
+++ b/docs/migration/migrate_6_0.asciidoc
@@ -10,4 +10,14 @@ your application to Kibana 6.0.
Kibana 6.0 will only support Painless and Lucene expression based scripts.
-*Impact:* You will need to migrate your groovy, python, javascript, etc. scripted fields to Painless or Lucene expressions.
\ No newline at end of file
+*Impact:* You will need to migrate your groovy, python, javascript, etc. scripted fields to Painless or Lucene expressions.
+
+[float]
+=== Changed response format of status API
+*Details:* In an effort to align with our style guidelines and provide a digestible response,
+the status API has changed:
+
+* Properties are now snake cased and several have been renamed
+* Metrics now provide the latest available data instead of samples over time
+
+*Impact:* You will need to update anything using the status API and expecting the previous response format.
\ No newline at end of file
diff --git a/src/core_plugins/status_page/public/lib/format_number.js b/src/core_plugins/status_page/public/lib/format_number.js
index a5e0a7f72bfd..d31a44889993 100644
--- a/src/core_plugins/status_page/public/lib/format_number.js
+++ b/src/core_plugins/status_page/public/lib/format_number.js
@@ -14,6 +14,9 @@ module.exports = function formatNumber(num, which) {
case 'ms':
postfix = ' ms';
break;
+ case 'integer':
+ format = '0';
+ break;
}
return numeral(num).format(format) + postfix;
};
diff --git a/src/core_plugins/status_page/public/lib/to_title_case.js b/src/core_plugins/status_page/public/lib/to_title_case.js
deleted file mode 100644
index 94e230cc3fef..000000000000
--- a/src/core_plugins/status_page/public/lib/to_title_case.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import _ from 'lodash';
-
-// Turns thisIsASentence to
-// This Is A Sentence
-module.exports = function toTitleCase(name) {
- return name
- .split(/(?=[A-Z])/)
- .map(function (word) { return word[0].toUpperCase() + _.rest(word).join(''); })
- .join(' ');
-};
diff --git a/src/core_plugins/status_page/public/status_page.html b/src/core_plugins/status_page/public/status_page.html
index c0ae2fa404f0..455ec252dc18 100644
--- a/src/core_plugins/status_page/public/status_page.html
+++ b/src/core_plugins/status_page/public/status_page.html
@@ -10,8 +10,8 @@
-
diff --git a/src/core_plugins/status_page/public/status_page.js b/src/core_plugins/status_page/public/status_page.js
index 05c0ad1b1b22..c350aa360e3d 100644
--- a/src/core_plugins/status_page/public/status_page.js
+++ b/src/core_plugins/status_page/public/status_page.js
@@ -27,9 +27,39 @@ const chrome = require('ui/chrome')
}
const data = resp.data;
- ui.metrics = data.metrics;
- ui.name = data.name;
+ const metrics = data.metrics;
+ if (metrics) {
+ ui.metrics = [{
+ name: 'Heap Total',
+ value: _.get(metrics, 'process.mem.heap_max_in_bytes'),
+ type: 'byte'
+ }, {
+ name: 'Heap Used',
+ value: _.get(metrics, 'process.mem.heap_used_in_bytes'),
+ type: 'byte'
+ }, {
+ name: 'Load',
+ value: [
+ _.get(metrics, 'os.cpu.load_average.1m'),
+ _.get(metrics, 'os.cpu.load_average.5m'),
+ _.get(metrics, 'os.cpu.load_average.15m')
+ ],
+ type: 'float'
+ }, {
+ name: 'Response Time Avg',
+ value: _.get(metrics, 'response_times.avg_in_millis'),
+ type: 'ms'
+ }, {
+ name: 'Response Time Max',
+ value: _.get(metrics, 'response_times.max_in_millis'),
+ type: 'ms'
+ }, {
+ name: 'Requests Per Second',
+ value: _.get(metrics, 'requests.total') * 1000 / _.get(metrics, 'collection_interval_in_millis')
+ }];
+ }
+ ui.name = data.name;
ui.statuses = data.status.statuses;
const overall = data.status.overall;
diff --git a/src/core_plugins/status_page/public/status_page.less b/src/core_plugins/status_page/public/status_page.less
index d82736de7278..7b391d547715 100644
--- a/src/core_plugins/status_page/public/status_page.less
+++ b/src/core_plugins/status_page/public/status_page.less
@@ -36,6 +36,7 @@
border: 0;
.content {
+ display: block;
text-align: right;
padding: 15px;
padding-right: 20px;
diff --git a/src/core_plugins/status_page/public/status_page_metric.html b/src/core_plugins/status_page/public/status_page_metric.html
index 9bda93533fc1..7d5a99d90a0d 100644
--- a/src/core_plugins/status_page/public/status_page_metric.html
+++ b/src/core_plugins/status_page/public/status_page_metric.html
@@ -1,6 +1,6 @@
-
{{metric.extendedTitle}}
- {{ metric.averages.join(', ') }}
+ {{ metric.name }}
+ {{ metric.value | statusMetric: metric.type}}
diff --git a/src/core_plugins/status_page/public/status_page_metric.js b/src/core_plugins/status_page/public/status_page_metric.js
index 1893e8eda2d4..412d93854672 100644
--- a/src/core_plugins/status_page/public/status_page_metric.js
+++ b/src/core_plugins/status_page/public/status_page_metric.js
@@ -2,74 +2,28 @@ import _ from 'lodash';
import moment from 'moment';
import numeral from 'numeral';
-import toTitleCase from './lib/to_title_case';
import formatNumber from './lib/format_number';
import readStatData from './lib/read_stat_data';
import uiModules from 'ui/modules';
import statusPageMetricTemplate from 'plugins/status_page/status_page_metric.html';
-function calcAvg(metricList, metricNumberType) {
- return metricList.map(function (data) {
- const uglySum = data.values.reduce(function (sumSoFar, vector) {
- return sumSoFar + vector.y;
- }, 0);
- return formatNumber(uglySum / data.values.length, metricNumberType);
- });
-}
-
uiModules
.get('kibana', [])
+.filter('statusMetric', function () {
+ return function (input, type) {
+ const metrics = [].concat(input);
+ return metrics.map(function (metric) {
+ return formatNumber(metric, type);
+ }).join(', ');
+ };
+})
.directive('statusPageMetric', function () {
return {
restrict: 'E',
template: statusPageMetricTemplate,
scope: {
- name: '@',
- data: '='
+ metric: '=',
},
- controllerAs: 'metric',
- controller: function ($scope) {
- const self = this;
-
- self.name = $scope.name;
- self.title = toTitleCase(self.name);
- self.extendedTitle = self.title;
- self.numberType = 'precise';
- self.seriesNames = [];
-
- switch (self.name) {
- case 'heapTotal':
- case 'heapUsed':
- self.numberType = 'byte';
- break;
-
- case 'responseTimeAvg':
- case 'responseTimeMax':
- self.numberType = 'ms';
- break;
-
- case 'load':
- self.seriesNames = ['1min', '5min', '15min'];
- break;
- }
-
- $scope.$watch('data', function (data) {
- self.rawData = data;
- self.chartData = readStatData(self.rawData, self.seriesNames);
- self.averages = calcAvg(self.chartData, self.numberType);
-
- let unit = '';
- self.averages = self.averages.map(function (average) {
- const parts = average.split(' ');
- const value = parts.shift();
- unit = parts.join(' ');
- return value;
- });
- self.extendedTitle = self.title;
- if (unit) {
- self.extendedTitle = `${self.extendedTitle} (${unit})`;
- }
- });
- }
+ controllerAs: 'metric'
};
});
diff --git a/src/server/status/__tests__/metrics.js b/src/server/status/__tests__/metrics.js
new file mode 100644
index 000000000000..67d5167e3cfb
--- /dev/null
+++ b/src/server/status/__tests__/metrics.js
@@ -0,0 +1,56 @@
+import _ from 'lodash';
+import expect from 'expect.js';
+
+import { getMetrics } from '../metrics';
+
+describe('Metrics', function () {
+ const mockOps = {
+ 'requests': { '5603': { 'total': 22, 'disconnects': 0, 'statusCodes': { '200': 22 } } },
+ 'responseTimes': { '5603': { 'avg': 1.8636363636363635, 'max': 4 } },
+ 'sockets': {
+ 'http': { 'total': 0 },
+ 'https': { 'total': 0 }
+ },
+ 'osload': [2.20751953125, 2.02294921875, 1.89794921875],
+ 'osmem': { 'total': 17179869184, 'free': 102318080 },
+ 'osup': 1008991,
+ 'psup': 7.168,
+ 'psmem': { 'rss': 193716224, 'heapTotal': 168194048, 'heapUsed': 130553400 },
+ 'concurrents': { '5603': 0 },
+ 'psdelay': 1.6091690063476562,
+ 'host': '123'
+ };
+ const config = {
+ ops: {
+ interval: 5000
+ },
+ server: {
+ port: 5603
+ }
+ };
+
+ let metrics;
+ beforeEach(() => {
+ metrics = getMetrics({
+ event: _.cloneDeep(mockOps),
+ config: {
+ get: path => _.get(config, path)
+ }
+ });
+ });
+
+ it('should snake case the request object', () => {
+ expect(metrics.requests.status_codes).not.to.be(undefined);
+ expect(metrics.requests.statusCodes).to.be(undefined);
+ });
+
+ it('should provide defined metrics', () => {
+ (function checkMetrics(currentMetric) {
+ _.forOwn(currentMetric, value => {
+ if (typeof value === 'object') return checkMetrics(value);
+ expect(currentMetric).not.to.be(undefined);
+ });
+
+ }(metrics));
+ });
+});
diff --git a/src/server/status/index.js b/src/server/status/index.js
index 90dea44ce537..b074c0ba6594 100644
--- a/src/server/status/index.js
+++ b/src/server/status/index.js
@@ -7,24 +7,29 @@ export default function (kbnServer, server, config) {
kbnServer.status = new ServerStatus(kbnServer.server);
if (server.plugins['even-better']) {
- kbnServer.mixin(require('./metrics'));
+ kbnServer.mixin(require('./metrics').collectMetrics);
}
const wrapAuth = wrapAuthConfig(config.get('status.allowAnonymous'));
-
+ const matchSnapshot = /-SNAPSHOT$/;
server.route(wrapAuth({
method: 'GET',
path: '/api/status',
handler: function (request, reply) {
- return reply({
+ const status = {
name: config.get('server.name'),
- version: config.get('pkg.version'),
- buildNum: config.get('pkg.buildNum'),
- buildSha: config.get('pkg.buildSha'),
uuid: config.get('server.uuid'),
+ version: {
+ number: config.get('pkg.version').replace(matchSnapshot, ''),
+ build_hash: config.get('pkg.buildSha'),
+ build_number: config.get('pkg.buildNum'),
+ build_snapshot: matchSnapshot.test(config.get('pkg.version'))
+ },
status: kbnServer.status.toJSON(),
metrics: kbnServer.metrics
- });
+ };
+
+ return reply(status);
}
}));
diff --git a/src/server/status/metrics.js b/src/server/status/metrics.js
index d00a8eb540d0..a2505b727b00 100644
--- a/src/server/status/metrics.js
+++ b/src/server/status/metrics.js
@@ -1,27 +1,40 @@
import _ from 'lodash';
import Samples from './samples';
-module.exports = function (kbnServer, server, config) {
- let lastReport = Date.now();
-
- kbnServer.metrics = new Samples(12);
+import { keysToSnakeCaseShallow } from '../../utils/case_conversion';
+export function collectMetrics(kbnServer, server, config) {
server.plugins['even-better'].monitor.on('ops', function (event) {
- const now = Date.now();
- const secSinceLast = (now - lastReport) / 1000;
- lastReport = now;
-
- const port = config.get('server.port');
- const requests = _.get(event, ['requests', port, 'total'], 0);
- const requestsPerSecond = requests / secSinceLast;
-
- kbnServer.metrics.add({
- heapTotal: _.get(event, 'psmem.heapTotal'),
- heapUsed: _.get(event, 'psmem.heapUsed'),
- load: event.osload,
- responseTimeAvg: _.get(event, ['responseTimes', port, 'avg']),
- responseTimeMax: _.get(event, ['responseTimes', port, 'max']),
- requestsPerSecond: requestsPerSecond
- });
-
+ kbnServer.metrics = getMetrics({ event, config });
});
-};
+}
+
+export function getMetrics({ event, config }) {
+ const port = config.get('server.port');
+ const timestamp = new Date().toISOString();
+ return {
+ last_updated: timestamp,
+ collection_interval_in_millis: config.get('ops.interval'),
+ uptime_in_millis: process.uptime() * 1000,
+ process: {
+ mem: {
+ heap_max_in_bytes: _.get(event, 'psmem.heapTotal'),
+ heap_used_in_bytes: _.get(event, 'psmem.heapUsed')
+ }
+ },
+ os: {
+ cpu: {
+ load_average: {
+ '1m': _.get(event, 'osload.0'),
+ '5m': _.get(event, 'osload.1'),
+ '15m': _.get(event, 'osload.1')
+ }
+ }
+ },
+ response_times: {
+ avg_in_millis: _.get(event, ['responseTimes', port, 'avg']),
+ max_in_millis: _.get(event, ['responseTimes', port, 'max'])
+ },
+ requests: keysToSnakeCaseShallow(_.get(event, ['requests', port])),
+ concurrent_connections: _.get(event, ['concurrents', port])
+ };
+}
diff --git a/src/ui/public/ingest/ingest.js b/src/ui/public/ingest/ingest.js
index 6b523d41c6c7..9fe0c43b9d09 100644
--- a/src/ui/public/ingest/ingest.js
+++ b/src/ui/public/ingest/ingest.js
@@ -1,5 +1,5 @@
import RefreshKibanaIndexProvider from 'plugins/kibana/management/sections/indices/_refresh_kibana_index';
-import { keysToCamelCaseShallow, keysToSnakeCaseShallow } from '../../../core_plugins/kibana/common/lib/case_conversion';
+import { keysToCamelCaseShallow, keysToSnakeCaseShallow } from '../../../utils/case_conversion';
import _ from 'lodash';
import angular from 'angular';
import chrome from 'ui/chrome';
diff --git a/src/core_plugins/kibana/common/lib/__tests__/case_conversion.js b/src/utils/__tests__/case_conversion.js
similarity index 100%
rename from src/core_plugins/kibana/common/lib/__tests__/case_conversion.js
rename to src/utils/__tests__/case_conversion.js
diff --git a/src/core_plugins/kibana/common/lib/case_conversion.js b/src/utils/case_conversion.js
similarity index 100%
rename from src/core_plugins/kibana/common/lib/case_conversion.js
rename to src/utils/case_conversion.js