[유치수] [NOBTS] change call stack table.

git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@1080 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
Chisu Yu
2013-01-03 09:30:51 +00:00
parent 880e714236
commit 0f7200e94e
7 changed files with 328 additions and 155 deletions
@@ -17,6 +17,7 @@ import com.nhn.hippo.web.calltree.span.SpanAlign;
import com.nhn.hippo.web.service.FlowChartService;
import com.nhn.hippo.web.service.SpanService;
import com.nhn.hippo.web.vo.TraceId;
import com.nhn.hippo.web.vo.callstacks.RecordSet;
/**
*
@@ -35,18 +36,25 @@ public class BusinessTransactionController {
@RequestMapping(value = "/selectTransaction", method = RequestMethod.GET)
public ModelAndView flow(@RequestParam(value = "traceId") String traceId) {
logger.debug("traceId:{}", traceId);
// select spans
List<SpanAlign> spanAligns = spanService.selectSpan(traceId);
ModelAndView mv = new ModelAndView("selectTransaction");
mv.addObject("spanList", spanAligns);
mv.addObject("traceId", traceId);
// Set<TraceId> traceIds = new HashSet<TraceId>(1);
// traceIds.add(new TraceId(UUID.fromString(traceId)));
// call tree
ServerCallTree callTree = flow.selectServerCallTree(new TraceId(UUID.fromString(traceId)));
mv.addObject("nodes", callTree.getNodes());
mv.addObject("links", callTree.getLinks());
// call stacks
RecordSet recordset = new RecordSet(spanAligns);
mv.addObject("callstack", recordset.getIterator());
mv.addObject("callstackStart", recordset.getStartTime());
mv.addObject("callstackEnd", recordset.getEndTime());
return mv;
}
}
@@ -7,6 +7,7 @@ import java.util.Date;
import java.util.List;
import java.util.UUID;
import com.profiler.common.AnnotationNames;
import com.profiler.common.ServiceType;
import com.profiler.common.bo.AnnotationBo;
import com.profiler.common.bo.Span;
@@ -15,10 +16,6 @@ public class AnnotationUtils {
private static final String FORMAT = "yyyy-MM-dd HH:mm:ss SSS";
private static final String API = "API";
private static final String ARCUS_COMMAND = "arcus.command";
private static final String HTTP_URL = "http.url";
@Deprecated
public static String longToDateStr(long date) {
SimpleDateFormat format = new SimpleDateFormat(FORMAT);
@@ -43,7 +40,7 @@ public class AnnotationUtils {
public static Object getDisplayMethod(Span span) {
List<AnnotationBo> list = span.getAnnotationBoList();
int index = Collections.binarySearch(list, API);
int index = Collections.binarySearch(list, AnnotationNames.API);
if (index > -1) {
return list.get(index).getValue();
@@ -60,15 +57,19 @@ public class AnnotationUtils {
List<AnnotationBo> list = span.getAnnotationBoList();
int index = -1;
if (span.getServiceType() == ServiceType.ARCUS || span.getServiceType() == ServiceType.MEMCACHED) {
index = Collections.binarySearch(list, ARCUS_COMMAND);
index = Collections.binarySearch(list, AnnotationNames.ARCUS_COMMAND);
}
if (span.getServiceType() == ServiceType.HTTP_CLIENT) {
index = Collections.binarySearch(list, HTTP_URL);
index = Collections.binarySearch(list, AnnotationNames.HTTP_URL);
}
if (span.getServiceType() == ServiceType.TOMCAT) {
index = Collections.binarySearch(list, HTTP_URL);
index = Collections.binarySearch(list, AnnotationNames.HTTP_URL);
}
if (span.getServiceType() == ServiceType.MYSQL) {
index = Collections.binarySearch(list, AnnotationNames.ARGS0);
}
if (index > -1) {
@@ -0,0 +1,68 @@
package com.nhn.hippo.web.vo.callstacks;
/**
* each stack
*
* @author netspider
*
*/
public class Record {
private final int tab;
private final boolean method;
private final String title;
private final String arguments;
private final long begin;
private final long elapsed;
private final String agent;
private final String service;
public Record(int tab, boolean method, String title, String arguments, long begin, long elapsed, String agent, String service) {
this.tab = tab;
this.method = method;
this.title = title;
this.arguments = arguments;
this.begin = begin;
this.elapsed = elapsed;
this.agent = agent;
this.service = service;
}
public int getTab() {
return tab;
}
public boolean isMethod() {
return method;
}
public String getTitle() {
return title;
}
public String getArguments() {
return arguments;
}
public long getBegin() {
return begin;
}
public long getElapsed() {
return elapsed;
}
public String getAgent() {
return agent;
}
public String getService() {
return service;
}
@Override
public String toString() {
return "Record [tab=" + tab + ", method=" + method + ", title=" + title + ", arguments=" + arguments + ", begin=" + begin + ", elapsed=" + elapsed + ", agent=" + agent + ", service=" + service + "]";
}
}
@@ -0,0 +1,114 @@
package com.nhn.hippo.web.vo.callstacks;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.nhn.hippo.web.calltree.span.SpanAlign;
import com.nhn.hippo.web.utils.AnnotationUtils;
import com.profiler.common.AnnotationNames;
import com.profiler.common.bo.AnnotationBo;
import com.profiler.common.bo.SpanBo;
import com.profiler.common.bo.SubSpanBo;
/**
*
* @author netspider
*
*/
public class RecordSet {
private long startTime = -1;
private long endTime = -1;
private final List<Record> recordset;
public RecordSet(List<SpanAlign> spanAligns) {
recordset = new ArrayList<Record>();
addSpanRecord(spanAligns);
}
public Iterator<Record> getIterator() {
return recordset.iterator();
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getEndTime() {
return endTime;
}
public void setEndTime(long endTime) {
this.endTime = endTime;
}
public boolean isStartTimeSet() {
return startTime != -1;
}
public boolean isEndTimeSet() {
return endTime != -1;
}
private void addAnnotationRecord(int depth, List<AnnotationBo> annotationBoList) {
for (AnnotationBo ann : annotationBoList) {
String annKey = ann.getKey();
if (AnnotationNames.API.equals(annKey) || AnnotationNames.API_ID.equals(annKey))
continue;
if (AnnotationNames.EXCEPTION.equals(annKey)) {
recordset.add(new Record(depth, false, ann.getValue().toString(), null, 0L, 0L, null, null));
} else if (AnnotationNames.BINDVALUE.equals(annKey)) {
recordset.add(new Record(depth, false, ann.getKey(), ann.getValue().toString(), 0L, 0L, null, null));
} else if (AnnotationNames.PREPAREDSTATEMENT.equals(annKey)) {
recordset.add(new Record(depth, false, ann.getKey(), ann.getValue().toString(), 0L, 0L, null, null));
}
}
}
private void addSpanRecord(List<SpanAlign> spanAligns) {
boolean marked = false;
for (SpanAlign sa : spanAligns) {
if (sa.isRoot()) {
SpanBo span = sa.getSpan();
AnnotationUtils.sortAnnotationListByKey(span);
String method = (String) AnnotationUtils.getDisplayMethod(span);
String arguments = (String) AnnotationUtils.getDisplayArgument(span);
long begin = span.getStartTime();
long elapsed = span.getElapsed();
if (!marked) {
setStartTime(begin);
setEndTime(begin + elapsed);
}
recordset.add(new Record(sa.getDepth(), true, method, arguments, begin, elapsed, span.getAgentId(), span.getServiceName()));
addAnnotationRecord(sa.getDepth() + 1, span.getAnnotationBoList());
} else {
SubSpanBo subSpan = sa.getSubSpanBo();
AnnotationUtils.sortAnnotationListByKey(subSpan);
String method = (String) AnnotationUtils.getDisplayMethod(subSpan);
Object arguments = AnnotationUtils.getDisplayArgument(subSpan);
long begin = sa.getSpan().getStartTime() + subSpan.getStartElapsed();
long elapsed = subSpan.getEndElapsed();
if (!marked) {
setStartTime(begin);
setEndTime(begin + elapsed);
}
recordset.add(new Record(sa.getDepth(), true, method, (arguments != null) ? arguments.toString() : "", begin, elapsed, subSpan.getAgentId(), subSpan.getServiceName()));
addAnnotationRecord(sa.getDepth() + 1, subSpan.getAnnotationBoList());
}
}
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
#hbase.client.host=localhost
hbase.client.host=localhost
#hbase.client.host=10.101.17.108
#dev-hippo002.ncl
@@ -6,7 +6,7 @@
#3대 짜리
#hbase.client.host=10.25.131.38
hbase.client.host=dev-hippo002.ncl
#hbase.client.host=dev-hippo002.ncl
hbase.client.port=2181
hbase.htable.threads.max=128
@@ -42,8 +42,14 @@
}
</script>
<style type="text/css">
#callStacks TH {
padding: 3px;
font-size:12px;
}
#callStacks TD {
padding: 3px;
font-size:12px;
}
#callStacks .method {
@@ -103,16 +109,17 @@
<ul class="nav nav-tabs" id="traceTabs">
<li><a href="#CallStacks" data-toggle="tab">Call Stacks</a></li>
<li><a href="#Timeline" data-toggle="tab">Timeline</a></li>
<li><a href="#Details" data-toggle="tab">Details (for HIPPO developer)</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="CallStacks" style="overflow:hidden;">
<!-- begin call stack -->
<!-- begin new call stack -->
<table id="callStacks" class="table table-bordered">
<thead>
<tr>
<th>Method</th>
<th>Arguments</th>
<th>Argument</th>
<th>Time[%]</th>
<th>Time[ms]</th>
<th>Agent</th>
@@ -120,79 +127,43 @@
</tr>
</thead>
<tbody>
<c:set var="startTime" scope="page" value="0"/>
<c:set var="endTime" scope="page" value="0"/>
<c:forEach items="${spanList}" var="span" varStatus="status">
<c:set var="startTime" scope="page" value="${callstackStart}"/>
<c:set var="endTime" scope="page" value="${callstackEnd}"/>
<c:forEach items="${callstack}" var="record" varStatus="status">
<c:set var="depth" scope="page" value="${span.depth}"/>
<c:if test="${span.root}">
<c:set var="sp" scope="page" value="${span.span}"/>
<c:set var="begin" scope="page" value="${sp.startTime}"/>
<c:set var="end" scope="page" value="${sp.startTime + sp.elapsed}"/>
<c:if test="${status.first}">
<c:set var="startTime" scope="page" value="${sp.startTime}"/>
</c:if>
<c:if test="${status.first}">
<c:set var="endTime" scope="page" value="${sp.startTime + sp.elapsed}"/>
</c:if>
<tr>
<td class="method" onmouseover="showDetail(${status.count})" onmouseout="hideDetail(${status.count})">
<c:forEach begin="0" end="${depth}">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</c:forEach>
${hippo:sortAnnotationListByKey(sp)}
${hippo:getDisplayMethod(sp)}
</td>
<!-- method -->
<td class="arguments">
${hippo:getDisplayArgument(sp)}
</td>
<!-- arguments -->
<td class="bar">
<c:if test="${status.first}">
<c:set var="barRatio" scope="page" value="${100 / (end - begin)}"/>
</c:if>
<div style="width:<fmt:formatNumber value="${((end - begin) * barRatio) + 0.9}" type="number" pattern="#"/>px; background-color:#69B2E9;">
&nbsp;</div>
</td>
<td class="time"><fmt:formatNumber type="number" value="${end - begin}"/></td>
<!-- exec -->
<td class="agent">${sp.agentId}</td>
<!-- agent -->
<td class="service">${sp.serviceName}</td>
<!-- service -->
</tr>
</c:if>
<c:if test="${!span.root}">
<c:set var="subSp" scope="page" value="${span.subSpanBo}"/>
<c:set var="begin" scope="page" value="${span.span.startTime + subSp.startElapsed}"/>
<c:set var="end" scope="page" value="${span.span.startTime + subSp.startElapsed + subSp.endElapsed}"/>
<tr>
<td class="method" onmouseover="showDetail(${status.count})" onmouseout="hideDetail(${status.count})">
<c:forEach begin="0" end="${depth + 1}">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</c:forEach>
${hippo:sortAnnotationListByKey(subSp)}
${hippo:getDisplayMethod(subSp)}
</td>
<!-- method -->
<td class="arguments">
${hippo:getDisplayArgument(subSp)}
</td>
<!-- arguments -->
<td class="bar">
<div style="width:<fmt:formatNumber value="${((end - begin) * barRatio) + 0.9}" type="number" pattern="#"/>px; background-color:#69B2E9;">
&nbsp;</div>
</td>
<td class="time"><fmt:formatNumber type="number" value="${end - begin}"/></td>
<!-- exec -->
<td class="agent">${subSp.agentId}</td>
<!-- agent -->
<td class="agent">${subSp.serviceName}</td>
<!-- service -->
</tr>
</c:if>
<c:set var="begin" scope="page" value="${record.begin}"/>
<c:set var="end" scope="page" value="${record.begin + record.elapsed}"/>
<c:if test="${status.first}">
<c:set var="barRatio" scope="page" value="${100 / (end - begin)}"/>
</c:if>
<tr>
<td class="method">
<c:forEach begin="0" end="${record.tab}">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</c:forEach>
<c:if test="${record.method}"><i class="icon-tag"></i></c:if>
<c:if test="${not record.method}"><i class="icon-info-sign"></i></c:if>
${record.title}
</td>
<td class="arguments">${record.arguments}</td>
<td class="bar">
<c:if test="${record.method}">
<div style="width:<fmt:formatNumber value="${((end - begin) * barRatio) + 0.9}" type="number" pattern="#"/>px; background-color:#69B2E9;">&nbsp;</div>
</c:if>
</td>
<td class="time">
<c:if test="${record.method}">
<fmt:formatNumber type="number" value="${record.elapsed}"/>
</c:if>
</td>
<td class="agent">${record.agent}</td>
<td class="service">${record.service}</td>
</tr>
</c:forEach>
</tbody>
</table>
<!-- end of call stack -->
<!-- end of new call stack -->
</div>
<div class="tab-pane" id="Timeline">
<!-- begin of timeline -->
@@ -279,74 +250,74 @@
</div>
<!-- end of timeline -->
</div>
<div class="tab-pane" id="Details">
<!-- begin details -->
<table id="businessTransactions" class="table table-bordered" style="font-size:12px;">
<thead>
<tr>
<th>#</th>
<th>Action</th>
<th>Arguments</th>
<th>EndPoint</th>
<th>Total[ms]</th>
<th>Application</th>
<th>Agent</th>
</tr>
</thead>
<tbody>
<c:forEach items="${spanList}" var="span" varStatus="status">
<c:if test="${span.root}">
<c:set var="sp" scope="page" value="${span.span}"/>
<c:forEach items="${sp.annotationBoList}" var="ano" varStatus="annoStatus">
<tr>
<td>${span.depth}</td>
<td>${ano.key}</td>
<td>${ano.value}</td>
<td><c:if test="${annoStatus.first}">${sp.endPoint}</c:if></td>
<td><c:if test="${annoStatus.first}">${sp.elapsed}</c:if></td>
<td></td>
<td><c:if test="${annoStatus.first}">${sp.serviceName}</c:if></td>
</tr>
</c:forEach>
<tr>
<td colspan="7">&nbsp;</td>
</tr>
</c:if>
<c:if test="${!span.root}">
<c:set var="subSp" scope="page" value="${span.subSpanBo}"/>
<c:forEach items="${subSp.annotationBoList}" var="ano" varStatus="annoStatus">
<tr>
<td>${span.depth}</td>
<td>${ano.key}</td>
<td>${ano.value}</td>
<td><c:if test="${annoStatus.first}">${subSp.endPoint}</c:if></td>
<td><c:if test="${annoStatus.first}">${subSp.endElapsed}</c:if></td>
<td><c:if test="${annoStatus.first}">${subSp.serviceName}</c:if></td>
</tr>
</c:forEach>
<tr>
<td colspan="7">&nbsp;</td>
</tr>
</c:if>
</c:forEach>
</tbody>
</table>
<!-- end of details -->
</div>
</div>
</div>
</div>
<hr/>
<div class="row">
<div class="span12"><br/><br/><br/>Application Details</div>
</div>
<div class="row">
<div class="span12">
<table id="businessTransactions" class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>Action</th>
<th>Arguments</th>
<th>EndPoint</th>
<th>Total[ms]</th>
<th>Exec[ms]</th>
<th>Application</th>
<th>Agent</th>
</tr>
</thead>
<tbody>
<c:forEach items="${spanList}" var="span" varStatus="status">
<c:if test="${span.root}">
<c:set var="sp" scope="page" value="${span.span}"/>
<c:forEach items="${sp.annotationBoList}" var="ano" varStatus="annoStatus">
<tr>
<td>${span.depth}</td>
<td>${ano.key}</td>
<td>${ano.value}</td>
<td><c:if test="${annoStatus.first}">${sp.endPoint}</c:if></td>
<td><c:if test="${annoStatus.first}">${sp.elapsed}</c:if></td>
<td></td>
<td><c:if test="${annoStatus.first}">${sp.serviceName}</c:if></td>
</tr>
</c:forEach>
<tr>
<td colspan="7">&nbsp;</td>
</tr>
</c:if>
<c:if test="${!span.root}">
<c:set var="subSp" scope="page" value="${span.subSpanBo}"/>
<c:forEach items="${subSp.annotationBoList}" var="ano" varStatus="annoStatus">
<tr>
<td>${span.depth}</td>
<td>${ano.key}</td>
<td>${ano.value}</td>
<td><c:if test="${annoStatus.first}">${subSp.endPoint}</c:if></td>
<td><c:if test="${annoStatus.first}">${subSp.endElapsed}</c:if></td>
<td></td>
<td><c:if test="${annoStatus.first}">${subSp.serviceName}</c:if></td>
</tr>
</c:forEach>
<tr>
<td colspan="7">&nbsp;</td>
</tr>
</c:if>
</c:forEach>
</tbody>
</table>
</div>
</div>
</div>
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<script type="text/javascript">
var data = {
+18 -7
View File
@@ -134,6 +134,8 @@
</li>
</ul>
</div>
<button id="btnTraceServerNow" class="btn btn-info" onclick="return false;">Now</button>
</form>
<div class="row">
@@ -346,13 +348,7 @@ $(document).ready(function () {
$("#starttime").val(date.getHours() + ":" + ((min < 10) ? ("0" + min) : min));
}
setQueryTimeRange(30);
$("#application").select2({
placeholder: "Select an application.",
});
$("#btnTraceServer").click(function(e) {
function query() {
if($("#application").val() == "") {
alert("\n\nSelect an application, please.\n\n");
return true;
@@ -388,6 +384,21 @@ $(document).ready(function () {
hideIndicator();
});
}
setQueryTimeRange(30);
$("#application").select2({
placeholder: "Select an application.",
});
$("#btnTraceServerNow").click(function(e) {
setQueryTimeRange(30);
query();
});
$("#btnTraceServer").click(function(e) {
query();
});
$("#btnTrace .dropdown-menu").on("click", function(e){