Browse Source

- basic rpc stat tracking

- simple admin dashboard: mem usage and rpc stats display
- minor frontend cleanup
master
Dan Janosik 5 years ago
parent
commit
d2786e5b6c
No known key found for this signature in database GPG Key ID: C6F8CE9FFDB2CED2
  1. 2
      app.js
  2. 34
      app/api/rpcApi.js
  3. 3
      routes/baseActionsRouter.js
  4. 92
      views/admin.pug
  5. 30
      views/block-analysis-search.pug
  6. 6
      views/layout.pug
  7. 17
      views/search.pug

2
app.js

@ -179,7 +179,7 @@ function loadHistoricalDataForChain(chain) {
function verifyRpcConnection() {
if (!global.activeBlockchain) {
debugLog(`Trying to verify RPC connection...`);
debugLog(`Verifying RPC connection...`);
coreApi.getNetworkInfo().then(function(getnetworkinfo) {
coreApi.getBlockchainInfo().then(function(getblockchaininfo) {

34
app/api/rpcApi.js

@ -26,6 +26,8 @@ var rpcQueue = async.queue(function(task, callback) {
var minRpcVersions = {getblockstats:"0.17.0"};
global.rpcStats = {};
function getBlockchainInfo() {
@ -321,6 +323,8 @@ function getRpcMethodHelp(methodName) {
function getRpcData(cmd) {
var startTime = new Date().getTime();
return new Promise(function(resolve, reject) {
debugLog(`RPC: ${cmd}`);
@ -335,11 +339,15 @@ function getRpcData(cmd) {
callback();
logStats(cmd, false, new Date().getTime() - startTime, false);
return;
}
resolve(result);
logStats(cmd, false, new Date().getTime() - startTime, true);
callback();
});
};
@ -349,6 +357,8 @@ function getRpcData(cmd) {
}
function getRpcDataWithParams(request) {
var startTime = new Date().getTime();
return new Promise(function(resolve, reject) {
debugLog(`RPC: ${JSON.stringify(request)}`);
@ -361,11 +371,15 @@ function getRpcDataWithParams(request) {
callback();
logStats(request.method, true, new Date().getTime() - startTime, false);
return;
}
resolve(result[0]);
logStats(request.method, true, new Date().getTime() - startTime, true);
callback();
});
};
@ -380,6 +394,26 @@ function unsupportedPromise(minRpcVersionNeeded) {
});
}
function logStats(cmd, hasParams, dt, success) {
if (!global.rpcStats[cmd]) {
global.rpcStats[cmd] = {count:0, withParams:0, time:0, successes:0, failures:0};
}
global.rpcStats[cmd].count++;
global.rpcStats[cmd].time += dt;
if (hasParams) {
global.rpcStats[cmd].withParams++;
}
if (success) {
global.rpcStats[cmd].successes++;
} else {
global.rpcStats[cmd].failures++;
}
}
module.exports = {
getBlockchainInfo: getBlockchainInfo,

3
routes/baseActionsRouter.js

@ -846,7 +846,7 @@ router.get("/tx/:transactionId", function(req, res, next) {
}).catch(function(err) {
res.locals.userMessage = "Failed to load transaction with txid=" + txid + ": " + err;
res.locals.pageErrors.push(utils.logError("1237y4ewssgt", err));
res.render("transaction");
@ -1438,6 +1438,7 @@ router.get("/tools", function(req, res, next) {
router.get("/admin", function(req, res, next) {
res.locals.memstats = v8.getHeapStatistics();
res.locals.rpcStats = global.rpcStats;
res.render("admin");

92
views/admin.pug

@ -7,5 +7,93 @@ block content
h1.h3 Admin
hr
pre
code.json #{JSON.stringify(memstats, null, 4)}
ul.nav.nav-tabs.mb-3
li.nav-item
a.nav-link.active(data-toggle="tab", href="#tab-details", role="tab") Details
li.nav-item
a.nav-link(data-toggle="tab", href="#tab-json", role="tab") JSON
div.tab-content
div.tab-pane.active(id="tab-details", role="tabpanel")
div.card.shadow-sm.mb-3
div.card-body
h3.h6 Memory Stats
hr
div.clearfix
div.row
div.summary-table-label Heap Size
div.summary-table-content.text-monospace
- var data = utils.formatLargeNumber(memstats.total_heap_size, 2);
span #{data[0]}
small #{data[1].abbreviation}B
div.row
div.summary-table-label Used Heap
div.summary-table-content.text-monospace
- var data = utils.formatLargeNumber(memstats.used_heap_size, 2);
span #{data[0]}
small #{data[1].abbreviation}B
div.row
div.summary-table-label Heap Limit
div.summary-table-content.text-monospace
- var data = utils.formatLargeNumber(memstats.heap_size_limit, 2);
span #{data[0]}
small #{data[1].abbreviation}B
div.row
div.summary-table-label Physical Size
div.summary-table-content.text-monospace
- var data = utils.formatLargeNumber(memstats.total_physical_size, 2);
span #{data[0]}
small #{data[1].abbreviation}B
div.row
div.summary-table-label Available Size
div.summary-table-content.text-monospace
- var data = utils.formatLargeNumber(memstats.total_available_size, 2);
span #{data[0]}
small #{data[1].abbreviation}B
div.card.shadow-sm.mb-3
div.card-body
h3.h6 RPC Stats
hr
table.table.table-hover.table-striped
thead
tr
th Method
th.text-right Count
th.text-right Time
small (s)
th.text-right Avg Time
small (ms)
th.text-right Successes / Failures
th.text-right Success Rate
tbody
each item, itemName in rpcStats
tr.text-monospace
td #{itemName}
td.text-right #{item.count.toLocaleString()}
td.text-right #{(item.time / 1000).toLocaleString()}
td.text-right #{(item.time / item.count).toLocaleString()}
td.text-right
span.text-success #{item.successes.toLocaleString()}
span.mx-1 /
span.text-danger #{item.failures.toLocaleString()}
td.text-right
span #{new Decimal(item.successes).dividedBy(new Decimal(item.successes + item.failures)).times(100).toDP(1)}%
div.tab-pane(id="tab-json", role="tabpanel")
div.card.shadow-sm.mb-3
div.card-body
h3.h6 Memory Stats
hr
div.highlight
pre
code.json #{JSON.stringify(memstats, null, 4)}

30
views/block-analysis-search.pug

@ -7,17 +7,29 @@ block content
h1.h3 Block Analysis
hr
p Search for a block by height or hash to see a summary analysis of the transactions within that block.
div.card.shadow-sm.mb-huge
div.card-body
h6.mb-3 Search for a block by height or hash to see a summary analysis of the transactions within that block.
div.mb-huge
form.form.form-inline(method="get", action="/block-analysis")
input(type="hidden", name="_csrf", value=csrfToken)
div.mb-3
form.form.form-inline(method="get", action="/block-analysis")
input(type="hidden", name="_csrf", value=csrfToken)
div.input-group
input.form-control(id="input-value", type="text", name="query", placeholder="block height/hash", value=(query), style="width: 400px;")
div.input-group-append
button.btn.btn-primary(type="submit") Go
div.input-group
input.form-control(id="input-value", type="text", name="query", placeholder="block height/hash", value=(query), style="width: 400px;")
div.input-group-append
button.btn.btn-primary(type="submit") Go
hr.my-4
h6 Selection of example blocks:
- var heights = [0, 170, 100000, 210000, 420000, 481824];
ul.text-monospace
each height in heights
li
a(href=`/block-analysis/${height}`) Block ##{height.toLocaleString()}
block endOfBody
script.

6
views/layout.pug

@ -86,6 +86,12 @@ html(lang="en")
i.fas.fa-search
ul.navbar-nav
li.nav-item.dropdown
a.nav-link.dropdown-toggle(href="javascript:void(0)", role="button", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
span Admin Tools
div.dropdown-menu.dropdown-menu-right.shadow(aria-label="Admin Tools Items")
a.dropdown-item(href="/admin") Admin Dashboard
li.nav-item.dropdown
a.nav-link.dropdown-toggle(href="javascript:void(0)", id="navbarDropdown", role="button", data-toggle="dropdown", aria-haspopup="true", aria-expanded="false")
i.fas.fa-cog.mr-1

17
views/search.pug

@ -7,12 +7,13 @@ block content
h1.h3 Search
hr
div.mb-huge
form.form.form-inline(method="post", action="/search")
input(type="hidden", name="_csrf", value=csrfToken)
div.card.shadow-sm.mb-huge
div.card-body
form.form.form-inline(method="post", action="/search")
input(type="hidden", name="_csrf", value=csrfToken)
div.input-group
input.form-control(type="text", name="query", placeholder="block height/hash, txid, address", value=(query), style="width: 400px;")
div.input-group-append
button.btn.btn-primary(type="submit") Search
div.input-group
input.form-control(type="text", name="query", placeholder="block height/hash, txid, address", value=(query), style="width: 400px;")
div.input-group-append
button.btn.btn-primary(type="submit") Search
Loading…
Cancel
Save