Skip to content

Commit 0851b4f

Browse files
committed
prometheus data processing and storage
1 parent 32d494a commit 0851b4f

38 files changed

+1498
-491
lines changed

chronos_npm_package/chronos.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,20 @@ class Chronos {
138138
}
139139
}
140140

141+
async docker () {
142+
await utilities.testMetricsQuery(this.config);
143+
if (this.config.database.type === 'MongoDB') {
144+
mongo.connect(this.config);
145+
mongo.serverQuery(this.config);
146+
// return mongo.modifyMetrics(this.config);
147+
} else if (this.config.database.type === 'PostgreSQL') {
148+
postgres.connect(this.config);
149+
postgres.serverQuery(this.config);
150+
} else {
151+
throw new Error('The only allowed database types are MongoDB and PostgreSQL');
152+
}
153+
}
154+
141155
ServerWrapper(server, proto, methods) {
142156
/**
143157
* Wraps the gRPC server object to automatically write logs to provided DB

chronos_npm_package/controllers/mongo.js

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,14 @@ mongo.serverQuery = async config => {
169169
await mongo.setQueryOnInterval(config);
170170
};
171171

172-
mongo.saveService = async config => {
172+
mongo.saveService = config => {
173173
let microservice;
174174
if (config.mode === 'kafka') {
175175
microservice = 'kafkametrics';
176176
} else if (config.mode === 'kubernetes') {
177177
microservice = 'kubernetesmetrics';
178+
} else if (config.mode === 'docker') {
179+
microservice = `${config.containerName}`;
178180
} else {
179181
throw new Error('Unrecongnized mode');
180182
}
@@ -205,6 +207,11 @@ mongo.setQueryOnInterval = async config => {
205207
} else if (config.mode === 'kubernetes') {
206208
model = KubernetesModel;
207209
metricsQuery = await utilities.promMetricsQuery;
210+
} else if (config.mode === 'docker') {
211+
model = ContainerInfoFunc(`${config.containerName}`);
212+
//console.log('setQueryOnInterval line 212 dockerModel:', ContainerInfoFunc(`${config.containerName}`));
213+
metricsQuery = utilities.promMetricsQuery;
214+
//console.log('setQueryOnInterval line 214 metricsQuery:', metricsQuery);
208215
} else {
209216
throw new Error('Unrecognized mode');
210217
}
@@ -230,24 +237,25 @@ mongo.setQueryOnInterval = async config => {
230237
///////
231238
length = await mongo.addMetrics(parsedArray, config.mode, currentMetricNames, model);
232239
}
233-
// const documents = [];
234-
// for (const metric of parsedArray) {
235-
// /**
236-
// * This will check if the current metric in the parsed array
237-
// * evaluates to true within the currentMetricNames object
238-
// * which is updated by the user when they select/deselect metrics on the electron app
239-
// * helping to avoid overloading the db with unnecessary data.
240-
// */
241-
242-
// if (currentMetricNames[metric.metric]) documents.push(model(metric));
243-
// }
244-
// await model.insertMany(parsedArray, err => {
245-
// if (err) {
246-
// console.error(err)
247-
// } else {
248-
// console.log(`${config.mode} metrics recorded in MongoDB`)
249-
// }
250-
// });
240+
const documents = [];
241+
for (const metric of parsedArray) {
242+
/**
243+
* This will check if the current metric in the parsed array
244+
* evaluates to true within the currentMetricNames object
245+
* which is updated by the user when they select/deselect metrics on the electron app
246+
* helping to avoid overloading the db with unnecessary data.
247+
*/
248+
249+
if (currentMetricNames[metric.metric]) documents.push(model(metric));
250+
}
251+
await model.insertMany(parsedArray, err => {
252+
if (err) {
253+
console.error(err)
254+
} else {
255+
console.log(`${config.mode} metrics recorded in MongoDB`)
256+
}
257+
});
258+
251259
let allMetrics = await model.find({});
252260
console.log('allMetrics.length: ', allMetrics.length);
253261
console.log("🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 start creating dashboards 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡 🟡")

chronos_npm_package/controllers/utilities.js

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ const helpers = {
5555
);
5656
}
5757

58-
const modeTypes = ['kafka', 'kubernetes', 'microservices'];
58+
const modeTypes = ['kafka', 'kubernetes', 'microservices', 'docker'];
5959

6060
if (!mode || !modeTypes.includes(mode)) {
6161
throw new Error(
62-
'You must input a mode into your chronos.config file. The mode may either be "kubernetes", "kafka", or "microservice"'
62+
'You must input a mode into your chronos.config file. The mode may either be "kubernetes", "kafka", "microservice", or "docker"'
6363
);
6464
}
6565

@@ -69,7 +69,7 @@ const helpers = {
6969
);
7070
}
7171

72-
if (mode === 'kubernetes') {
72+
if (mode === 'kubernetes' || mode === 'docker') {
7373
if (
7474
!promService ||
7575
typeof promService !== 'string' ||
@@ -139,7 +139,7 @@ const helpers = {
139139
getMetricsURI: config => {
140140
if (config.mode === 'kafka') {
141141
return config.jmxuri;
142-
} else if (config.mode === 'kubernetes') {
142+
} else if (config.mode === 'kubernetes' || config.mode === 'docker') {
143143
return `http://${config.promService}:${config.promPort}/api/v1/query?query=`;
144144
} else {
145145
throw new Error('Unrecognized mode');
@@ -153,14 +153,14 @@ const helpers = {
153153
*/
154154
testMetricsQuery: async config => {
155155
let URI = helpers.getMetricsURI(config);
156-
if (config.mode === 'kubernetes') URI += 'up';
156+
URI += 'up';
157157
try {
158158
const response = await axios.get(URI);
159-
if (response.status !== 200) console.error('Invalid response from metrics server:', URI);
159+
if (response.status !== 200) console.error('Invalid response from metrics server:', URI, response.status, response.data);
160160
else console.log('Successful initial response from metrics server:', URI);
161161
return response;
162162
} catch (error) {
163-
console.log(error);
163+
console.error(error);
164164
throw new Error('Unable to query metrics server: ' + URI);
165165
}
166166
},
@@ -226,38 +226,30 @@ const helpers = {
226226
*/
227227
promMetricsQuery: async config => {
228228
const URI = helpers.getMetricsURI(config);
229-
const query = URI + encodeURIComponent('{__name__=~".+",container=""}');
230-
try {
231-
const response = await axios.get(query);
232-
//console.log("response is: ", response);
233-
return helpers.parseProm(response.data.data.result);
234-
} catch (error) {
235-
return console.error(config.mode, '|', 'Error fetching from URI:', URI, '\n', error);
229+
let query;
230+
if (config.mode === 'docker') {
231+
query = URI + encodeURIComponent(`{__name__=~".+",name="${config.containerName}"}`);
232+
} else {
233+
query = URI + encodeURIComponent('{__name__=~".+",container=""}');
236234
}
237-
},
238-
239-
promMetrics: async config => {
240-
const URI = `http://${config.promService}:${config.promPort}/api/v1/query?query=`;
241-
const query = URI + encodeURIComponent('{__name__=~".+",container=""}');
242235
try {
243236
const response = await axios.get(query);
244-
//console.log("response is: ", response);
245-
return response.data.data.result;
237+
//console.log('promMetricsQuery line 236:', response.data.data.result);
238+
return helpers.parseProm(config, response.data.data.result);
246239
} catch (error) {
247-
return console.error('Error fetching from URI:', URI, '\n', error);
240+
return console.error(config.mode, '|', 'Error fetching from URI:', URI, '\n', error);
248241
}
249242
},
250243

251-
252244
/**
253245
* Parses response from Prometheus request and returns object with
254246
* @param {*} data
255247
* @returns bject with the gathered metric, value, time gathered, and category of event
256248
*/
257-
parseProm: data => {
249+
parseProm: (config, data) => {
258250
const res = [];
259251
const time = Date.now();
260-
const category = 'Event';
252+
const category = config.mode === 'docker' ? `${config.containerName}`: 'Event';
261253

262254
/**
263255
* Opportunity for improvement: Prometheus may query metrics that have the same job + instance + metric
@@ -272,10 +264,18 @@ const helpers = {
272264
const names = new Set();
273265

274266
for (const info of data) {
275-
if (!info.metric.job) continue;
276-
// Set the base name using the job, IP, and metric __name__
277-
let wholeName = info.metric.job + '/' + info.metric.instance + '/' + info.metric['__name__'];
278-
let name = wholeName.replace(/.*\/.*\//g, '');
267+
let wholeName;
268+
let name;
269+
if (config.mode === 'docker'){
270+
if (!info.metric.name) continue;
271+
wholeName = info.metric['__name__'];
272+
name = wholeName.replace(/.*\/.*\//g, '');
273+
} else {
274+
if (!info.metric.job) continue;
275+
// Set the base name using the job, IP, and metric __name__
276+
wholeName = info.metric.job + '/' + info.metric.instance + '/' + info.metric['__name__'];
277+
name = wholeName.replace(/.*\/.*\//g, '');
278+
}
279279
if (names.has(name)) continue;
280280
else {
281281
names.add(name);
@@ -303,6 +303,8 @@ const helpers = {
303303
return res;
304304
},
305305

306+
307+
306308
createGrafanaDashboard: async (
307309
metric,
308310
datasource,

chronos_npm_package/models/ContainerInfo.js

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -2,53 +2,24 @@ const mongoose = require('mongoose');
22

33
const { Schema } = mongoose;
44

5-
const ContainerSchema = new Schema({
6-
// Added additional schema for Docker container stats (9).
7-
containerid: {
8-
type: String,
9-
},
10-
containername: {
11-
type: String,
12-
},
13-
platform: {
14-
type: String,
15-
},
16-
starttime: {
5+
const DockerSchema = new Schema({
6+
time: {
177
type: Date,
8+
default: Date.now(),
189
},
19-
memoryusage: {
20-
type: Number, // bytes
21-
},
22-
memorylimit: {
23-
type: Number,
24-
},
25-
memorypercent: {
26-
type: Number,
10+
metric: {
11+
type: String,
2712
},
28-
cpupercent: {
13+
value: {
2914
type: Number,
3015
},
31-
networkreceived: {
32-
type: Number, // bytes
33-
default: 0,
34-
},
35-
networksent: {
36-
type: Number, // bytes
37-
default: 0,
38-
},
39-
processcount: {
40-
type: Number, // count
41-
},
42-
restartcount: {
43-
type: Number, // count
44-
},
45-
time: {
46-
type: Date,
47-
default: Date.now(),
16+
category: {
17+
type: String,
18+
default: '',
4819
},
4920
});
5021

5122
module.exports = ContainerName => {
5223
console.log('Inside Docker Schema ContainerInfo.js LN52', ContainerName)
53-
return mongoose.model(ContainerName, ContainerSchema);
24+
return mongoose.model(ContainerName, DockerSchema);
5425
};

examples/docker/books/BookServer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ chronos.propagate();
1414
const app = express();
1515

1616
app.use(express.json());
17-
app.use('/', chronos.track());
17+
chronos.docker();
1818

1919
app.use(cors());
2020
app.use('/', express.static(path.resolve(__dirname, '../frontend')));

examples/docker/books/chronos-config.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ module.exports = {
66
microservice: 'books',
77
interval: 5000,
88

9-
// Mode Specific
10-
mode: 'microservices',
11-
dockerized: true,
9+
// Mode Specific
10+
mode: 'docker',
11+
promService: 'docker.for.mac.localhost',
12+
promPort: 9090,
13+
containerName: 'books',
1214

1315
database: {
1416
connection: 'REST',

examples/docker/books/chronos_npm_package/chronos.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ class Chronos {
108108
if (this.config.database.type === 'MongoDB') {
109109
mongo.connect(this.config);
110110
mongo.serverQuery(this.config);
111-
} else if (this.config.database.type === 'PostgreSQL') {
111+
}
112+
113+
else if (this.config.database.type === 'PostgreSQL') {
112114
postgres.connect(this.config);
113115
postgres.serverQuery(this.config);
114116
} else {
@@ -120,6 +122,24 @@ class Chronos {
120122
// Test metrics server connection
121123
await utilities.testMetricsQuery(this.config);
122124

125+
if (this.config.database.type === 'MongoDB') {
126+
await mongo.connect(this.config);
127+
await mongo.storeGrafanaAPIKey(this.config);
128+
//await mongo.createGrafanaDashboards(this.config);
129+
mongo.serverQuery(this.config);
130+
// return mongo.modifyMetrics(this.config);
131+
}
132+
133+
else if (this.config.database.type === 'PostgreSQL') {
134+
postgres.connect(this.config);
135+
postgres.serverQuery(this.config);
136+
} else {
137+
throw new Error('The only allowed database types are MongoDB and PostgreSQL');
138+
}
139+
}
140+
141+
async docker () {
142+
await utilities.testMetricsQuery(this.config);
123143
if (this.config.database.type === 'MongoDB') {
124144
mongo.connect(this.config);
125145
mongo.serverQuery(this.config);

0 commit comments

Comments
 (0)