Skip to content

Commit ada19c3

Browse files
Caliper terminates if prometheus is not available (#1288)
This is due to the error event not being correctly captured when a request is made to prometheus Also added some extra code to output a warning and stop trying to do any more queries for the round. It won't stop it for all rounds but checks on every round. closes #1267 Signed-off-by: D <d_kelsey@uk.ibm.com> Co-authored-by: D <d_kelsey@uk.ibm.com>
1 parent 6a76834 commit ada19c3

File tree

3 files changed

+124
-23
lines changed

3 files changed

+124
-23
lines changed

packages/caliper-core/lib/common/prometheus/prometheus-query-client.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,11 @@ class PrometheusQueryClient {
149149
resolve();
150150
}
151151
});
152-
res.on('error', err => {
153-
Logger.error(err);
154-
reject(err);
155-
});
152+
});
153+
154+
req.on('error', err => {
155+
Logger.error(err);
156+
reject(err);
156157
});
157158

158159
req.end();

packages/caliper-core/lib/manager/monitors/monitor-prometheus.js

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class PrometheusMonitor extends MonitorInterface {
6565
* Retrieve the query client
6666
* @returns {PrometheusQueryClient} the query client
6767
*/
68-
getQueryClient(){
68+
getQueryClient() {
6969
return this.prometheusQueryClient;
7070
}
7171

@@ -74,7 +74,7 @@ class PrometheusMonitor extends MonitorInterface {
7474
* @async
7575
*/
7676
async start() {
77-
this.startTime = Date.now()/1000;
77+
this.startTime = Date.now() / 1000;
7878
}
7979

8080
/**
@@ -114,7 +114,7 @@ class PrometheusMonitor extends MonitorInterface {
114114
* @async
115115
*/
116116
async getStatistics(testLabel) {
117-
this.endTime = Date.now()/1000;
117+
this.endTime = Date.now() / 1000;
118118

119119
const resourceStats = [];
120120
const chartArray = [];
@@ -131,7 +131,14 @@ class PrometheusMonitor extends MonitorInterface {
131131
// label: a matching label for the component of interest
132132
// }
133133
const queryString = PrometheusQueryHelper.buildStringRangeQuery(queryObject.query, this.startTime, this.endTime, queryObject.step);
134-
const response = await this.prometheusQueryClient.getByEncodedUrl(queryString);
134+
135+
let response;
136+
try {
137+
response = await this.prometheusQueryClient.getByEncodedUrl(queryString);
138+
} catch (error) {
139+
Logger.warn('Failed to connect to Prometheus, unable to perform queries');
140+
break;
141+
}
135142

136143
// Retrieve map of component names and corresponding values for the issued query
137144
const componentNameValueMap = PrometheusQueryHelper.extractStatisticFromRange(response, queryObject.statistic, queryObject.label);
@@ -146,13 +153,13 @@ class PrometheusMonitor extends MonitorInterface {
146153
newQueryObjectIteration = false;
147154
watchItemStat.set('Name', key);
148155
const multiplier = queryObject.multiplier ? queryObject.multiplier : 1;
149-
watchItemStat.set('Value', (value*multiplier).toPrecision(this.precision));
156+
watchItemStat.set('Value', (value * multiplier).toPrecision(this.precision));
150157
// Store
151158
resourceStats.push(watchItemStat);
152159

153160
// Build separate charting information
154161
const metricMap = new Map();
155-
metricMap.set('Name', watchItemStat.get('Name'));
162+
metricMap.set('Name', watchItemStat.get('Name'));
156163
metricMap.set(queryObject.name, watchItemStat.get('Value'));
157164
metricArray.push(metricMap);
158165
}

packages/caliper-core/test/manager/monitors/monitor-prometheus.js

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,58 @@ const chai = require('chai');
2121
const should = chai.should();
2222
const sinon = require('sinon');
2323

24+
class FakeQueryClient {
25+
static getByEncodedUrlCount = 0;
26+
27+
static reset() {
28+
FakeQueryClient.getByEncodedUrlCount = 0;
29+
}
30+
31+
static setGetByEncodedUrlResponse(ableToConnect, response) {
32+
FakeQueryClient.ableToConnect = ableToConnect;
33+
FakeQueryClient.response = response;
34+
}
35+
36+
async getByEncodedUrl() {
37+
FakeQueryClient.getByEncodedUrlCount++;
38+
if (!FakeQueryClient.ableToConnect) {
39+
throw new Error('ECONNREFUSED');
40+
}
41+
return FakeQueryClient.response;
42+
}
43+
}
44+
2445
describe('Prometheus monitor implementation', () => {
2546

26-
const fakeQueryClient = sinon.stub();
27-
PrometheusMonitorRewire.__set__('PrometheusQueryClient', fakeQueryClient);
47+
PrometheusMonitorRewire.__set__('PrometheusQueryClient', FakeQueryClient);
2848

2949
// Before/After
3050
let clock;
31-
beforeEach( () => {
51+
beforeEach(() => {
3252
clock = sinon.useFakeTimers();
3353
});
3454

35-
afterEach( () => {
55+
afterEach(() => {
3656
clock.restore();
3757
});
3858

3959
// Test data
4060
const monitorOptions = {
4161
metrics : {
42-
include: ['peer', 'pushgateway', 'dev.*'],
62+
url: 'http://localhost:9090',
63+
include: ['peer', 'orderer', 'dev.*'],
4364
queries: [
4465
{
66+
name: 'avg cpu',
67+
label: 'name',
4568
query: 'sum(rate(container_cpu_usage_seconds_total{name=~".+"}[$interval])) by (name) * 100',
46-
statistic: 'average'
69+
statistic: 'avg'
4770
},
4871
{
72+
name: 'max cpu',
73+
label: 'name',
4974
query: 'sum(rate(container_cpu_usage_seconds_total{name=~".+"}[$interval])) by (name) * 100',
50-
statistic: 'maximum'
75+
statistic: 'max'
5176
}
5277
]
5378
}
@@ -78,7 +103,7 @@ describe('Prometheus monitor implementation', () => {
78103
});
79104
});
80105

81-
describe('#getQueryClient', ()=>{
106+
describe('#getQueryClient', () => {
82107

83108
it('should return the internal Query Client', () => {
84109
const mon = new PrometheusMonitorRewire({});
@@ -92,7 +117,7 @@ describe('Prometheus monitor implementation', () => {
92117

93118
it('should set the start time with the current time', () => {
94119
clock.tick(42);
95-
const mon = new PrometheusMonitorRewire({push_url: '123'});
120+
const mon = new PrometheusMonitorRewire({ push_url: '123' });
96121
mon.start();
97122
mon.startTime.should.equal(0.042);
98123
});
@@ -102,7 +127,7 @@ describe('Prometheus monitor implementation', () => {
102127
describe('#stop', () => {
103128
it('should remove startTime if it exists', () => {
104129
clock.tick(42);
105-
const mon = new PrometheusMonitorRewire({push_url: '123'});
130+
const mon = new PrometheusMonitorRewire({ push_url: '123' });
106131
mon.start();
107132
mon.startTime.should.equal(0.042);
108133
mon.stop();
@@ -114,7 +139,7 @@ describe('Prometheus monitor implementation', () => {
114139

115140
it('should reset the start time', () => {
116141
clock.tick(42);
117-
const mon = new PrometheusMonitorRewire({push_url: '123'});
142+
const mon = new PrometheusMonitorRewire({ push_url: '123' });
118143
mon.start();
119144
clock.tick(42);
120145
mon.restart();
@@ -149,15 +174,83 @@ describe('Prometheus monitor implementation', () => {
149174
const mon = new PrometheusMonitorRewire(monitorOptions);
150175
mon.includeStatistic('peer0.org0.example.com').should.equal(true);
151176

152-
mon.includeStatistic('pushgateway').should.equal(true);
177+
mon.includeStatistic('pushgateway').should.equal(false);
153178

154179
mon.includeStatistic('dev-org0.example.com').should.equal(true);
155180

156181
mon.includeStatistic('penuin').should.equal(false);
157182

158-
mon.includeStatistic('orderer0.example.com').should.equal(false);
183+
mon.includeStatistic('orderer0.example.com').should.equal(true);
159184
});
160185
});
161186

187+
describe('When getting statistics', () => {
188+
const response = {
189+
status: 'success',
190+
data: {
191+
resultType: 'matrix',
192+
result: [
193+
{
194+
metric: {
195+
name: 'orderer.example.com'
196+
},
197+
values: [
198+
[
199+
1648125000.736,
200+
'37318656'
201+
],
202+
[
203+
1648125010.736,
204+
'37318656'
205+
],
206+
[
207+
1648125020.736,
208+
'37318656'
209+
]
210+
]
211+
},
212+
{
213+
metric: {
214+
name: 'peer0.org1.example.com'
215+
},
216+
values: [
217+
[
218+
1648125000.736,
219+
'80855040'
220+
],
221+
[
222+
1648125010.736,
223+
'80855040'
224+
],
225+
[
226+
1648125020.736,
227+
'80855040'
228+
]
229+
]
230+
}
231+
]
232+
}
233+
};
234+
235+
it('should stop processing further queries and return an empty set of results if it fails to connect to prometheus ', async () => {
236+
const prometheusMonitor = new PrometheusMonitorRewire(monitorOptions);
237+
FakeQueryClient.reset();
238+
FakeQueryClient.setGetByEncodedUrlResponse(false);
239+
const res = await prometheusMonitor.getStatistics();
240+
FakeQueryClient.getByEncodedUrlCount.should.equal(1);
241+
res.resourceStats.length.should.equal(0);
242+
res.chartStats.length.should.equal(0);
243+
});
244+
245+
it('should process all queries successfully if able to connect to prometheus', async () => {
246+
const prometheusMonitor = new PrometheusMonitorRewire(monitorOptions);
247+
FakeQueryClient.reset();
248+
FakeQueryClient.setGetByEncodedUrlResponse(true, response);
249+
const res = await prometheusMonitor.getStatistics();
250+
FakeQueryClient.getByEncodedUrlCount.should.equal(2);
251+
res.resourceStats.length.should.equal(4);
252+
res.chartStats.length.should.equal(0);
253+
});
254+
});
162255

163256
});

0 commit comments

Comments
 (0)