[유치수] [NOBTS] add terminal span

git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@947 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
Chisu Yu
2012-11-29 08:59:10 +00:00
parent d6ffaa2ed0
commit df0eac5118
17 changed files with 620 additions and 324 deletions
@@ -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<Server> {
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;
}
@@ -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<String, Server> servers = new HashMap<String, Server>();
private final Map<String, String> spanIdToServerId = new HashMap<String, String>();
private final Map<String, ServerRequest> ServerRequests = new HashMap<String, ServerRequest>();
private final List<SpanBo> spans = new ArrayList<SpanBo>();
private final BusinessTransactions businessTransactions = new BusinessTransactions();
private final Map<String, Server> servers = new HashMap<String, Server>();
private final Map<String, String> spanIdToServerId = new HashMap<String, String>();
private final Map<String, ServerRequest> serverRequests = new HashMap<String, ServerRequest>();
private final List<SpanBo> spans = new ArrayList<SpanBo>();
private final BusinessTransactions businessTransactions = new BusinessTransactions();
private boolean isBuilt = false;
private boolean isBuilt = false;
private final Set<TerminalRequest> terminalRequests = new HashSet<TerminalRequest>();
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<String, Server> 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<String, Server> 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<Server> getNodes() {
return this.servers.values();
}
public Collection<Server> getNodes() {
return this.servers.values();
}
public Collection<ServerRequest> getLinks() {
return this.ServerRequests.values();
}
public Collection<ServerRequest> 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();
}
}
@@ -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<TraceId> traceIds = new HashSet<TraceId>(1);
traceIds.add(new TraceId(UUID.fromString(traceId)));
ServerCallTree callTree = flow.selectServerCallTree(traceIds);
// Set<TraceId> traceIds = new HashSet<TraceId>(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;
}
@@ -53,13 +53,13 @@ public class FlowChartController {
Set<TraceId> 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());
@@ -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<List<TerminalRequest>> selectTerminal(String applicationName, long from, long to);
}
@@ -18,11 +18,13 @@ public interface TraceDao {
List<SpanBo> selectSpanAndAnnotation(UUID traceId);
List<SpanBo> selectSpan(long traceIdMost, long traceIdLeast);
List<List<SpanBo>> selectSpans(List<UUID> traceIds);
List<List<SpanBo>> selectSpans(Set<TraceId> traceIds);
List<SpanBo> selectSpans(TraceId traceId);
@Deprecated
List<List<SpanBo>> selectSpansAndAnnotation(Set<TraceId> traceIds);
}
@@ -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<List<TerminalRequest>> terminalRequestCountMapper;
@Override
public List<List<TerminalRequest>> 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;
}
}
@@ -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<SpanBo> 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<List<SpanBo>> selectSpansAndAnnotation(Set<TraceId> traceIds) {
List<Get> gets = new ArrayList<Get>(traceIds.size());
@@ -51,7 +51,8 @@ public class SpanMapper implements RowMapper<List<SpanBo>> {
List<SpanBo> spanList = new ArrayList<SpanBo>();
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);
@@ -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<List<TerminalRequest>> {
@Override
public List<TerminalRequest> mapRow(Result result, int rowNum) throws Exception {
KeyValue[] keyList = result.raw();
List<TerminalRequest> requestList = new ArrayList<TerminalRequest>();
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;
}
}
@@ -56,14 +56,24 @@ public interface FlowChartService {
*/
public ServerCallTree selectServerCallTree(Set<TraceId> traceIds);
/**
*
* @param traceIds
* @param applicationName
* @param from
* @param to
* @return
*/
public ServerCallTree selectServerCallTree(Set<TraceId> traceIds, String applicationName, long from, long to);
/**
* select all application names
*
* @return all of application names
*/
public List<String> selectAllApplicationNames();
public String[] selectAgentIds(String[] hosts);
public String[] selectAgentIds(String[] hosts);
public ServerCallTree selectServerCallTree(TraceId traceId);
}
@@ -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<String> selectAllApplicationNames() {
return applicationIndexDao.selectAllApplicationNames();
}
@Autowired
private TerminalStatisticsDao terminalStatisticsDao;
@Override
public String[] selectAgentIdsFromApplicationName(String applicationName) {
return applicationIndexDao.selectAgentIds(applicationName);
}
@Override
public List<String> selectAllApplicationNames() {
return applicationIndexDao.selectAllApplicationNames();
}
@Override
public Set<TraceId> 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<byte[]> bytes = this.traceIndexDao.scanTraceIndex(agentIds[0], from, to);
Set<TraceId> result = new HashSet<TraceId>();
for (byte[] traceId : bytes) {
TraceId tid = new TraceId(traceId);
result.add(tid);
logger.trace("traceid:{}", tid);
}
return result;
} else {
// multi scan 가능한 동일 open htable 에서 액세스함.
List<List<byte[]>> multiScan = this.traceIndexDao.multiScanTraceIndex(agentIds, from, to);
Set<TraceId> result = new HashSet<TraceId>();
for (List<byte[]> scan : multiScan) {
for (byte[] traceId : scan) {
result.add(new TraceId(traceId));
}
}
return result;
}
}
@Override
public Set<TraceId> selectTraceIdsFromTraceIndex(String[] agentIds, long from, long to) {
if (agentIds == null) {
throw new NullPointerException("agentIds");
}
@Override
public RPCCallTree selectRPCCallTree(Set<TraceId> traceIds) {
final RPCCallTree tree = new RPCCallTree();
List<List<SpanBo>> traces = this.traceDao.selectSpans(traceIds);
for (List<SpanBo> 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<byte[]> bytes = this.traceIndexDao.scanTraceIndex(agentIds[0], from, to);
Set<TraceId> result = new HashSet<TraceId>();
for (byte[] traceId : bytes) {
TraceId tid = new TraceId(traceId);
result.add(tid);
logger.trace("traceid:{}", tid);
}
return result;
} else {
// multi scan 가능한 동일 open htable 에서 액세스함.
List<List<byte[]>> multiScan = this.traceIndexDao.multiScanTraceIndex(agentIds, from, to);
Set<TraceId> result = new HashSet<TraceId>();
for (List<byte[]> scan : multiScan) {
for (byte[] traceId : scan) {
result.add(new TraceId(traceId));
}
}
return result;
}
}
@Override
public ServerCallTree selectServerCallTree(Set<TraceId> traceIds) {
final ServerCallTree tree = new ServerCallTree();
@Override
public RPCCallTree selectRPCCallTree(Set<TraceId> traceIds) {
final RPCCallTree tree = new RPCCallTree();
List<List<SpanBo>> traces = this.traceDao.selectSpans(traceIds);
for (List<SpanBo> transaction : traces) {
for (SpanBo eachTransaction : transaction) {
tree.addSpan(eachTransaction);
}
}
return tree.build();
}
List<List<SpanBo>> traces = this.traceDao.selectSpans(traceIds);
@Override
public ServerCallTree selectServerCallTree(Set<TraceId> traceIds) {
final ServerCallTree tree = new ServerCallTree();
for (List<SpanBo> transaction : traces) {
List<SpanBo> processed = refine(transaction);
markRecursiveCall(processed);
for (SpanBo eachTransaction : processed) {
tree.addSpan(eachTransaction);
}
}
return tree.build();
}
List<List<SpanBo>> traces = this.traceDao.selectSpans(traceIds);
for (List<SpanBo> transaction : traces) {
List<SpanBo> 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<SpanBo> transaction = this.traceDao.selectSpans(traceId);
List<SpanBo> processed = refine(transaction);
markRecursiveCall(processed);
for (SpanBo eachTransaction : processed) {
tree.addSpan(eachTransaction);
}
return tree.build();
}
@Override
public ServerCallTree selectServerCallTree(Set<TraceId> traceIds, String applicationName, long from, long to) {
final Map<String, ServiceType> terminalQueryParams = new HashMap<String, ServiceType>();
final ServerCallTree tree = new ServerCallTree();
StopWatch watch = new StopWatch();
watch.start("scanNonTerminalSpans");
// fetch non-terminal spans
List<List<SpanBo>> traces = this.traceDao.selectSpans(traceIds);
watch.stop();
int totalNonTerminalSpansCount = 0;
// processing spans
for (List<SpanBo> transaction : traces) {
totalNonTerminalSpansCount += transaction.size();
List<SpanBo> 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<String, ServiceType> param : terminalQueryParams.entrySet()) {
ServiceType svcType = param.getValue();
if (!svcType.isRpcClient() && !svcType.isUnknown() && !svcType.isTerminal()) {
long start = System.currentTimeMillis();
List<List<TerminalRequest>> terminals = terminalStatisticsDao.selectTerminal(param.getKey(), from, to);
logger.info(" Fetch terminals of {} : {}ms", param.getKey(), System.currentTimeMillis() - start);
for (List<TerminalRequest> 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<SpanBo> list, final SpanBo parent) {
for (int i = 0; i < list.size(); i++) {
@@ -139,10 +217,7 @@ public class FlowChartServiceImpl implements FlowChartService {
private List<SpanBo> refine(final List<SpanBo> 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<SpanBo> 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<TraceId> selectTraceIdsFromApplicationTraceIndex(String applicationName, long from, long to) {
if (applicationName == null) {
throw new NullPointerException("applicationName");
}
private void markRecursiveCall(final List<SpanBo> 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<TraceId> selectTraceIdsFromApplicationTraceIndex(String applicationName, long from, long to) {
if (applicationName == null) {
throw new NullPointerException("applicationName");
}
List<byte[]> bytes = this.applicationTraceIndexDao.scanTraceIndex(applicationName, from, to);
Set<TraceId> result = new HashSet<TraceId>();
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<HbaseColumn> column = new ArrayList<HBaseQuery.HbaseColumn>();
column.add(new HbaseColumn("Agents", "AgentID"));
List<byte[]> bytes = this.applicationTraceIndexDao.scanTraceIndex(applicationName, from, to);
Set<TraceId> result = new HashSet<TraceId>();
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<Map<String, byte[]>> iterator = client.getHBaseData(query);
@Override
public String[] selectAgentIds(String[] hosts) {
List<HbaseColumn> column = new ArrayList<HBaseQuery.HbaseColumn>();
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<Map<String, byte[]>> 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;
}
}
@@ -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<SpanAlign> selectSpan(String uuid) {
UUID id = UUID.fromString(uuid);
List<SpanBo> spans = traceDao.selectSpanAndAnnotation(id);
if (spans == null) {
return Collections.emptyList();
}
transitionApiId(spans);
List<SpanAlign> 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<SpanAlign> selectSpan(String uuid) {
UUID id = UUID.fromString(uuid);
List<SpanBo> spans = traceDao.selectSpanAndAnnotation(id);
if (spans == null) {
return Collections.emptyList();
}
transitionApiId(spans);
List<SpanAlign> 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<SpanBo> spans) {
for (SpanBo spanBo : spans) {
List<AnnotationBo> 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<SpanBo> spans) {
for (SpanBo spanBo : spans) {
List<AnnotationBo> 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<SpanAlign> order(List<SpanBo> spans) {
private List<SpanAlign> order(List<SpanBo> spans) {
SpanAligner spanAligner = new SpanAligner(spans);
return spanAligner.sort();
}
SpanAligner spanAligner = new SpanAligner(spans);
return spanAligner.sort();
}
}
@@ -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;
}
}
+1
View File
@@ -23,4 +23,5 @@
</bean>
<bean id="applicationNameMapper" class="com.nhn.hippo.web.mapper.ApplicationNameMapper"></bean>
<bean id="agentIdMapper" class="com.nhn.hippo.web.mapper.AgentIdMapper"></bean>
<bean id="terminalRequestCountMapper" class="com.nhn.hippo.web.mapper.TerminalRequestCountMapper"></bean>
</beans>
+6 -10
View File
@@ -15,19 +15,17 @@
],
"serviceType" : "${node.serviceType}",
"terminal" : "${node.serviceType.terminal}"
}
<c:if test="${!status.last}">,</c:if>
} <c:if test="${!status.last}">,</c:if>
</c:forEach>
],
"links" : [
<c:forEach items="${links}" var="link" varStatus="status">
{
"source" : ${link.from.sequence},
"source" : ${link.from.sequence},
"target" : ${link.to.sequence},
"value" : ${link.histogram.sampleCount},
"histogram" : ${link.histogram}
}
<c:if test="${!status.last}">,</c:if>
"histogram" : ${link.histogram}
} <c:if test="${!status.last}">,</c:if>
</c:forEach>
]
},
@@ -47,8 +45,7 @@
<c:if test="${!status2.last}">,</c:if>
</c:forEach>
]
}
<c:if test="${!status.last}">,</c:if>
} <c:if test="${!status.last}">,</c:if>
</c:forEach>
],
@@ -60,8 +57,7 @@
"timestamp" : ${trace.startTime},
"executionTime" : ${trace.executionTime},
"name" : "${t.rpc}"
}
<c:if test="${!status4.last}">,</c:if>
} <c:if test="${!status4.last}">,</c:if>
</c:forEach>
<c:if test="${!status3.last}">,</c:if>
</c:forEach>
@@ -202,28 +202,6 @@
]
};
var rpcdata = {
"nodes":[
<c:forEach items="${rpcnodes}" var="node" varStatus="status">
<c:if test="${node.terminal}">
{"name":"${node.serviceName}:${node.rpc}"}
</c:if>
<c:if test="${not node.terminal}">
{"name":"${node}"}
</c:if>
<c:if test="${!status.last}">,
</c:if>
</c:forEach>
],
"links":[
<c:forEach items="${rpclinks}" var="link" varStatus="status">
{"source":${link.from.sequence}, "target":${link.to.sequence}, "value":${link.callCount}}
<c:if test="${!status.last}">,
</c:if>
</c:forEach>
]
};
$(document).ready(function () {
drawSankeyChart(data, "#graph", 960, 500);
});