Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stats API: implement the "kibana status" spec from the Monitoring data model for stats #20577

Merged
merged 46 commits into from
Jul 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
cd83e73
[Stats API] Set API field names per spec
tsullivan Jul 5, 2018
acba93c
fix jest tests
tsullivan Jul 11, 2018
3478ed4
fix api integration test
tsullivan Jul 11, 2018
12718bc
trash the original metrics collector
tsullivan Jul 11, 2018
d59cd4d
move some logic out of the collector types combiner into inline
tsullivan Jul 11, 2018
027ef25
Make a new stats collector for the API
tsullivan Jul 12, 2018
b7f0766
isolate data transforms for api data and upload data
tsullivan Jul 12, 2018
fb05f20
no static methods
tsullivan Jul 12, 2018
4fe1c9d
remove external in bytes
tsullivan Jul 12, 2018
c1e8226
remove the _stats prefix for kibana and reporting
tsullivan Jul 12, 2018
d162284
update jest test snapshot
tsullivan Jul 12, 2018
489be42
fix collector_types_combiner test
tsullivan Jul 12, 2018
6e36b3c
Merge branch 'master' into usage/stats-api-fixes
tsullivan Jul 12, 2018
817314c
fix usage api
tsullivan Jul 12, 2018
dfb901b
add test suite todo comment
tsullivan Jul 12, 2018
48d4987
reduce some loc change
tsullivan Jul 12, 2018
9be60c9
roll back mysterious change
tsullivan Jul 12, 2018
244627f
reduce some more loc change
tsullivan Jul 12, 2018
81f502b
comment correction
tsullivan Jul 12, 2018
8130311
reduce more loc change
tsullivan Jul 12, 2018
4243523
whitespace
tsullivan Jul 13, 2018
366aae9
comment question
tsullivan Jul 13, 2018
01d3bd8
fix cluster_uuid
tsullivan Jul 13, 2018
d5c7e64
fix stats integration test
tsullivan Jul 13, 2018
23a40c5
fix bulk uploader test, combineTypes is no longer external
tsullivan Jul 13, 2018
07e6a67
very important comments about the current nature of stats represented…
tsullivan Jul 13, 2018
c11c68d
add stats api tests with/without authentication
tsullivan Jul 13, 2018
7a149e0
fix more fields to match data model
tsullivan Jul 13, 2018
82f4283
fix more tests
tsullivan Jul 13, 2018
7a2c455
Merge branch 'master' into usage/stats-api-fixes
tsullivan Jul 13, 2018
1c4cc37
fix jest test
tsullivan Jul 13, 2018
7366cb6
remove TODO
tsullivan Jul 16, 2018
ffe3f8f
remove sockets
tsullivan Jul 16, 2018
ab67e64
use snake_case for api field names
tsullivan Jul 16, 2018
64728d9
restore accidental removal + copy/paste error
tsullivan Jul 17, 2018
fb6fca7
sourceKibana -> getKibanaInfoForStats
tsullivan Jul 17, 2018
b3c92e5
skip usage test on legacy endpoint
tsullivan Jul 17, 2018
4ee99b9
fix api tests
tsullivan Jul 17, 2018
cb46d50
more comment
tsullivan Jul 17, 2018
73e1d34
stop putting a field in that used to be omitted
tsullivan Jul 17, 2018
51444d7
fix the internal type to ID the usage data for bulk uploader
tsullivan Jul 18, 2018
7102f04
correct the kibana usage type value, which is shown as-is in the API
tsullivan Jul 18, 2018
f641e28
Merge branch 'master' into usage/stats-api-fixes
tsullivan Jul 18, 2018
79111eb
more fixes for the constants identifying collector types + test again…
tsullivan Jul 18, 2018
528cc0d
add a comment on a hack, and a whitespace fix
tsullivan Jul 18, 2018
eebed0c
Merge branch 'master' into usage/stats-api-fixes
tsullivan Jul 18, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/server/kbn_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ import configSetupMixin from './config/setup';
import httpMixin from './http';
import { loggingMixin } from './logging';
import warningsMixin from './warnings';
import { statusMixin } from './status';
import { usageMixin } from './usage';
import { statusMixin } from './status';
import pidMixin from './pid';
import { configDeprecationWarningsMixin } from './config/deprecation_warnings';
import configCompleteMixin from './config/complete';
Expand Down Expand Up @@ -68,8 +68,8 @@ export default class KbnServer {
loggingMixin,
configDeprecationWarningsMixin,
warningsMixin,
statusMixin,
usageMixin,
statusMixin,

// writes pid file
pidMixin,
Expand Down
49 changes: 49 additions & 0 deletions src/server/status/collectors/get_ops_stats_collector.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/


import { KIBANA_STATS_TYPE } from '../constants';
import { getKibanaInfoForStats } from '../lib';

/*
* Initialize a collector for Kibana Ops Stats
*
* NOTE this collector's fetch method returns the latest stats from the
* Hapi/Good/Even-Better ops event listener. Therefore, the stats reset
* every 5 seconds (the default value of the ops.interval configuration
* setting). That makes it geared for providing the latest "real-time"
* stats. In the long-term, fetch should return stats that constantly
* accumulate over the server's uptime for better machine readability.
* Since the data is captured, timestamped and stored, the historical
* data can provide "real-time" stats by calculating a derivative of
* the metrics.
* See PR comment in https://github.com/elastic/kibana/pull/20577/files#r202416647
*/
export function getOpsStatsCollector(server, kbnServer) {
const { collectorSet } = server.usage;
return collectorSet.makeStatsCollector({
type: KIBANA_STATS_TYPE,
fetch: () => {
return {
kibana: getKibanaInfoForStats(server, kbnServer),
...kbnServer.metrics // latest metrics captured from the ops event listener in src/server/status/index
};
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@
* under the License.
*/

export { MetricsCollector } from './metrics_collector';
export { getOpsStatsCollector } from './get_ops_stats_collector';
20 changes: 20 additions & 0 deletions src/server/status/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export const KIBANA_STATS_TYPE = 'kibana_stats'; // kibana stats per 5s intervals
17 changes: 8 additions & 9 deletions src/server/status/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,29 @@
*/

import ServerStatus from './server_status';
import { MetricsCollector } from './metrics_collector';
import { Metrics } from './metrics_collector/metrics';
import { Metrics } from './lib/metrics';
import { registerStatusPage, registerStatusApi, registerStatsApi } from './routes';
import { getOpsStatsCollector } from './collectors';

export function statusMixin(kbnServer, server, config) {
const collector = new MetricsCollector(server, config);
kbnServer.status = new ServerStatus(kbnServer.server);

const statsCollector = getOpsStatsCollector(server, kbnServer);
const { collectorSet } = server.usage;
collectorSet.register(statsCollector);

const { ['even-better']: evenBetter } = server.plugins;

if (evenBetter) {
const metrics = new Metrics(config, server);

evenBetter.monitor.on('ops', event => {
// for status API (to deprecate in next major)
metrics.capture(event).then(data => { kbnServer.metrics = data; });

// for metrics API (replacement API)
collector.collect(event); // collect() is async, but here we aren't depending on the return value
metrics.capture(event).then(data => { kbnServer.metrics = data; }); // captures (performs transforms on) the latest event data and stashes the metrics for status/stats API payload
});
}

// init routes
registerStatusPage(kbnServer, server, config);
registerStatusApi(kbnServer, server, config);
registerStatsApi(kbnServer, server, config, collector);
registerStatsApi(kbnServer, server, config);
}
46 changes: 46 additions & 0 deletions src/server/status/lib/get_kibana_info_for_stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { get } from 'lodash';

const snapshotRegex = /-snapshot/i;

/**
* This provides a meta data attribute along with Kibana stats.
*
* @param {Object} kbnServer manager of Kibana services - see `src/server/kbn_server` in Kibana core
* @param {Object} config Server config
* @param {String} host Kibana host
* @return {Object} The object containing a "kibana" field and source instance details.
*/
export function getKibanaInfoForStats(server, kbnServer) {
const config = server.config();
const status = kbnServer.status.toJSON();

return {
uuid: config.get('server.uuid'),
name: config.get('server.name'),
index: config.get('kibana.index'),
host: config.get('server.host'),
transport_address: `${config.get('server.host')}:${config.get('server.port')}`,
version: kbnServer.version.replace(snapshotRegex, ''),
snapshot: snapshotRegex.test(kbnServer.version),
status: get(status, 'overall.state')
};
}
20 changes: 20 additions & 0 deletions src/server/status/lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

export { getKibanaInfoForStats } from './get_kibana_info_for_stats';
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import os from 'os';
import v8 from 'v8';
import { get, isObject, merge } from 'lodash';
import { keysToSnakeCaseShallow } from '../../../utils/case_conversion';
import { getAllStats as cGroupStats } from './cgroup';
Expand All @@ -32,19 +33,17 @@ export class Metrics {
static getStubMetrics() {
return {
process: {
mem: {}
memory: {
heap: {}
}
},
os: {
cpu: {},
mem: {}
memory: {}
},
response_times: {},
requests: {
status_codes: {}
},
sockets: {
http: {},
https: {}
}
};
}
Expand All @@ -56,53 +55,52 @@ export class Metrics {

const metrics = {
last_updated: timestamp,
collection_interval_in_millis: this.config.get('ops.interval'),
uptime_in_millis: event.process.uptime_ms, // TODO: deprecate this field, data should only have process.uptime_ms
collection_interval_in_millis: this.config.get('ops.interval')
};

return merge(metrics, event, cgroup);
}

captureEvent(hapiEvent) {
const heapStats = v8.getHeapStatistics();
const port = this.config.get('server.port');

const avgInMillis = get(hapiEvent, ['responseTimes', port, 'avg']); // sadly, it's possible for this to be NaN
const maxInMillis = get(hapiEvent, ['responseTimes', port, 'max']);

return {
process: {
mem: {
// https://nodejs.org/docs/latest-v8.x/api/process.html#process_process_memoryusage
heap_max_in_bytes: get(hapiEvent, 'psmem.heapTotal'),
heap_used_in_bytes: get(hapiEvent, 'psmem.heapUsed'),
memory: {
heap: {
// https://nodejs.org/docs/latest-v8.x/api/process.html#process_process_memoryusage
total_in_bytes: get(hapiEvent, 'psmem.heapTotal'),
used_in_bytes: get(hapiEvent, 'psmem.heapUsed'),
size_limit: heapStats.heap_size_limit
},
resident_set_size_in_bytes: get(hapiEvent, 'psmem.rss'),
external_in_bytes: get(hapiEvent, 'psmem.external')
},
event_loop_delay: get(hapiEvent, 'psdelay'),
pid: process.pid,
uptime_ms: process.uptime() * 1000
uptime_in_millis: process.uptime() * 1000
},
os: {
cpu: {
load_average: {
'1m': get(hapiEvent, 'osload.0'),
'5m': get(hapiEvent, 'osload.1'),
'15m': get(hapiEvent, 'osload.2')
}
load: {
'1m': get(hapiEvent, 'osload.0'),
'5m': get(hapiEvent, 'osload.1'),
'15m': get(hapiEvent, 'osload.2')
},
mem: {
memory: {
total_in_bytes: os.totalmem(),
free_in_bytes: os.freemem(),
total_in_bytes: os.totalmem()
}
used_in_bytes: get(hapiEvent, 'osmem.total') - get(hapiEvent, 'osmem.free')
},
uptime_in_millis: os.uptime() * 1000
},
response_times: {
// TODO: rename to use `_ms` suffix per beats naming conventions
avg_in_millis: isNaN(avgInMillis) ? undefined : avgInMillis, // convert NaN to undefined
max_in_millis: maxInMillis
},
requests: keysToSnakeCaseShallow(get(hapiEvent, ['requests', port])),
concurrent_connections: get(hapiEvent, ['concurrents', port]),
sockets: get(hapiEvent, 'sockets'),
event_loop_delay: get(hapiEvent, 'psdelay')
};
}

Expand Down
Loading