Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a summary tab to Javametrics. #49

Merged
merged 2 commits into from
Nov 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 114 additions & 40 deletions dashboard/src/main/webapp/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,47 @@

<div class="headerDiv"><span class="rightHeader"></span><span class="leftHeader"></span></div>

<div class="container-fluid">
<div class="row">
<div class="col-md-6 hideable" id="httpDiv1"></div>
<div class="col-md-3 hideable" id="httpDiv2"></div>
<div class="col-md-3 hideable" id="httpDiv3"></div>
<div id="tabs" class="container">

<ul class="nav nav-tabs">
<li class="active">
<a href="#dashboard" id="dashboard-tab" data-toggle="tab">Dashboard</a>
</li>
<li>
<a href="#summary" id="summary-tab" data-toggle="tab">Summary</a>
</li>
</ul>

<div class="tab-content ">
<div class="tab-pane active" id="dashboard">
<div class="container-fluid">
<div class="row">
<div class="col-md-6 hideable" id="httpDiv1"></div>
<div class="col-md-3 hideable" id="httpDiv2"></div>
<div class="col-md-3 hideable" id="httpDiv3"></div>
</div>

<div class="row">
<div class="col-md-4 hideable" id="cpuDiv1"></div>
<div class="col-md-4 hideable" id="gcDiv1"></div>
<!-- <div class="col-md-4 hideable" id="envDiv"></div> -->
</div>
<div class="row">
<div class="col-md-6 hideable" id="memPoolsDiv"></div>
</div>
</div>
</div>

<div class="row">
<div class="col-md-4 hideable" id="cpuDiv1"></div>
<div class="col-md-4 hideable" id="gcDiv1"></div>
<div class="col-md-4 hideable" id="envDiv"></div>
</div>
<div class="row">
<div class="col-md-6 hideable" id="memPoolsDiv"></div>
<div class="tab-pane" id="summary">
<div class="container-fluid">
<div class="row">
<div class="col-md-4 hideable" id="envDiv"></div>
<div class="col-md-4 hideable" id="summaryDiv"></div>
<div class="col-md-4 hideable" id="top5Div"></div>
</div>
</div>
</div>
</div>
</div>

<script>
Expand All @@ -65,14 +91,14 @@
shortBottom: 30,
left: 60
},
canvasWidth = $("#cpuDiv1").width() - 8, // -8 for margins and borders
httpCanvasWidth = $("#httpDiv1").width() - 8,
memPoolsCanvasWidth = $("#memPoolsDiv").width() - 8,
graphWidth = canvasWidth - margin.left - margin.right,
httpGraphWidth = httpCanvasWidth - margin.left - margin.right,
memPoolsGraphWidth = memPoolsCanvasWidth - margin.left - margin.right,
canvasHeight = 250,
tallerGraphHeight = canvasHeight - margin.top - margin.shortBottom,
canvasWidth = $("#cpuDiv1").width() - 8; // -8 for margins and borders
httpCanvasWidth = $("#httpDiv1").width() - 8;
memPoolsCanvasWidth = $("#memPoolsDiv").width() - 8;
graphWidth = canvasWidth - margin.left - margin.right;
httpGraphWidth = httpCanvasWidth - margin.left - margin.right;
memPoolsGraphWidth = memPoolsCanvasWidth - margin.left - margin.right;
canvasHeight = 250;
tallerGraphHeight = canvasHeight - margin.top - margin.shortBottom;
graphHeight = canvasHeight - margin.top - margin.bottom;

let myurl = location.host;
Expand All @@ -98,23 +124,30 @@
</script>

<script type="text/javascript" src="graphmetrics/js/header.js"></script>
<script type="text/javascript" src="graphmetrics/js/envTable.js"></script>
<script type="text/javascript" src="graphmetrics/js/textTable.js"></script>
<script type="text/javascript" src="graphmetrics/js/cpuChart.js"></script>
<script type="text/javascript" src="graphmetrics/js/httpThroughPutChart.js"></script>
<script type="text/javascript" src="graphmetrics/js/httpRequestsChart.js"></script>
<script type="text/javascript" src="graphmetrics/js/httpTop5.js"></script>
<script type="text/javascript" src="graphmetrics/js/top5.js"></script>
<script type="text/javascript" src="graphmetrics/js/gcTimeChart.js"></script>
<script type="text/javascript" src="graphmetrics/js/memPoolsChart.js"></script>
<script>
let hostname = location.host;
let pathname = location.pathname
let pathname = location.pathname;
let dashboardRoot = "/" + pathname.split('/')[1];

var webSocketProtocol = "ws://"
let webSocketProtocol = "ws://"
if(location.protocol === "https:") {
webSocketProtocol = "wss://"
}

let client = new WebSocket(webSocketProtocol + hostname + pathname + "javametrics-socket")
let summary = {cpu:{}, gc:{}, memoryPools:{}};

let envTable = new TextTable('#envDiv', '#summary', localizedStrings.envTitle);
let summaryTable = new TextTable('#summaryDiv', '#summary', "Summary"); // TODO move this to localizedStrings.
let httpTop5 = new Top5('#top5Div', '#summary', localizedStrings.httpTop5Title);
httpTop5.settop5Options({host: hostname, filteredPath: dashboardRoot});

client.onmessage = function(message) {
received = JSON.parse(message.data);
Expand All @@ -124,46 +157,87 @@
switch (topic) {
case 'cpu':
updateCPUData(payload);
summary.cpu.systemMean = received.payload.systemMean;
summary.cpu.processMean = received.payload.processMean;
break;
case 'gc':
updateGCData(payload);
summary.gc.time = received.payload.gcTimeSummary;
break;
case 'env':
populateEnvTable(payload);
envTable.populateTableJSON(payload);
break;
case 'http':
updateHttpData(payload);
break;
case 'httpURLs':
updateURLData(payload);
httpTop5.updateURLData(payload);
break;
case 'title' :
updateHeader(payload);
break;
case 'memoryPools':
updateMemPoolsData(payload);
summary.memoryPools = {usedHeapAfterGCAverage: received.payload.usedHeapAfterGCAverage,
usedHeapAfterGCMax: received.payload.usedHeapAfterGCMax,
usedNativeMax: received.payload.usedNativeMax
};
break;

}
let summaryData = [];
if( summary.cpu.processMean ) {
let value = new Number(summary.cpu.processMean);
let valueStr = value.toLocaleString([],{style: 'percent', minimumSignificantDigits: 4, maximumSignificantDigits: 4});
summaryData.push({Parameter: 'Average Process CPU', Value: valueStr});
}
if( summary.cpu.systemMean ) {
let value = new Number(summary.cpu.systemMean);
let valueStr = value.toLocaleString([],{style: 'percent', minimumSignificantDigits: 4, maximumSignificantDigits: 4});
summaryData.push({Parameter: 'Average System CPU', Value: valueStr});
}
if( summary.gc.time ) {
let value = new Number(summary.gc.time);
let valueStr = value.toLocaleString([],{style: 'percent', minimumSignificantDigits: 4, maximumSignificantDigits: 4});
summaryData.push({Parameter: 'Time Spent in GC', Value: `${valueStr}`});
}
if( summary.memoryPools.usedHeapAfterGCMax ) {
summaryData.push({Parameter: 'Max Heap Used After GC', Value: `${summary.memoryPools.usedHeapAfterGCMax} bytes`});
summaryData.push({Parameter: 'Max Native Heap Used', Value: `${summary.memoryPools.usedNativeMax} bytes`});
}
summaryTable.populateTable(summaryData);
}
</script>
<script>

let selected_tab = "dashboard-tab"

window.addEventListener('resize', resize);

// Also re-size when we change tabs in case we re-sized
// while the new tab wasn't visible.
$('.nav-tabs a').on('shown.bs.tab', function(event) {
selected_tab = event.target.id;
resize();
});

function resize() {
canvasWidth = $("#cpuDiv1").width() - 8,
httpCanvasWidth = $("#httpDiv1").width() - 8,
memPoolsCanvasWidth = $("#memPoolsDiv").width() - 8,
graphWidth = canvasWidth - margin.left - margin.right,
httpGraphWidth = httpCanvasWidth - margin.left - margin.right,
memPoolsGraphWidth = memPoolsCanvasWidth - margin.left - margin.right,
resizeCPUChart();
resizeHttpChart();
resizeHttpThroughputChart();
resizeHttpTop5Chart();
resizeGCChart();
resizeMemPoolsChart();
resizeEnvTable();
if (selected_tab == "dashboard-tab") {
canvasWidth = $("#cpuDiv1").width() - 8,
httpCanvasWidth = $("#httpDiv1").width() - 8,
memPoolsCanvasWidth = $("#memPoolsDiv").width() - 8,
graphWidth = canvasWidth - margin.left - margin.right,
httpGraphWidth = httpCanvasWidth - margin.left - margin.right,
memPoolsGraphWidth = memPoolsCanvasWidth - margin.left - margin.right,
resizeCPUChart();
resizeHttpChart();
resizeHttpThroughputChart();
resizeGCChart();
resizeMemPoolsChart();
} else if(selected_tab == "summary-tab") {
envTable.resizeTable();
summaryTable.resizeTable();
httpTop5.resizeTop5Chart();
}
}

</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,24 @@ public class DataProviderManager {
private static final String GC_TOPIC = "gc";
private static final String CPU_TOPIC = "cpu";
private static final String MEMORYPOOLS_TOPIC = "memoryPools";
private static final String ENV_TOPIC = "env";
private static final String ENV_TOPIC = "env";

private ScheduledExecutorService exec;

private static String escapeStringForJSON(String str) {
return str.replace("\\", "\\\\").replace("\"", "\\\"");
}

// So long as we get the CPU samples at a constant interval
// we can average them out. (Note: the total itself is
// not meaningful.)
private double totalSystemCPULoad = 0.0;
private double totalProcessCPULoad = 0.0;
private double cpuLoadSamples = 0.0;

private long usedHeapAfterGCMax = 0;
private long usedNativeMax = 0;

/**
* Create a JavametricsMBeanConnector
*/
Expand Down Expand Up @@ -75,32 +85,48 @@ private void emitEnvironmentData() {

private void emitGCData() {
long timeStamp = System.currentTimeMillis();
double gcTime = GCDataProvider.getGCCollectionTime();
if (gcTime >= 0) { // Don't send -1 'no data' values
double gcFraction = GCDataProvider.getLatestGCPercentage();
double gcFractionSummary = GCDataProvider.getTotalGCPercentage();

if (gcFraction >= 0) { // Don't send -1 'no data' values
StringBuilder message = new StringBuilder();
message.append("{\"time\":\"");
message.append(timeStamp);
message.append("\", \"gcTime\": \"");
message.append(gcTime);
message.append(gcFraction);
message.append("\", \"gcTimeSummary\": \"");
message.append(gcFractionSummary);
message.append("\"}");
Javametrics.getInstance().sendJSON(GC_TOPIC, message.toString());
}
}

private void emitCPUUsage() {
long timeStamp = System.currentTimeMillis();
double process = CPUDataProvider.getProcessCpuLoad();
double system = CPUDataProvider.getSystemCpuLoad();
if (system >= 0 && process >= 0) {
StringBuilder message = new StringBuilder();
message.append("{\"time\":\"");
message.append(timeStamp);
message.append("\", \"system\": \"");
message.append(system);
message.append("\", \"process\": \"");
message.append(process);
message.append("\"}");
Javametrics.getInstance().sendJSON(CPU_TOPIC, message.toString());
try{
long timeStamp = System.currentTimeMillis();
double process = CPUDataProvider.getProcessCpuLoad();
double system = CPUDataProvider.getSystemCpuLoad();
cpuLoadSamples++;
if (system >= 0 && process >= 0) {
totalProcessCPULoad += process;
totalSystemCPULoad += system;

StringBuilder message = new StringBuilder();
message.append("{\"time\":\"");
message.append(timeStamp);
message.append("\", \"system\": \"");
message.append(system);
message.append("\", \"process\": \"");
message.append(process);
message.append("\", \"processMean\": \"");
message.append(totalProcessCPULoad/cpuLoadSamples);
message.append("\", \"systemMean\": \"");
message.append(totalSystemCPULoad/cpuLoadSamples);
message.append("\"}");
Javametrics.getInstance().sendJSON(CPU_TOPIC, message.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}

Expand All @@ -110,17 +136,32 @@ private void emitMemoryPoolUsage() {
long usedNative = MemoryPoolDataProvider.getNativeMemory();
long usedHeap = MemoryPoolDataProvider.getHeapMemory();
if (usedHeapAfterGC >= 0) { // check that some data is available
String usedHeapAfterGCStr = Long.toString(usedHeapAfterGC, 10);
usedHeapAfterGCMax = Math.max(usedHeapAfterGCMax, usedHeapAfterGC);

String usedNativeStr = Long.toString(usedNative, 10);
usedNativeMax = Math.max(usedNativeMax, usedNative);

String usedHeapStr = Long.toString(usedHeap, 10);

StringBuilder message = new StringBuilder();
message.append("{\"time\":\"");
message.append(timeStamp);
message.append("\", \"usedHeapAfterGC\": \"");
message.append(usedHeapAfterGC);
message.append(usedHeapAfterGCStr);
message.append("\", \"usedHeap\": \"");
message.append(usedHeap);
message.append(usedHeapStr);
message.append("\", \"usedNative\": \"");
message.append(usedNative);
message.append(usedNativeStr);

// Used heap max is not actually that interesting, it ought to get to 100% just before a GC.
message.append("\", \"usedHeapAfterGCMax\": \"");
message.append(usedHeapAfterGCMax);
message.append("\", \"usedNativeMax\": \"");
message.append(usedNativeMax);
message.append("\"}");
Javametrics.getInstance().sendJSON(MEMORYPOOLS_TOPIC, message.toString());
}
}

}
Loading