Implement metrics
This commit is contained in:
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"sqltools.connections": [
|
||||||
|
{
|
||||||
|
"previewLimit": 50,
|
||||||
|
"driver": "SQLite",
|
||||||
|
"name": "1",
|
||||||
|
"database": "E:\\tmp\\output.db"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
22
client.js
22
client.js
@@ -5,6 +5,7 @@ const NanoTimer = require("nanotimer");
|
|||||||
const { createBaseLogger, createSessionLogger } = require("./logger");
|
const { createBaseLogger, createSessionLogger } = require("./logger");
|
||||||
const { verifyDefaults, verifyExists } = require("./utils");
|
const { verifyDefaults, verifyExists } = require("./utils");
|
||||||
const { clientOptions } = require("./cliOptions");
|
const { clientOptions } = require("./cliOptions");
|
||||||
|
const { MetricManager } = require("./metrics/metricManager");
|
||||||
|
|
||||||
const logger = createBaseLogger();
|
const logger = createBaseLogger();
|
||||||
const options = commandLineArgs(clientOptions);
|
const options = commandLineArgs(clientOptions);
|
||||||
@@ -78,6 +79,17 @@ function startInterval(session, sessionLogger) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const metricManager = new MetricManager();
|
||||||
|
// async function main() {
|
||||||
|
// const test1 = metricManager.AddMetrics("test");
|
||||||
|
// for (let i = 0; i < 1e5; i++) {
|
||||||
|
// test1.AddEvent();
|
||||||
|
// test1.UpdateBar();
|
||||||
|
// await setTimeout(() => {}, 200);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// main();
|
||||||
|
|
||||||
for (let i = 0; i < options.sessions; i++) {
|
for (let i = 0; i < options.sessions; i++) {
|
||||||
const sessionLogger = createSessionLogger(i);
|
const sessionLogger = createSessionLogger(i);
|
||||||
sessionLogger.info(`Connecting to ${options.host}:${options.port}...`);
|
sessionLogger.info(`Connecting to ${options.host}:${options.port}...`);
|
||||||
@@ -101,12 +113,20 @@ for (let i = 0; i < options.sessions; i++) {
|
|||||||
sessionLogger.info(
|
sessionLogger.info(
|
||||||
`Successfully bound, sending ${options.messagecount} messages '${options.source}'->'${options.destination}' ('${options.message}')`
|
`Successfully bound, sending ${options.messagecount} messages '${options.source}'->'${options.destination}' ('${options.message}')`
|
||||||
);
|
);
|
||||||
|
const rxMetrics = metricManager.AddMetrics(`Session-${i}-RX`);
|
||||||
|
const txMetrics = metricManager.AddMetrics(`Session-${i}-TX`);
|
||||||
startInterval(session, sessionLogger);
|
startInterval(session, sessionLogger);
|
||||||
// TODO: Add error message for invalid systemid and password
|
// TODO: Add error message for invalid systemid and password
|
||||||
|
|
||||||
session.on("deliver_sm", function (pdu) {
|
session.on("deliver_sm", function (pdu) {
|
||||||
sessionLogger.info("Got deliver_sm, replying...");
|
rxMetrics.AddEvent();
|
||||||
|
// sessionLogger.info("Got deliver_sm, replying...");
|
||||||
|
setTimeout(() => {
|
||||||
session.send(pdu.response());
|
session.send(pdu.response());
|
||||||
|
txMetrics.AddEvent();
|
||||||
|
}, 2000);
|
||||||
|
// session.send(pdu.response());
|
||||||
|
// txMetrics.AddEvent();
|
||||||
});
|
});
|
||||||
session.on("enquire_link", function (pdu) {
|
session.on("enquire_link", function (pdu) {
|
||||||
session.send(pdu.response());
|
session.send(pdu.response());
|
||||||
|
30
metrics/circularBuffer.js
Normal file
30
metrics/circularBuffer.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
class CircularBuffer {
|
||||||
|
constructor(size) {
|
||||||
|
this.buffer = new Array(size);
|
||||||
|
this.size = size;
|
||||||
|
this.head = 0;
|
||||||
|
this.tail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
push(item) {
|
||||||
|
this.buffer[this.head] = item;
|
||||||
|
this.head = (this.head + 1) % this.size;
|
||||||
|
if (this.head === this.tail) {
|
||||||
|
this.tail = (this.tail + 1) % this.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toArray() {
|
||||||
|
const result = [];
|
||||||
|
let current = this.tail;
|
||||||
|
for (let i = 0; i < this.size; i++) {
|
||||||
|
if (this.buffer[current] !== undefined) {
|
||||||
|
result.push(this.buffer[current]);
|
||||||
|
}
|
||||||
|
current = (current + 1) % this.size;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { CircularBuffer };
|
24
metrics/metricManager.js
Normal file
24
metrics/metricManager.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const cliProgress = require("cli-progress");
|
||||||
|
const { Metric } = require("./metrics");
|
||||||
|
|
||||||
|
class MetricManager {
|
||||||
|
constructor() {
|
||||||
|
this.metricBufferSize = 1000;
|
||||||
|
this.multibar = new cliProgress.MultiBar(
|
||||||
|
{
|
||||||
|
clearOnComplete: false,
|
||||||
|
barCompleteChar: "\u2588",
|
||||||
|
barIncompleteChar: "\u2591",
|
||||||
|
format: " {bar} | {name} | {value}/{total}",
|
||||||
|
},
|
||||||
|
cliProgress.Presets.shades_grey
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddMetrics(name) {
|
||||||
|
const metric = new Metric(name, this.multibar, this.metricBufferSize);
|
||||||
|
return metric;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { MetricManager };
|
39
metrics/metrics.js
Normal file
39
metrics/metrics.js
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
const { CircularBuffer } = require("./circularBuffer");
|
||||||
|
|
||||||
|
class Metric {
|
||||||
|
constructor(barName, multibar, bufferSize) {
|
||||||
|
this.multibar = multibar;
|
||||||
|
this.pbar = multibar.create(0, 0);
|
||||||
|
this.pbar.update(0, { name: barName });
|
||||||
|
this.buffer = new CircularBuffer(bufferSize);
|
||||||
|
this.maxRate = 0;
|
||||||
|
setInterval(this.UpdateBar.bind(this), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddEvent() {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
this.buffer.push({ timestamp, count: 1 });
|
||||||
|
}
|
||||||
|
|
||||||
|
GetRate() {
|
||||||
|
const entries = this.buffer.toArray();
|
||||||
|
const currentTime = Date.now();
|
||||||
|
|
||||||
|
const interval = entries.length > 1 ? currentTime - entries[0].timestamp : 1;
|
||||||
|
|
||||||
|
const totalRX = entries.reduce((sum, entry) => sum + entry.count, 0);
|
||||||
|
return Math.round((totalRX / interval) * 100000) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateBar() {
|
||||||
|
const eps = this.GetRate();
|
||||||
|
if (eps > this.maxRate) {
|
||||||
|
this.pbar.total = eps;
|
||||||
|
this.maxRate = eps;
|
||||||
|
}
|
||||||
|
this.pbar.update(eps);
|
||||||
|
this.multibar.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Metric };
|
@@ -14,6 +14,7 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"cli-progress": "^3.12.0",
|
||||||
"command-line-args": "^5.2.1",
|
"command-line-args": "^5.2.1",
|
||||||
"command-line-usage": "^7.0.1",
|
"command-line-usage": "^7.0.1",
|
||||||
"nanotimer": "^0.3.15",
|
"nanotimer": "^0.3.15",
|
||||||
|
30
pnpm-lock.yaml
generated
30
pnpm-lock.yaml
generated
@@ -5,6 +5,9 @@ settings:
|
|||||||
excludeLinksFromLockfile: false
|
excludeLinksFromLockfile: false
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
cli-progress:
|
||||||
|
specifier: ^3.12.0
|
||||||
|
version: 3.12.0
|
||||||
command-line-args:
|
command-line-args:
|
||||||
specifier: ^5.2.1
|
specifier: ^5.2.1
|
||||||
version: 5.2.1
|
version: 5.2.1
|
||||||
@@ -166,7 +169,6 @@ packages:
|
|||||||
/ansi-regex@5.0.1:
|
/ansi-regex@5.0.1:
|
||||||
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/ansi-styles@4.3.0:
|
/ansi-styles@4.3.0:
|
||||||
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
|
||||||
@@ -222,6 +224,13 @@ packages:
|
|||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
supports-color: 7.2.0
|
supports-color: 7.2.0
|
||||||
|
|
||||||
|
/cli-progress@3.12.0:
|
||||||
|
resolution: {integrity: sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==}
|
||||||
|
engines: {node: '>=4'}
|
||||||
|
dependencies:
|
||||||
|
string-width: 4.2.3
|
||||||
|
dev: false
|
||||||
|
|
||||||
/color-convert@1.9.3:
|
/color-convert@1.9.3:
|
||||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -318,6 +327,10 @@ packages:
|
|||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/emoji-regex@8.0.0:
|
||||||
|
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/enabled@2.0.0:
|
/enabled@2.0.0:
|
||||||
resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
|
resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -569,6 +582,11 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/is-fullwidth-code-point@3.0.0:
|
||||||
|
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/is-glob@4.0.3:
|
/is-glob@4.0.3:
|
||||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -839,6 +857,15 @@ packages:
|
|||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/string-width@4.2.3:
|
||||||
|
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dependencies:
|
||||||
|
emoji-regex: 8.0.0
|
||||||
|
is-fullwidth-code-point: 3.0.0
|
||||||
|
strip-ansi: 6.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
/string_decoder@1.3.0:
|
/string_decoder@1.3.0:
|
||||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -850,7 +877,6 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-regex: 5.0.1
|
ansi-regex: 5.0.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/strip-json-comments@3.1.1:
|
/strip-json-comments@3.1.1:
|
||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
|
Reference in New Issue
Block a user