diff --git a/src/core_plugins/status_page/public/status_page.js b/src/core_plugins/status_page/public/status_page.js index 05c0ad1b1b226..77fdd34c73eac 100644 --- a/src/core_plugins/status_page/public/status_page.js +++ b/src/core_plugins/status_page/public/status_page.js @@ -27,7 +27,35 @@ const chrome = require('ui/chrome') } const data = resp.data; - ui.metrics = data.metrics; + const metrics = data.metrics; + const v6Timestamp = _.get(metrics, 'last_updated'); + if (v6Timestamp) { + const timestamp = new Date(v6Timestamp).getTime(); + ui.metrics = { + heapTotal: [ + [timestamp, _.get(metrics, 'process.mem.heap_max_in_bytes')] + ], + heapUsed: [ + [timestamp, _.get(metrics, 'process.mem.heap_used_in_bytes')] + ], + load: [[timestamp, [ + _.get(metrics, 'os.cpu.load_average.1m'), + _.get(metrics, 'os.cpu.load_average.5m'), + _.get(metrics, 'os.cpu.load_average.15m') + ]]], + responseTimeAvg: [ + [timestamp, _.get(metrics, 'response_times.avg_in_millis')] + ], + responseTimeMax: [ + [timestamp, _.get(metrics, 'response_times.max_in_millis')] + ], + requestsPerSecond: [ + [timestamp, _.get(metrics, 'requests.total') * 1000 / _.get(metrics, 'collection_interval_in_millis')] + ] + }; + } else { + ui.metrics = data.metrics; + } ui.name = data.name; ui.statuses = data.status.statuses; diff --git a/src/core_plugins/status_page/public/status_page.less b/src/core_plugins/status_page/public/status_page.less index d82736de72784..7b391d5477157 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/server/config/schema.js b/src/server/config/schema.js index cc6bcc18cc979..a3a407211f3e2 100644 --- a/src/server/config/schema.js +++ b/src/server/config/schema.js @@ -148,7 +148,8 @@ module.exports = () => Joi.object({ }).default(), status: Joi.object({ - allowAnonymous: Joi.boolean().default(false) + allowAnonymous: Joi.boolean().default(false), + v6ApiFormat: Joi.boolean().default(false) }).default(), tilemap: Joi.object({ manifestServiceUrl: Joi.string().default('https://tiles.elastic.co/v2/manifest'), diff --git a/src/server/status/__tests__/metrics.js b/src/server/status/__tests__/metrics.js new file mode 100644 index 0000000000000..67d5167e3cfb6 --- /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 90dea44ce5378..beebaf649f2c0 100644 --- a/src/server/status/index.js +++ b/src/server/status/index.js @@ -7,15 +7,31 @@ 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) { + const v6Format = config.get('status.v6ApiFormat'); + if (v6Format) { + return reply({ + name: config.get('server.name'), + 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({ name: config.get('server.name'), version: config.get('pkg.version'), @@ -23,7 +39,7 @@ export default function (kbnServer, server, config) { buildSha: config.get('pkg.buildSha'), uuid: config.get('server.uuid'), status: kbnServer.status.toJSON(), - metrics: kbnServer.metrics + metrics: kbnServer.legacyMetrics }); } })); diff --git a/src/server/status/metrics.js b/src/server/status/metrics.js index d00a8eb540d04..4d75ff82b242a 100644 --- a/src/server/status/metrics.js +++ b/src/server/status/metrics.js @@ -1,11 +1,14 @@ import _ from 'lodash'; import Samples from './samples'; -module.exports = function (kbnServer, server, config) { - let lastReport = Date.now(); +import { keysToSnakeCaseShallow } from '../../utils/case_conversion'; - kbnServer.metrics = new Samples(12); +export function collectMetrics(kbnServer, server, config) { + let lastReport = Date.now(); + kbnServer.legacyMetrics = new Samples(12); server.plugins['even-better'].monitor.on('ops', function (event) { + kbnServer.metrics = getMetrics({ event, config }); + const now = Date.now(); const secSinceLast = (now - lastReport) / 1000; lastReport = now; @@ -14,7 +17,7 @@ module.exports = function (kbnServer, server, config) { const requests = _.get(event, ['requests', port, 'total'], 0); const requestsPerSecond = requests / secSinceLast; - kbnServer.metrics.add({ + kbnServer.legacyMetrics.add({ heapTotal: _.get(event, 'psmem.heapTotal'), heapUsed: _.get(event, 'psmem.heapUsed'), load: event.osload, @@ -24,4 +27,35 @@ module.exports = function (kbnServer, server, 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.2') + } + } + }, + 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 6b523d41c6c74..9fe0c43b9d099 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