From df0eac5118f7b45eea665dca0e66c07caa8fb63d Mon Sep 17 00:00:00 2001 From: Chisu Yu Date: Thu, 29 Nov 2012 08:59:10 +0000 Subject: [PATCH] =?UTF-8?q?[=EC=9C=A0=EC=B9=98=EC=88=98]=20[NOBTS]=20add?= =?UTF-8?q?=20terminal=20span?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@947 84d0f5b1-2673-498c-a247-62c4ff18d310 --- .../nhn/hippo/web/calltree/server/Server.java | 8 + .../web/calltree/server/ServerCallTree.java | 218 +++++++----- .../BusinessTransactionController.java | 13 +- .../web/controller/FlowChartController.java | 6 +- .../hippo/web/dao/TerminalStatisticsDao.java | 14 + .../java/com/nhn/hippo/web/dao/TraceDao.java | 4 +- .../dao/hbase/HbaseTerminalStatisticsDao.java | 54 +++ .../hippo/web/dao/hbase/HbaseTraceDao.java | 11 + .../com/nhn/hippo/web/mapper/SpanMapper.java | 3 +- .../mapper/TerminalRequestCountMapper.java | 40 +++ .../hippo/web/service/FlowChartService.java | 16 +- .../web/service/FlowChartServiceImpl.java | 327 +++++++++++------- .../hippo/web/service/SpanServiceImpl.java | 117 ++++--- .../com/nhn/hippo/web/vo/TerminalRequest.java | 74 ++++ src/main/resources/root-context.xml | 1 + src/main/webapp/WEB-INF/views/flowserver.jsp | 16 +- .../WEB-INF/views/selectTransaction.jsp | 22 -- 17 files changed, 620 insertions(+), 324 deletions(-) create mode 100644 src/main/java/com/nhn/hippo/web/dao/TerminalStatisticsDao.java create mode 100644 src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTerminalStatisticsDao.java create mode 100644 src/main/java/com/nhn/hippo/web/mapper/TerminalRequestCountMapper.java create mode 100644 src/main/java/com/nhn/hippo/web/vo/TerminalRequest.java diff --git a/src/main/java/com/nhn/hippo/web/calltree/server/Server.java b/src/main/java/com/nhn/hippo/web/calltree/server/Server.java index b5a2872df..b12c3b123 100644 --- a/src/main/java/com/nhn/hippo/web/calltree/server/Server.java +++ b/src/main/java/com/nhn/hippo/web/calltree/server/Server.java @@ -3,6 +3,7 @@ package com.nhn.hippo.web.calltree.server; import java.util.HashSet; import java.util.Set; +import com.nhn.hippo.web.vo.TerminalRequest; import com.profiler.common.ServiceType; import com.profiler.common.bo.SpanBo; @@ -34,6 +35,13 @@ public class Server implements Comparable { this.serviceType = span.getServiceType(); } + public Server(String id, String applicationName, String endPoint, ServiceType serviceType) { + this.id = id; + this.applicationName = applicationName; + this.endPoint = endPoint; + this.serviceType = serviceType; + } + public String getId() { return this.id; } diff --git a/src/main/java/com/nhn/hippo/web/calltree/server/ServerCallTree.java b/src/main/java/com/nhn/hippo/web/calltree/server/ServerCallTree.java index bc60d8ae6..fdf6fe01c 100644 --- a/src/main/java/com/nhn/hippo/web/calltree/server/ServerCallTree.java +++ b/src/main/java/com/nhn/hippo/web/calltree/server/ServerCallTree.java @@ -3,49 +3,69 @@ package com.nhn.hippo.web.calltree.server; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; -import com.nhn.hippo.web.vo.BusinessTransactions; -import com.profiler.common.bo.SpanBo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.nhn.hippo.web.vo.BusinessTransactions; +import com.nhn.hippo.web.vo.TerminalRequest; +import com.profiler.common.ServiceType; +import com.profiler.common.bo.SpanBo; + /** * Call Tree - * + * * @author netspider */ public class ServerCallTree { - private Logger logger = LoggerFactory.getLogger(this.getClass()); + private Logger logger = LoggerFactory.getLogger(this.getClass()); - private final String PREFIX_CLIENT = "CLIENT:"; + private final String PREFIX_CLIENT = "CLIENT:"; - private final Map servers = new HashMap(); - private final Map spanIdToServerId = new HashMap(); - private final Map ServerRequests = new HashMap(); - private final List spans = new ArrayList(); - private final BusinessTransactions businessTransactions = new BusinessTransactions(); + private final Map servers = new HashMap(); + private final Map spanIdToServerId = new HashMap(); + private final Map serverRequests = new HashMap(); + private final List spans = new ArrayList(); + private final BusinessTransactions businessTransactions = new BusinessTransactions(); - private boolean isBuilt = false; + private boolean isBuilt = false; + + private final Set terminalRequests = new HashSet(); + + public void addTerminal(TerminalRequest terminal) { + terminalRequests.add(terminal); + +// Server server = new Server(terminal.getTo(), terminal.getTo(), "UNKNOWN", ServiceType.parse(terminal.getToServiceType())); +// servers.put(server.getId(), server); +// +// Server from = new Server(terminal.getFrom(), terminal.getFrom(), "UNKNOWN", ServiceType.UNKNOWN); +// +// ServerRequest request = new ServerRequest(from, server); +// serverRequests.put(request.getId(), request); + } - public void addSpan(SpanBo span) { - /** - * make Servers - */ - // TODO: 여기에서 이러지말고 수집할 때 처음부터 table에 저장해둘 수 있나?? - Server server = new Server(span); + public void addSpan(SpanBo span) { + /** + * make Servers + */ + // TODO: 여기에서 이러지말고 수집할 때 처음부터 table에 저장해둘 수 있나?? + Server server = new Server(span); - if (server.getId() == null) { - return; - } - - // TODO: remove this later. -// if (server.getId().contains("mysql:jdbc:") || server.getId().contains("favicon")) { -// return; -// } + if (server.getId() == null) { + return; + } + + // TODO: remove this later. + // if (server.getId().contains("mysql:jdbc:") || + // server.getId().contains("favicon")) { + // return; + // } if (!servers.containsKey(server.getId())) { servers.put(server.getId(), server); @@ -54,86 +74,102 @@ public class ServerCallTree { } spanIdToServerId.put(String.valueOf(span.getSpanId()), server.getId()); - // TODO: remove client node -// if (span.getParentSpanId() == -1) { -// Server client = new Server(PREFIX_CLIENT + span.getAgentID(), span.getEndPoint(), false); -// servers.put(client.getId(), client); -// spanIdToServerId.put(PREFIX_CLIENT + span.getSpanID(), client.getId()); -// } + // TODO: remove client node + // if (span.getParentSpanId() == -1) { + // Server client = new Server(PREFIX_CLIENT + span.getAgentID(), + // span.getEndPoint(), false); + // servers.put(client.getId(), client); + // spanIdToServerId.put(PREFIX_CLIENT + span.getSpanID(), + // client.getId()); + // } - /** - * Preparing makes link (ServerRequests) - */ - if (span.getParentSpanId() == -1) { - businessTransactions.add(span); - } else { - spans.add(span); - } - } + /** + * Preparing makes link (ServerRequests) + */ + if (span.getParentSpanId() == -1) { + businessTransactions.add(span); + } else { + spans.add(span); + } + } - public ServerCallTree build() { - if (isBuilt) - return this; + public ServerCallTree build() { + if (isBuilt) + return this; - int i = 0; - for (Entry entry : servers.entrySet()) { - entry.getValue().setSequence(i++); - } + // add terminal servers + for (TerminalRequest terminal : terminalRequests) { + Server server = new Server(terminal.getTo(), terminal.getTo(), "UNKNOWN", ServiceType.parse(terminal.getToServiceType())); + servers.put(server.getId(), server); + } + + // mark server index + int i = 0; + for (Entry entry : servers.entrySet()) { + entry.getValue().setSequence(i++); + } - for (SpanBo span : spans) { - String from = String.valueOf(span.getParentSpanId()); - String to = String.valueOf(span.getSpanId()); + // add terminal requests + for (TerminalRequest terminal : terminalRequests) { + ServerRequest request = new ServerRequest(servers.get(terminal.getFrom()), servers.get(terminal.getTo())); + serverRequests.put(request.getId(), request); + } + + // add non-terminal requests + for (SpanBo span : spans) { + String from = String.valueOf(span.getParentSpanId()); + String to = String.valueOf(span.getSpanId()); - Server fromServer = servers.get(spanIdToServerId.get(from)); - Server toServer = servers.get(spanIdToServerId.get(to)); + Server fromServer = servers.get(spanIdToServerId.get(from)); + Server toServer = servers.get(spanIdToServerId.get(to)); - if (fromServer == null) { - fromServer = servers.get(spanIdToServerId.get(PREFIX_CLIENT + to)); - } + if (fromServer == null) { + fromServer = servers.get(spanIdToServerId.get(PREFIX_CLIENT + to)); + } - // TODO 없는 url에 대한 호출이 고려되어야 함. 일단 임시로 회피. - if (fromServer == null) { - logger.debug("invalid form server {}", from); - continue; - } - ServerRequest serverRequest = new ServerRequest(fromServer, toServer); + // TODO 없는 url에 대한 호출이 고려되어야 함. 일단 임시로 회피. + if (fromServer == null) { + logger.debug("invalid form server {}", from); + continue; + } + ServerRequest serverRequest = new ServerRequest(fromServer, toServer); - // TODO: local call인 경우 보여주지 않음. - if (serverRequest.isSelfCalled()) { - continue; - } + // TODO: local call인 경우 보여주지 않음. + if (serverRequest.isSelfCalled()) { + continue; + } - if (ServerRequests.containsKey(serverRequest.getId())) { - ServerRequests.get(serverRequest.getId()).addRequest(span.getElapsed()); - } else { - ServerRequests.put(serverRequest.getId(), serverRequest); - } - } + if (serverRequests.containsKey(serverRequest.getId())) { + serverRequests.get(serverRequest.getId()).addRequest(span.getElapsed()); + } else { + serverRequests.put(serverRequest.getId(), serverRequest); + } + } - isBuilt = true; - return this; - } + isBuilt = true; + return this; + } - public Collection getNodes() { - return this.servers.values(); - } + public Collection getNodes() { + return this.servers.values(); + } - public Collection getLinks() { - return this.ServerRequests.values(); - } + public Collection getLinks() { + return this.serverRequests.values(); + } - public BusinessTransactions getBusinessTransactions() { - return businessTransactions; - } + public BusinessTransactions getBusinessTransactions() { + return businessTransactions; + } - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); - sb.append("Server=").append(servers); - sb.append("\n"); - sb.append("ServerRequest=").append(ServerRequests.values()); + sb.append("Server=").append(servers); + sb.append("\n"); + sb.append("ServerRequest=").append(serverRequests.values()); - return sb.toString(); - } + return sb.toString(); + } } diff --git a/src/main/java/com/nhn/hippo/web/controller/BusinessTransactionController.java b/src/main/java/com/nhn/hippo/web/controller/BusinessTransactionController.java index df55f5c76..689bc565b 100644 --- a/src/main/java/com/nhn/hippo/web/controller/BusinessTransactionController.java +++ b/src/main/java/com/nhn/hippo/web/controller/BusinessTransactionController.java @@ -1,8 +1,6 @@ package com.nhn.hippo.web.controller; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.UUID; import org.slf4j.Logger; @@ -14,7 +12,6 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; -import com.nhn.hippo.web.calltree.rpc.RPCCallTree; import com.nhn.hippo.web.calltree.server.ServerCallTree; import com.nhn.hippo.web.calltree.span.SpanAlign; import com.nhn.hippo.web.service.FlowChartService; @@ -44,15 +41,11 @@ public class BusinessTransactionController { mv.addObject("spanList", spanAligns); mv.addObject("traceId", traceId); - Set traceIds = new HashSet(1); - traceIds.add(new TraceId(UUID.fromString(traceId))); - ServerCallTree callTree = flow.selectServerCallTree(traceIds); +// Set traceIds = new HashSet(1); +// traceIds.add(new TraceId(UUID.fromString(traceId))); + ServerCallTree callTree = flow.selectServerCallTree(new TraceId(UUID.fromString(traceId))); mv.addObject("nodes", callTree.getNodes()); mv.addObject("links", callTree.getLinks()); - - RPCCallTree rpcTree = flow.selectRPCCallTree(traceIds); - mv.addObject("rpcnodes", rpcTree.getNodes()); - mv.addObject("rpclinks", rpcTree.getLinks()); return mv; } diff --git a/src/main/java/com/nhn/hippo/web/controller/FlowChartController.java b/src/main/java/com/nhn/hippo/web/controller/FlowChartController.java index c627b1967..212a06e06 100644 --- a/src/main/java/com/nhn/hippo/web/controller/FlowChartController.java +++ b/src/main/java/com/nhn/hippo/web/controller/FlowChartController.java @@ -53,13 +53,13 @@ public class FlowChartController { Set traceIds = flow.selectTraceIdsFromApplicationTraceIndex(applicationName, from, to); watch.stop(); - logger.info("time:{} {}", watch.getLastTaskTimeMillis(), traceIds.size()); + logger.info("Fetch traceIds elapsed : {}ms, {} traces", watch.getLastTaskTimeMillis(), traceIds.size()); watch.start("selectServerCallTree"); - ServerCallTree callTree = flow.selectServerCallTree(traceIds); + ServerCallTree callTree = flow.selectServerCallTree(traceIds, applicationName, from, to); watch.stop(); - logger.info("time:{}", watch.getLastTaskTimeMillis()); + logger.info("Fetch calltree time : {}ms", watch.getLastTaskTimeMillis()); model.addAttribute("nodes", callTree.getNodes()); model.addAttribute("links", callTree.getLinks()); diff --git a/src/main/java/com/nhn/hippo/web/dao/TerminalStatisticsDao.java b/src/main/java/com/nhn/hippo/web/dao/TerminalStatisticsDao.java new file mode 100644 index 000000000..bdee06034 --- /dev/null +++ b/src/main/java/com/nhn/hippo/web/dao/TerminalStatisticsDao.java @@ -0,0 +1,14 @@ +package com.nhn.hippo.web.dao; + +import java.util.List; + +import com.nhn.hippo.web.vo.TerminalRequest; + +/** + * + * @author netspider + * + */ +public interface TerminalStatisticsDao { + public List> selectTerminal(String applicationName, long from, long to); +} diff --git a/src/main/java/com/nhn/hippo/web/dao/TraceDao.java b/src/main/java/com/nhn/hippo/web/dao/TraceDao.java index be981e501..96c4af126 100644 --- a/src/main/java/com/nhn/hippo/web/dao/TraceDao.java +++ b/src/main/java/com/nhn/hippo/web/dao/TraceDao.java @@ -18,11 +18,13 @@ public interface TraceDao { List selectSpanAndAnnotation(UUID traceId); List selectSpan(long traceIdMost, long traceIdLeast); - + List> selectSpans(List traceIds); List> selectSpans(Set traceIds); + List selectSpans(TraceId traceId); + @Deprecated List> selectSpansAndAnnotation(Set traceIds); } diff --git a/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTerminalStatisticsDao.java b/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTerminalStatisticsDao.java new file mode 100644 index 000000000..ec006f513 --- /dev/null +++ b/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTerminalStatisticsDao.java @@ -0,0 +1,54 @@ +package com.nhn.hippo.web.dao.hbase; + +import java.util.List; + +import org.apache.hadoop.hbase.client.Scan; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.hadoop.hbase.RowMapper; +import org.springframework.stereotype.Repository; + +import com.nhn.hippo.web.dao.TerminalStatisticsDao; +import com.nhn.hippo.web.vo.TerminalRequest; +import com.profiler.common.hbase.HBaseTables; +import com.profiler.common.hbase.HbaseOperations2; +import com.profiler.common.util.TerminalSpanUtils; +import com.profiler.common.util.TimeSlot; + +/** + * + * @author netspider + * + */ +@Repository +public class HbaseTerminalStatisticsDao implements TerminalStatisticsDao { + + private int scanCacheSize = 40; + + @Autowired + private HbaseOperations2 hbaseOperations2; + + @Autowired + @Qualifier("terminalRequestCountMapper") + private RowMapper> terminalRequestCountMapper; + + @Override + public List> selectTerminal(String applicationName, long from, long to) { + Scan scan = createScan(applicationName, from, to); + return hbaseOperations2.find(HBaseTables.TERMINAL_STATISTICS, scan, terminalRequestCountMapper); + } + + private Scan createScan(String applicationName, long from, long to) { + byte[] startKey = TerminalSpanUtils.makeRowKey(applicationName, TimeSlot.getSlot(from)); + byte[] endKey = TerminalSpanUtils.makeRowKey(applicationName, TimeSlot.getSlot(to)); + + Scan scan = new Scan(); + scan.setCaching(this.scanCacheSize); + scan.setStartRow(startKey); + scan.setStopRow(endKey); + scan.addFamily(HBaseTables.TERMINAL_STATISTICS_CF_COUNTER); + scan.setId("terminalStatisticsScan"); + + return scan; + } +} diff --git a/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTraceDao.java b/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTraceDao.java index b4608dacc..22a3e3256 100644 --- a/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTraceDao.java +++ b/src/main/java/com/nhn/hippo/web/dao/hbase/HbaseTraceDao.java @@ -27,6 +27,8 @@ import com.profiler.common.util.BytesUtils; public class HbaseTraceDao implements TraceDao { private final byte[] COLFAM_SPAN = HBaseTables.TRACES_CF_SPAN; + + private final byte[] COLFAM_TERMINALSPAN = HBaseTables.TRACES_CF_TERMINALSPAN; private final byte[] COLFAM_ANNOTATION = HBaseTables.TRACES_CF_ANNOTATION; @@ -54,6 +56,7 @@ public class HbaseTraceDao implements TraceDao { Get get = new Get(uuidBytes); get.addFamily(COLFAM_SPAN); get.addFamily(COLFAM_ANNOTATION); + get.addFamily(COLFAM_TERMINALSPAN); return template2.get(HBaseTables.TRACES, get, spanAnnotationMapper); } @@ -85,6 +88,14 @@ public class HbaseTraceDao implements TraceDao { } return template2.get(HBaseTables.TRACES, gets, spanMapper); } + + @Override + public List selectSpans(TraceId traceId) { + Get get = new Get(traceId.getBytes()); + get.addFamily(COLFAM_SPAN); + get.addFamily(COLFAM_TERMINALSPAN); + return template2.get(HBaseTables.TRACES, get, spanMapper); + } public List> selectSpansAndAnnotation(Set traceIds) { List gets = new ArrayList(traceIds.size()); diff --git a/src/main/java/com/nhn/hippo/web/mapper/SpanMapper.java b/src/main/java/com/nhn/hippo/web/mapper/SpanMapper.java index 3b9630c00..59916fd31 100644 --- a/src/main/java/com/nhn/hippo/web/mapper/SpanMapper.java +++ b/src/main/java/com/nhn/hippo/web/mapper/SpanMapper.java @@ -51,7 +51,8 @@ public class SpanMapper implements RowMapper> { List spanList = new ArrayList(); for (KeyValue kv : keyList) { // family name "span"일때로만 한정. - if (kv.getFamilyLength() == HBaseTables.TRACES_CF_SPAN.length) { + if (kv.getFamilyLength() == HBaseTables.TRACES_CF_SPAN.length || + kv.getFamilyLength() == HBaseTables.TRACES_CF_TERMINALSPAN.length) { SpanBo spanBo = new SpanBo(); spanBo.setMostTraceId(most); spanBo.setLeastTraceId(least); diff --git a/src/main/java/com/nhn/hippo/web/mapper/TerminalRequestCountMapper.java b/src/main/java/com/nhn/hippo/web/mapper/TerminalRequestCountMapper.java new file mode 100644 index 000000000..aa04e5162 --- /dev/null +++ b/src/main/java/com/nhn/hippo/web/mapper/TerminalRequestCountMapper.java @@ -0,0 +1,40 @@ +package com.nhn.hippo.web.mapper; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.client.Result; +import org.apache.hadoop.hbase.util.Bytes; +import org.springframework.data.hadoop.hbase.RowMapper; +import org.springframework.stereotype.Component; + +import com.nhn.hippo.web.vo.TerminalRequest; +import com.profiler.common.hbase.HBaseTables; +import com.profiler.common.util.TerminalSpanUtils; + +/** + * + */ +@Component +public class TerminalRequestCountMapper implements RowMapper> { + + @Override + public List mapRow(Result result, int rowNum) throws Exception { + KeyValue[] keyList = result.raw(); + + List requestList = new ArrayList(); + for (KeyValue kv : keyList) { + if (kv.getFamilyLength() == HBaseTables.TERMINAL_STATISTICS_CF_COUNTER.length) { + String from = TerminalSpanUtils.getApplicationNameFromRowKey(kv.getRow()); + String to = TerminalSpanUtils.getApplicationNameFromColumnName(kv.getQualifier()); + int requestCount = Bytes.toInt(kv.getValue()); + short serviceType = TerminalSpanUtils.getServiceTypeFromColumnName(kv.getQualifier()); + + TerminalRequest request = new TerminalRequest(from, to, serviceType, requestCount); + requestList.add(request); + } + } + return requestList; + } +} diff --git a/src/main/java/com/nhn/hippo/web/service/FlowChartService.java b/src/main/java/com/nhn/hippo/web/service/FlowChartService.java index 6924f167a..b4dc36e9f 100755 --- a/src/main/java/com/nhn/hippo/web/service/FlowChartService.java +++ b/src/main/java/com/nhn/hippo/web/service/FlowChartService.java @@ -56,14 +56,24 @@ public interface FlowChartService { */ public ServerCallTree selectServerCallTree(Set traceIds); + /** + * + * @param traceIds + * @param applicationName + * @param from + * @param to + * @return + */ + public ServerCallTree selectServerCallTree(Set traceIds, String applicationName, long from, long to); + /** * select all application names * * @return all of application names */ public List selectAllApplicationNames(); - - - public String[] selectAgentIds(String[] hosts); + public String[] selectAgentIds(String[] hosts); + + public ServerCallTree selectServerCallTree(TraceId traceId); } diff --git a/src/main/java/com/nhn/hippo/web/service/FlowChartServiceImpl.java b/src/main/java/com/nhn/hippo/web/service/FlowChartServiceImpl.java index 7f7363f60..8345d7347 100755 --- a/src/main/java/com/nhn/hippo/web/service/FlowChartServiceImpl.java +++ b/src/main/java/com/nhn/hippo/web/service/FlowChartServiceImpl.java @@ -1,10 +1,12 @@ package com.nhn.hippo.web.service; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import org.slf4j.Logger; @@ -12,14 +14,17 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; +import org.springframework.util.StopWatch; import com.nhn.hippo.web.calltree.rpc.RPCCallTree; import com.nhn.hippo.web.calltree.server.ServerCallTree; import com.nhn.hippo.web.dao.ApplicationIndexDao; import com.nhn.hippo.web.dao.ApplicationTraceIndexDao; import com.nhn.hippo.web.dao.RootTraceIndexDao; +import com.nhn.hippo.web.dao.TerminalStatisticsDao; import com.nhn.hippo.web.dao.TraceDao; import com.nhn.hippo.web.dao.TraceIndexDao; +import com.nhn.hippo.web.vo.TerminalRequest; import com.nhn.hippo.web.vo.TraceId; import com.profiler.common.ServiceType; import com.profiler.common.bo.SpanBo; @@ -34,96 +39,169 @@ import com.profiler.common.hbase.HBaseTables; @Service public class FlowChartServiceImpl implements FlowChartService { - private Logger logger = LoggerFactory.getLogger(this.getClass()); + private Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - @Qualifier("hbaseClient") - HBaseClient client; + @Autowired + @Qualifier("hbaseClient") + HBaseClient client; - @Autowired - private TraceDao traceDao; + @Autowired + private TraceDao traceDao; - @Autowired - private RootTraceIndexDao rootTraceIndexDao; + @Autowired + private RootTraceIndexDao rootTraceIndexDao; - @Autowired - private TraceIndexDao traceIndexDao; + @Autowired + private TraceIndexDao traceIndexDao; - @Autowired - private ApplicationIndexDao applicationIndexDao; + @Autowired + private ApplicationIndexDao applicationIndexDao; - @Autowired - private ApplicationTraceIndexDao applicationTraceIndexDao; + @Autowired + private ApplicationTraceIndexDao applicationTraceIndexDao; - @Override - public List selectAllApplicationNames() { - return applicationIndexDao.selectAllApplicationNames(); - } + @Autowired + private TerminalStatisticsDao terminalStatisticsDao; - @Override - public String[] selectAgentIdsFromApplicationName(String applicationName) { - return applicationIndexDao.selectAgentIds(applicationName); - } + @Override + public List selectAllApplicationNames() { + return applicationIndexDao.selectAllApplicationNames(); + } - @Override - public Set selectTraceIdsFromTraceIndex(String[] agentIds, long from, long to) { - if (agentIds == null) { - throw new NullPointerException("agentIds"); - } + @Override + public String[] selectAgentIdsFromApplicationName(String applicationName) { + return applicationIndexDao.selectAgentIds(applicationName); + } - if (agentIds.length == 1) { - // single scan - if (logger.isTraceEnabled()) { - logger.trace("scan {}, {}, {}", new Object[]{agentIds[0], from, to}); - } - List bytes = this.traceIndexDao.scanTraceIndex(agentIds[0], from, to); - Set result = new HashSet(); - for (byte[] traceId : bytes) { - TraceId tid = new TraceId(traceId); - result.add(tid); - logger.trace("traceid:{}", tid); - } - return result; - } else { - // multi scan 가능한 동일 open htable 에서 액세스함. - List> multiScan = this.traceIndexDao.multiScanTraceIndex(agentIds, from, to); - Set result = new HashSet(); - for (List scan : multiScan) { - for (byte[] traceId : scan) { - result.add(new TraceId(traceId)); - } - } - return result; - } - } + @Override + public Set selectTraceIdsFromTraceIndex(String[] agentIds, long from, long to) { + if (agentIds == null) { + throw new NullPointerException("agentIds"); + } - @Override - public RPCCallTree selectRPCCallTree(Set traceIds) { - final RPCCallTree tree = new RPCCallTree(); - List> traces = this.traceDao.selectSpans(traceIds); - for (List transaction : traces) { - for (SpanBo eachTransaction : transaction) { - tree.addSpan(eachTransaction); - } - } - return tree.build(); - } + if (agentIds.length == 1) { + // single scan + if (logger.isTraceEnabled()) { + logger.trace("scan {}, {}, {}", new Object[] { agentIds[0], from, to }); + } + List bytes = this.traceIndexDao.scanTraceIndex(agentIds[0], from, to); + Set result = new HashSet(); + for (byte[] traceId : bytes) { + TraceId tid = new TraceId(traceId); + result.add(tid); + logger.trace("traceid:{}", tid); + } + return result; + } else { + // multi scan 가능한 동일 open htable 에서 액세스함. + List> multiScan = this.traceIndexDao.multiScanTraceIndex(agentIds, from, to); + Set result = new HashSet(); + for (List scan : multiScan) { + for (byte[] traceId : scan) { + result.add(new TraceId(traceId)); + } + } + return result; + } + } - @Override - public ServerCallTree selectServerCallTree(Set traceIds) { - final ServerCallTree tree = new ServerCallTree(); + @Override + public RPCCallTree selectRPCCallTree(Set traceIds) { + final RPCCallTree tree = new RPCCallTree(); + List> traces = this.traceDao.selectSpans(traceIds); + for (List transaction : traces) { + for (SpanBo eachTransaction : transaction) { + tree.addSpan(eachTransaction); + } + } + return tree.build(); + } - List> traces = this.traceDao.selectSpans(traceIds); + @Override + public ServerCallTree selectServerCallTree(Set traceIds) { + final ServerCallTree tree = new ServerCallTree(); - for (List transaction : traces) { - List processed = refine(transaction); - markRecursiveCall(processed); - for (SpanBo eachTransaction : processed) { - tree.addSpan(eachTransaction); - } - } - return tree.build(); - } + List> traces = this.traceDao.selectSpans(traceIds); + + for (List transaction : traces) { + List processed = refine(transaction); + markRecursiveCall(processed); + for (SpanBo eachTransaction : processed) { + tree.addSpan(eachTransaction); + } + } + return tree.build(); + } + + @Override + public ServerCallTree selectServerCallTree(TraceId traceId) { + final ServerCallTree tree = new ServerCallTree(); + + List transaction = this.traceDao.selectSpans(traceId); + + List processed = refine(transaction); + markRecursiveCall(processed); + for (SpanBo eachTransaction : processed) { + tree.addSpan(eachTransaction); + } + return tree.build(); + } + + @Override + public ServerCallTree selectServerCallTree(Set traceIds, String applicationName, long from, long to) { + final Map terminalQueryParams = new HashMap(); + final ServerCallTree tree = new ServerCallTree(); + + StopWatch watch = new StopWatch(); + watch.start("scanNonTerminalSpans"); + + // fetch non-terminal spans + List> traces = this.traceDao.selectSpans(traceIds); + + watch.stop(); + int totalNonTerminalSpansCount = 0; + + // processing spans + for (List transaction : traces) { + totalNonTerminalSpansCount += transaction.size(); + + List processed = refine(transaction); + markRecursiveCall(processed); + for (SpanBo eachTransaction : processed) { + tree.addSpan(eachTransaction); + + // make query param + terminalQueryParams.put(eachTransaction.getServiceName(), eachTransaction.getServiceType()); + } + } + + if (logger.isInfoEnabled()) { + logger.info("Fetch non-terminal spans elapsed : {}ms, {} traces, {} spans", new Object[] { watch.getLastTaskTimeMillis(), traces.size(), totalNonTerminalSpansCount }); + } + + watch.start("scanTerminalStatistics"); + + // fetch terminal info + for (Entry param : terminalQueryParams.entrySet()) { + ServiceType svcType = param.getValue(); + if (!svcType.isRpcClient() && !svcType.isUnknown() && !svcType.isTerminal()) { + long start = System.currentTimeMillis(); + List> terminals = terminalStatisticsDao.selectTerminal(param.getKey(), from, to); + logger.info(" Fetch terminals of {} : {}ms", param.getKey(), System.currentTimeMillis() - start); + + for (List terminal : terminals) { + for (TerminalRequest t : terminal) { + tree.addTerminal(t); + } + } + } + } + + watch.stop(); + logger.info("Fetch terminal statistics elapsed : {}ms", watch.getLastTaskTimeMillis()); + + return tree.build(); + } private SpanBo findChildSpan(final List list, final SpanBo parent) { for (int i = 0; i < list.size(); i++) { @@ -139,10 +217,7 @@ public class FlowChartServiceImpl implements FlowChartService { private List refine(final List list) { for (int i = 0; i < list.size(); i++) { SpanBo span = list.get(i); - String svcName = span.getServiceName(); - // TODO 임시로 HTTP/1.1을 확인하게 해두었음. merge해야하는 span 확인 방법을 바꿔야함. - // if ("HTTP/1.1".equals(svcName)) { if (span.getServiceType().isRpcClient()) { SpanBo child = findChildSpan(list, span); @@ -161,58 +236,58 @@ public class FlowChartServiceImpl implements FlowChartService { } return list; } - - private void markRecursiveCall(final List list) { - for (int i = 0; i < list.size(); i++) { - SpanBo a = list.get(i); - for (int j = 0; j < list.size(); j++) { - if (i == j) - continue; - SpanBo b = list.get(j); - if (a.getServiceName().equals(b.getServiceName()) && a.getSpanId() == b.getParentSpanId()) { - a.increaseRecursiveCallCount(); - } - } - } - } - @Override - public Set selectTraceIdsFromApplicationTraceIndex(String applicationName, long from, long to) { - if (applicationName == null) { - throw new NullPointerException("applicationName"); - } + private void markRecursiveCall(final List list) { + for (int i = 0; i < list.size(); i++) { + SpanBo a = list.get(i); + for (int j = 0; j < list.size(); j++) { + if (i == j) + continue; + SpanBo b = list.get(j); + if (a.getServiceName().equals(b.getServiceName()) && a.getSpanId() == b.getParentSpanId()) { + a.increaseRecursiveCallCount(); + } + } + } + } - if (logger.isTraceEnabled()) { - logger.trace("scan {}, {}, {}", new Object[]{applicationName, from, to}); - } + @Override + public Set selectTraceIdsFromApplicationTraceIndex(String applicationName, long from, long to) { + if (applicationName == null) { + throw new NullPointerException("applicationName"); + } - List bytes = this.applicationTraceIndexDao.scanTraceIndex(applicationName, from, to); - Set result = new HashSet(); - for (byte[] traceId : bytes) { - TraceId tid = new TraceId(traceId); - result.add(tid); - logger.trace("traceid:{}", tid); - } - return result; - } + if (logger.isTraceEnabled()) { + logger.trace("scan {}, {}, {}", new Object[] { applicationName, from, to }); + } - @Override - public String[] selectAgentIds(String[] hosts) { - List column = new ArrayList(); - column.add(new HbaseColumn("Agents", "AgentID")); + List bytes = this.applicationTraceIndexDao.scanTraceIndex(applicationName, from, to); + Set result = new HashSet(); + for (byte[] traceId : bytes) { + TraceId tid = new TraceId(traceId); + result.add(tid); + logger.trace("traceid:{}", tid); + } + return result; + } - HBaseQuery query = new HBaseQuery(HBaseTables.APPLICATION_INDEX, null, null, column); - Iterator> iterator = client.getHBaseData(query); + @Override + public String[] selectAgentIds(String[] hosts) { + List column = new ArrayList(); + column.add(new HbaseColumn("Agents", "AgentID")); - if (logger.isDebugEnabled()) { - while (iterator.hasNext()) { - logger.debug("selectedAgentId={}", iterator.next()); - } - logger.debug("!!!==============WARNING==============!!!"); - logger.debug("!!! selectAgentIds IS NOT IMPLEMENTED !!!"); - logger.debug("!!!===================================!!!"); - } + HBaseQuery query = new HBaseQuery(HBaseTables.APPLICATION_INDEX, null, null, column); + Iterator> iterator = client.getHBaseData(query); - return hosts; - } + if (logger.isDebugEnabled()) { + while (iterator.hasNext()) { + logger.debug("selectedAgentId={}", iterator.next()); + } + logger.debug("!!!==============WARNING==============!!!"); + logger.debug("!!! selectAgentIds IS NOT IMPLEMENTED !!!"); + logger.debug("!!!===================================!!!"); + } + + return hosts; + } } diff --git a/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java b/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java index 5357f98d8..b5603de8b 100644 --- a/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java +++ b/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java @@ -1,5 +1,14 @@ package com.nhn.hippo.web.service; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + import com.nhn.hippo.web.calltree.span.SpanAlign; import com.nhn.hippo.web.calltree.span.SpanAligner; import com.nhn.hippo.web.dao.TraceDao; @@ -8,14 +17,6 @@ import com.profiler.common.bo.SpanBo; import com.profiler.common.mapping.ApiMappingTable; import com.profiler.common.mapping.ApiUtils; import com.profiler.common.mapping.MethodMapping; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; -import java.util.UUID; /** * @@ -23,59 +24,61 @@ import java.util.UUID; @Service public class SpanServiceImpl implements SpanService { - private Logger logger = LoggerFactory.getLogger(this.getClass()); + private Logger logger = LoggerFactory.getLogger(this.getClass()); - @Autowired - private TraceDao traceDao; + @Autowired + private TraceDao traceDao; - @Override - public List selectSpan(String uuid) { - UUID id = UUID.fromString(uuid); - List spans = traceDao.selectSpanAndAnnotation(id); - if (spans == null) { - return Collections.emptyList(); - } - transitionApiId(spans); - List order = order(spans); - // TODO root span not found시 row data라도 보여줘야 됨. - if (order.size() != spans.size()) { - // TODO 중간 노드 데이터 분실 ? 혹은 잘못된 데이터 생성? - logger.info("span node not complete! "); - } - return order; + @Override + public List selectSpan(String uuid) { + UUID id = UUID.fromString(uuid); + List spans = traceDao.selectSpanAndAnnotation(id); + if (spans == null) { + return Collections.emptyList(); + } + transitionApiId(spans); + List order = order(spans); + // TODO root span not found시 row data라도 보여줘야 됨. + if (order.size() != spans.size()) { + // TODO 중간 노드 데이터 분실 ? 혹은 잘못된 데이터 생성? + logger.info("span node not complete! "); + } + return order; - } + } - private void transitionApiId(List spans) { - for (SpanBo spanBo : spans) { - List annotationBoList = spanBo.getAnnotationBoList(); - for (AnnotationBo annotationBo : annotationBoList) { - // TODO API-ID 일단 날코딩 나중에 뭔가 key를 따자 - if ("API-ID".equals(annotationBo.getKey())) { - MethodMapping methodMapping = null; - try { - methodMapping = ApiMappingTable.findMethodMapping((Integer) annotationBo.getValue()); - } catch (Exception e) { - e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. - } - String className = methodMapping.getClassMapping().getClassName(); - String methodName = methodMapping.getMethodName(); - String[] parameterType = methodMapping.getParameterType(); - String[] parameterName = methodMapping.getParameterName(); - String args = ApiUtils.mergeParameterVariableNameDescription(parameterType, parameterName); - AnnotationBo api = new AnnotationBo(); - api.setKey("API"); - api.setValue(className + "." + methodName + args); - annotationBoList.add(api); - break; - } - } - } - } + private void transitionApiId(List spans) { + for (SpanBo spanBo : spans) { + List annotationBoList = spanBo.getAnnotationBoList(); + for (AnnotationBo annotationBo : annotationBoList) { + // TODO API-ID 일단 날코딩 나중에 뭔가 key를 따자 + if ("API-ID".equals(annotationBo.getKey())) { + MethodMapping methodMapping = null; + try { + methodMapping = ApiMappingTable.findMethodMapping((Integer) annotationBo.getValue()); + } catch (Exception e) { + e.printStackTrace(); // To change body of catch + // statement use File | Settings + // | File Templates. + } + String className = methodMapping.getClassMapping().getClassName(); + String methodName = methodMapping.getMethodName(); + String[] parameterType = methodMapping.getParameterType(); + String[] parameterName = methodMapping.getParameterName(); + String args = ApiUtils.mergeParameterVariableNameDescription(parameterType, parameterName); + AnnotationBo api = new AnnotationBo(); + api.setKey("API"); + api.setValue(className + "." + methodName + args); + annotationBoList.add(api); + break; + } + } + } + } - private List order(List spans) { + private List order(List spans) { - SpanAligner spanAligner = new SpanAligner(spans); - return spanAligner.sort(); - } + SpanAligner spanAligner = new SpanAligner(spans); + return spanAligner.sort(); + } } diff --git a/src/main/java/com/nhn/hippo/web/vo/TerminalRequest.java b/src/main/java/com/nhn/hippo/web/vo/TerminalRequest.java new file mode 100644 index 000000000..eeb79d960 --- /dev/null +++ b/src/main/java/com/nhn/hippo/web/vo/TerminalRequest.java @@ -0,0 +1,74 @@ +package com.nhn.hippo.web.vo; + +public class TerminalRequest { + + private final String from; + private final String to; + private final short toServiceType; + private final int requestCount; + + public TerminalRequest(String from, String to, short toServiceType, int requestCount) { + this.from = from; + this.to = to; + this.toServiceType = toServiceType; + this.requestCount = requestCount; + } + + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } + + public int getRequestCount() { + return requestCount; + } + + public short getToServiceType() { + return toServiceType; + } + + @Override + public String toString() { + return "{From=" + from + ", To=" + to + ", ReqCount=" + requestCount + "}"; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((from == null) ? 0 : from.hashCode()); + result = prime * result + requestCount; + result = prime * result + ((to == null) ? 0 : to.hashCode()); + result = prime * result + toServiceType; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + TerminalRequest other = (TerminalRequest) obj; + if (from == null) { + if (other.from != null) + return false; + } else if (!from.equals(other.from)) + return false; + if (requestCount != other.requestCount) + return false; + if (to == null) { + if (other.to != null) + return false; + } else if (!to.equals(other.to)) + return false; + if (toServiceType != other.toServiceType) + return false; + return true; + } +} diff --git a/src/main/resources/root-context.xml b/src/main/resources/root-context.xml index ad969f019..28185ca6f 100644 --- a/src/main/resources/root-context.xml +++ b/src/main/resources/root-context.xml @@ -23,4 +23,5 @@ + diff --git a/src/main/webapp/WEB-INF/views/flowserver.jsp b/src/main/webapp/WEB-INF/views/flowserver.jsp index e9d2c24c9..9ad89307f 100644 --- a/src/main/webapp/WEB-INF/views/flowserver.jsp +++ b/src/main/webapp/WEB-INF/views/flowserver.jsp @@ -15,19 +15,17 @@ ], "serviceType" : "${node.serviceType}", "terminal" : "${node.serviceType.terminal}" - } - , + } , ], "links" : [ { - "source" : ${link.from.sequence}, + "source" : ${link.from.sequence}, "target" : ${link.to.sequence}, "value" : ${link.histogram.sampleCount}, - "histogram" : ${link.histogram} - } - , + "histogram" : ${link.histogram} + } , ] }, @@ -47,8 +45,7 @@ , ] - } - , + } , ], @@ -60,8 +57,7 @@ "timestamp" : ${trace.startTime}, "executionTime" : ${trace.executionTime}, "name" : "${t.rpc}" - } - , + } , , diff --git a/src/main/webapp/WEB-INF/views/selectTransaction.jsp b/src/main/webapp/WEB-INF/views/selectTransaction.jsp index 682ec474b..352e0577c 100644 --- a/src/main/webapp/WEB-INF/views/selectTransaction.jsp +++ b/src/main/webapp/WEB-INF/views/selectTransaction.jsp @@ -202,28 +202,6 @@ ] }; - var rpcdata = { - "nodes":[ - - - {"name":"${node.serviceName}:${node.rpc}"} - - - {"name":"${node}"} - - , - - - ], - "links":[ - - {"source":${link.from.sequence}, "target":${link.to.sequence}, "value":${link.callCount}} - , - - - ] - }; - $(document).ready(function () { drawSankeyChart(data, "#graph", 960, 500); });