Skip to content

Commit a7c3255

Browse files
authored
Add some collector classes for objects that get registered in a CollectorSet (#19098)
* Add some collector classes for objects that get registered in a CollectorSet * comment cleanup * don't pass an inline-defined logger to collectorSet * add a helper logger function so collector has access to logger at construction
1 parent fcec107 commit a7c3255

13 files changed

+190
-111
lines changed

x-pack/plugins/monitoring/server/kibana_monitoring/lib/__tests__/collector_set.js renamed to x-pack/plugins/monitoring/server/kibana_monitoring/classes/__tests__/collector_set.js

+51-30
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import { identity, noop } from 'lodash';
88
import sinon from 'sinon';
99
import expect from 'expect.js';
10+
import { Collector } from '../collector';
1011
import { CollectorSet } from '../collector_set';
1112

1213
const DEBUG_LOG = [ 'debug', 'monitoring-ui', 'kibana-monitoring' ];
@@ -17,52 +18,74 @@ const CHECK_DELAY = 100; // can be lower than COLLECTOR_INTERVAL because the col
1718

1819
describe('CollectorSet', () => {
1920
describe('registers a collector set and runs lifecycle events', () => {
20-
let log;
21+
let server;
2122
let init;
2223
let cleanup;
2324
let fetch;
2425
beforeEach(() => {
25-
log = sinon.spy();
26+
server = {
27+
log: sinon.spy()
28+
};
2629
init = noop;
2730
cleanup = noop;
2831
fetch = noop;
2932
});
3033

34+
it('should throw an error if non-Collector type of object is registered', () => {
35+
const collectors = new CollectorSet(server, {
36+
interval: COLLECTOR_INTERVAL,
37+
combineTypes: identity,
38+
onPayload: identity
39+
});
40+
41+
const registerPojo = () => {
42+
collectors.register({
43+
type: 'type_collector_test',
44+
fetchAfterInit: true,
45+
init,
46+
fetch,
47+
cleanup
48+
});
49+
};
50+
51+
expect(registerPojo).to.throwException(({ message }) => {
52+
expect(message).to.be('CollectorSet can only have Collector instances registered');
53+
});
54+
});
55+
3156
it('should skip bulk upload if payload is empty', (done) => {
32-
const collectors = new CollectorSet({
57+
const collectors = new CollectorSet(server, {
3358
interval: COLLECTOR_INTERVAL,
34-
logger: log,
3559
combineTypes: identity,
3660
onPayload: identity
3761
});
3862

39-
collectors.register({
63+
collectors.register(new Collector(server, {
4064
type: 'type_collector_test',
4165
fetchAfterInit: true,
4266
init,
4367
fetch,
4468
cleanup
45-
});
69+
}));
4670

4771
collectors.start();
4872

4973
// allow interval to tick a few times
5074
setTimeout(() => {
5175
collectors.cleanup();
5276

53-
expect(log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
54-
expect(log.calledWith(DEBUG_LOG, 'Initializing type_collector_test collector')).to.be(true);
55-
expect(log.calledWith(DEBUG_LOG, 'Fetching data from type_collector_test collector')).to.be(true);
56-
expect(log.calledWith(DEBUG_LOG, 'Skipping bulk uploading of an empty stats payload')).to.be(true); // proof of skip
57-
expect(log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
58-
expect(log.calledWith(DEBUG_LOG, 'Running type_collector_test cleanup')).to.be(true);
77+
expect(server.log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
78+
expect(server.log.calledWith(DEBUG_LOG, 'Initializing type_collector_test collector')).to.be(true);
79+
expect(server.log.calledWith(DEBUG_LOG, 'Fetching data from type_collector_test collector')).to.be(true);
80+
expect(server.log.calledWith(DEBUG_LOG, 'Skipping bulk uploading of an empty stats payload')).to.be(true); // proof of skip
81+
expect(server.log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
82+
expect(server.log.calledWith(DEBUG_LOG, 'Running type_collector_test cleanup')).to.be(true);
5983

6084
done(); // for async exit
6185
}, CHECK_DELAY);
6286
});
6387

6488
it('should run the bulk upload handler', (done) => {
65-
const log = sinon.spy();
6689
const combineTypes = sinon.spy(data => {
6790
return [
6891
data[0][0],
@@ -71,34 +94,33 @@ describe('CollectorSet', () => {
7194
});
7295
const onPayload = sinon.spy();
7396

74-
const collectors = new CollectorSet({
97+
const collectors = new CollectorSet(server, {
7598
interval: COLLECTOR_INTERVAL,
76-
logger: log,
7799
combineTypes,
78100
onPayload
79101
});
80102

81103
fetch = () => ({ testFetch: true });
82-
collectors.register({
104+
collectors.register(new Collector(server, {
83105
type: 'type_collector_test',
84106
fetchAfterInit: true,
85107
init,
86108
fetch,
87109
cleanup
88-
});
110+
}));
89111

90112
collectors.start();
91113

92114
// allow interval to tick a few times
93115
setTimeout(() => {
94116
collectors.cleanup();
95117

96-
expect(log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
97-
expect(log.calledWith(DEBUG_LOG, 'Initializing type_collector_test collector')).to.be(true);
98-
expect(log.calledWith(DEBUG_LOG, 'Fetching data from type_collector_test collector')).to.be(true);
99-
expect(log.calledWith(DEBUG_LOG, 'Uploading bulk stats payload to the local cluster')).to.be(true);
100-
expect(log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
101-
expect(log.calledWith(DEBUG_LOG, 'Running type_collector_test cleanup')).to.be(true);
118+
expect(server.log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
119+
expect(server.log.calledWith(DEBUG_LOG, 'Initializing type_collector_test collector')).to.be(true);
120+
expect(server.log.calledWith(DEBUG_LOG, 'Fetching data from type_collector_test collector')).to.be(true);
121+
expect(server.log.calledWith(DEBUG_LOG, 'Uploading bulk stats payload to the local cluster')).to.be(true);
122+
expect(server.log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
123+
expect(server.log.calledWith(DEBUG_LOG, 'Running type_collector_test cleanup')).to.be(true);
102124

103125
// un-flattened
104126
expect(combineTypes.getCall(0).args[0]).to.eql(
@@ -115,29 +137,28 @@ describe('CollectorSet', () => {
115137
});
116138

117139
it('should log the info-level status of stopping and restarting', (done) => {
118-
const collectors = new CollectorSet({
140+
const collectors = new CollectorSet(server, {
119141
interval: COLLECTOR_INTERVAL,
120-
logger: log,
121142
combineTypes: identity,
122143
onPayload: identity
123144
});
124145

125-
collectors.register({
146+
collectors.register(new Collector(server, {
126147
type: 'type_collector_test',
127148
fetchAfterInit: true,
128149
init,
129150
fetch,
130151
cleanup
131-
});
152+
}));
132153

133154
collectors.start();
134-
expect(log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
155+
expect(server.log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
135156

136157
collectors.cleanup();
137-
expect(log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
158+
expect(server.log.calledWith(INFO_LOG, 'Stopping all stats collectors')).to.be(true);
138159

139160
collectors.start();
140-
expect(log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
161+
expect(server.log.calledWith(INFO_LOG, 'Starting all stats collectors')).to.be(true);
141162

142163
// exit
143164
collectors.cleanup();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { getCollectorLogger } from '../lib';
8+
9+
export class Collector {
10+
/*
11+
* @param {Object} server - server object
12+
* @param {String} properties.type - property name as the key for the data
13+
* @param {Function} properties.init (optional) - initialization function
14+
* @param {Function} properties.fetch - function to query data
15+
* @param {Function} properties.cleanup (optional) - cleanup function
16+
* @param {Boolean} properties.fetchAfterInit (optional) - if collector should fetch immediately after init
17+
*/
18+
constructor(server, { type, init, fetch, cleanup, fetchAfterInit }) {
19+
this.type = type;
20+
this.init = init;
21+
this.fetch = fetch;
22+
this.cleanup = cleanup;
23+
this.fetchAfterInit = fetchAfterInit;
24+
25+
this.log = getCollectorLogger(server);
26+
}
27+
}

x-pack/plugins/monitoring/server/kibana_monitoring/lib/collector_set.js renamed to x-pack/plugins/monitoring/server/kibana_monitoring/classes/collector_set.js

+30-26
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
*/
66

77
import { flatten, isEmpty } from 'lodash';
8-
import { LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG } from '../../../common/constants';
98
import Promise from 'bluebird';
10-
11-
const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG];
9+
import { getCollectorLogger } from '../lib';
10+
import { Collector } from './collector';
11+
import { UsageCollector } from './usage_collector';
1212

1313
/*
1414
* A collector object has types registered into it with the register(type)
@@ -18,47 +18,41 @@ const LOGGING_TAGS = [LOGGING_TAG, KIBANA_MONITORING_LOGGING_TAG];
1818
export class CollectorSet {
1919

2020
/*
21-
* @param options.interval {Number} in milliseconds
22-
* @param options.logger {Function}
23-
* @param options.combineTypes {Function}
24-
* @param options.onPayload {Function}
21+
* @param {Object} server - server object
22+
* @param {Number} options.interval - in milliseconds
23+
* @param {Function} options.combineTypes
24+
* @param {Function} options.onPayload
2525
*/
26-
constructor({ interval, logger, combineTypes, onPayload }) {
26+
constructor(server, { interval, combineTypes, onPayload }) {
2727
this._collectors = [];
2828
this._timer = null;
2929

3030
if (typeof interval !== 'number') {
3131
throw new Error('interval number of milliseconds is required');
3232
}
33-
if (typeof logger !== 'function') {
34-
throw new Error('Logger function is required');
35-
}
3633
if (typeof combineTypes !== 'function') {
3734
throw new Error('combineTypes function is required');
3835
}
3936
if (typeof onPayload !== 'function') {
4037
throw new Error('onPayload function is required');
4138
}
4239

43-
this._log = {
44-
debug: message => logger(['debug', ...LOGGING_TAGS], message),
45-
info: message => logger(['info', ...LOGGING_TAGS], message),
46-
warn: message => logger(['warning', ...LOGGING_TAGS], message)
47-
};
40+
this._log = getCollectorLogger(server);
4841

4942
this._interval = interval;
5043
this._combineTypes = combineTypes;
5144
this._onPayload = onPayload;
5245
}
5346

5447
/*
55-
* @param {String} type.type
56-
* @param {Function} type.init (optional)
57-
* @param {Function} type.fetch
58-
* @param {Function} type.cleanup (optional)
48+
* @param collector {Collector} collector object
5949
*/
60-
register(type) {
61-
this._collectors.push(type);
50+
register(collector) {
51+
// check instanceof
52+
if (!(collector instanceof Collector)) {
53+
throw new Error('CollectorSet can only have Collector instances registered');
54+
}
55+
this._collectors.push(collector);
6256
}
6357

6458
/*
@@ -75,10 +69,7 @@ export class CollectorSet {
7569
collector.init();
7670
}
7771

78-
if (collector.setLogger) {
79-
this._log.debug(`Setting logger for ${collector.type} collector`);
80-
collector.setLogger(this._log);
81-
}
72+
this._log.debug(`Setting logger for ${collector.type} collector`);
8273

8374
if (collector.fetchAfterInit) {
8475
initialCollectors.push(collector);
@@ -139,6 +130,19 @@ export class CollectorSet {
139130
});
140131
}
141132

133+
async bulkFetchUsage() {
134+
const usageCollectors = this._collectors.filter(c => c instanceof UsageCollector);
135+
const bulk = await this._bulkFetch(usageCollectors);
136+
137+
// summarize each type of stat
138+
return bulk.reduce((accumulatedStats, currentStat) => {
139+
return {
140+
...accumulatedStats,
141+
[currentStat.type]: currentStat.result,
142+
};
143+
}, {});
144+
}
145+
142146
cleanup() {
143147
this._log.info(`Stopping all stats collectors`);
144148

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { Collector } from './collector';
8+
9+
export class UsageCollector extends Collector {
10+
constructor(server, properties) {
11+
super(server, properties);
12+
}
13+
}

x-pack/plugins/monitoring/server/kibana_monitoring/collectors/__tests__/get_kibana_usage_collector.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ describe('getKibanaUsageCollector', () => {
2222
getCluster: sinon.stub()
2323
}
2424
},
25-
config: () => ({ get: sinon.stub() })
25+
config: () => ({ get: sinon.stub() }),
26+
log: sinon.stub(),
2627
};
2728
serverStub.plugins.elasticsearch.getCluster.withArgs('admin').returns(clusterStub);
2829
callClusterStub = callClusterFactory(serverStub).getCallClusterInternal();

x-pack/plugins/monitoring/server/kibana_monitoring/collectors/get_kibana_usage_collector.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import { get, snakeCase } from 'lodash';
88
import { KIBANA_USAGE_TYPE } from '../../../common/constants';
9+
import { UsageCollector } from '../classes/usage_collector';
910

1011
const TYPES = [
1112
'dashboard',
@@ -20,7 +21,7 @@ const TYPES = [
2021
* Fetches saved object client counts by querying the saved object index
2122
*/
2223
export function getKibanaUsageCollector(server, callCluster) {
23-
return {
24+
return new UsageCollector(server, {
2425
type: KIBANA_USAGE_TYPE,
2526
async fetch() {
2627
const index = server.config().get('kibana.index');
@@ -52,15 +53,13 @@ export function getKibanaUsageCollector(server, callCluster) {
5253

5354
return {
5455
index,
55-
56-
// combine the bucketCounts and 0s for types that don't have documents
57-
...TYPES.reduce((acc, type) => ({
56+
...TYPES.reduce((acc, type) => ({ // combine the bucketCounts and 0s for types that don't have documents
5857
...acc,
5958
[snakeCase(type)]: {
6059
total: bucketCounts[type] || 0
6160
}
6261
}), {})
6362
};
6463
}
65-
};
64+
});
6665
}

0 commit comments

Comments
 (0)