diff --git a/src/main/java/com/nhn/hippo/web/calltree/span/SpanAlign.java b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAlign.java index fe2f48c25..9946d8b42 100644 --- a/src/main/java/com/nhn/hippo/web/calltree/span/SpanAlign.java +++ b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAlign.java @@ -7,47 +7,61 @@ import com.profiler.common.bo.SubSpanBo; * */ public class SpanAlign { - private int depth; - private SpanBo span; - private SubSpanBo subSpanBo; - private boolean root = true; + private int depth; + private SpanBo spanBo; + private SubSpanBo subSpanBo; + private boolean span = true; - public SpanAlign(int depth, SpanBo span) { - this.depth = depth; - this.span = span; - } + public SpanAlign(int depth, SpanBo spanBo) { + this.depth = depth; + this.spanBo = spanBo; + this.span = true; + } - public SpanAlign(int depth, SpanBo root, SubSpanBo subSpanBo) { - this.depth = depth; - this.span = root; - this.subSpanBo = subSpanBo; - } + public SpanAlign(int depth, SpanBo spanBo, SubSpanBo subSpanBo) { + this.depth = depth; + this.spanBo = spanBo; + this.subSpanBo = subSpanBo; + this.span = false; + } - public void setRoot(boolean root) { - this.root = root; - } + public void setSpan(boolean span) { + this.span = span; + } - public boolean isRoot() { - return root; - } + public boolean isSpan() { + return span; + } - public int getDepth() { - return depth; - } + public int getDepth() { + return depth; + } -// public String getDepthSpace() { -// StringBuilder sb = new StringBuilder(depth); -// for (int i = 0; i < depth; i++) { -// sb.append(' '); -// } -// return sb.toString(); -// } + public SpanBo getSpan() { + return spanBo; + } - public SpanBo getSpan() { - return span; - } + public SubSpanBo getSubSpanBo() { + return subSpanBo; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("SpanAlign={"); + sb.append("depth=").append(depth); + + if (subSpanBo != null) { + sb.append(", orgDepth").append(subSpanBo.getDepth()); + sb.append(", subSpabBo=").append(subSpanBo.getServiceName()); + } else { + sb.append(", spabBo=").append(spanBo.getServiceName()); + } + + sb.append("}\n"); + + return sb.toString(); + } - public SubSpanBo getSubSpanBo() { - return subSpanBo; - } } diff --git a/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner.java b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner.java index 4b724977b..a7a41c2e8 100644 --- a/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner.java +++ b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner.java @@ -16,6 +16,7 @@ import com.profiler.common.bo.SpanBo; /** * */ +@Deprecated public class SpanAligner { public static final Long SPAN_ROOT = -1L; diff --git a/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner2.java b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner2.java new file mode 100644 index 000000000..44f1d5232 --- /dev/null +++ b/src/main/java/com/nhn/hippo/web/calltree/span/SpanAligner2.java @@ -0,0 +1,72 @@ +package com.nhn.hippo.web.calltree.span; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.profiler.common.bo.SpanBo; +import com.profiler.common.bo.SubSpanBo; + +/** + * + * @author netspider + * + */ +public class SpanAligner2 { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final Map spanMap; + + public SpanAligner2(List spans) { + spanMap = new HashMap(spans.size()); + + for (SpanBo span : spans) { + if (spanMap.containsKey(span.getSpanId())) { + throw new IllegalStateException("duplicated spanId. id:" + span.getSpanId()); + } + this.spanMap.put((span.getParentSpanId() == -1) ? -1L : span.getSpanId(), span); + } + } + + public List sort() { + List list = new ArrayList(); + SpanBo root = spanMap.get(new Long(-1)); + + if (root == null) { + throw new IllegalStateException("root span not found"); + } + + populate(root, 0, list); + + System.out.println(list); + + return list; + } + + private void populate(SpanBo parentSpan, int spanDepth, List container) { + int depth = spanDepth + 1; + + SpanAlign element = new SpanAlign(depth, parentSpan); + container.add(element); + + List subSpanList = parentSpan.getSubSpanList(); + for (SubSpanBo subSpanBo : subSpanList) { + if (subSpanBo.getDepth() != -1) { + depth = spanDepth + subSpanBo.getDepth() + 1; + } + + SpanAlign sa = new SpanAlign(depth, parentSpan, subSpanBo); + container.add(sa); + + Long nextSpanId = new Long(subSpanBo.getNextSpanId()); + if (nextSpanId != -1 && spanMap.containsKey(nextSpanId)) { + populate(spanMap.get(new Long(nextSpanId)), depth, container); + } + } + } +} diff --git a/src/main/java/com/nhn/hippo/web/calltree/span/SpanPopulator.java b/src/main/java/com/nhn/hippo/web/calltree/span/SpanPopulator.java index 98b8a58d4..862a571e9 100644 --- a/src/main/java/com/nhn/hippo/web/calltree/span/SpanPopulator.java +++ b/src/main/java/com/nhn/hippo/web/calltree/span/SpanPopulator.java @@ -11,6 +11,7 @@ import java.util.List; /** * */ +@Deprecated public class SpanPopulator { private List list; private int index = 0; @@ -43,7 +44,7 @@ public class SpanPopulator { long nextSpanStartTime = getNextSpanStartTime(); if (subStartTime <= nextSpanStartTime) { SpanAlign subSpanAlign = new SpanAlign(spanAlign.getDepth(), span, subSpanBo); - subSpanAlign.setRoot(false); + subSpanAlign.setSpan(false); populatedList.add(subSpanAlign); } else { if (nextSpanStartTime == Long.MAX_VALUE) { 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 623ea32ec..726981392 100644 --- a/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java +++ b/src/main/java/com/nhn/hippo/web/service/SpanServiceImpl.java @@ -2,6 +2,7 @@ package com.nhn.hippo.web.service; import com.nhn.hippo.web.calltree.span.SpanAlign; import com.nhn.hippo.web.calltree.span.SpanAligner; +import com.nhn.hippo.web.calltree.span.SpanAligner2; import com.nhn.hippo.web.calltree.span.SpanPopulator; import com.nhn.hippo.web.dao.AgentInfoDao; import com.nhn.hippo.web.dao.SqlMetaDataDao; @@ -28,171 +29,164 @@ 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; - @Autowired - private SqlMetaDataDao sqlMetaDataDao; + @Autowired + private SqlMetaDataDao sqlMetaDataDao; - @Autowired - private AgentInfoDao agentInfoDao; + @Autowired + private AgentInfoDao agentInfoDao; - @Override - public List selectSpan(String uuid) { - UUID id = UUID.fromString(uuid); - List spans = traceDao.selectSpanAndAnnotation(id); - if (spans == null || spans.isEmpty()) { - return Collections.emptyList(); - } + @Override + public List selectSpan(String uuid) { + UUID id = UUID.fromString(uuid); + List spans = traceDao.selectSpanAndAnnotation(id); + if (spans == null || spans.isEmpty()) { + return Collections.emptyList(); + } - List order = order(spans); - transitionApiId(order); - transitionSqlId(order); - // TODO root span not found시 row data라도 보여줘야 됨. + List order = order(spans); + transitionApiId(order); + transitionSqlId(order); + // TODO root span not found시 row data라도 보여줘야 됨. - return order; + return order; + } - } + private void transitionAnnotation(List spans, AnnotationReplacementCallback annotationReplacementCallback) { + for (SpanAlign spanAlign : spans) { + List annotationBoList; + if (spanAlign.isSpan()) { + annotationBoList = spanAlign.getSpan().getAnnotationBoList(); + annotationReplacementCallback.replacement(spanAlign, annotationBoList); + } else { + annotationBoList = spanAlign.getSubSpanBo().getAnnotationBoList(); + annotationReplacementCallback.replacement(spanAlign, annotationBoList); + } + } + } + private void transitionSqlId(final List spans) { + this.transitionAnnotation(spans, new AnnotationReplacementCallback() { + @Override + public void replacement(SpanAlign spanAlign, List annotationBoList) { + AnnotationBo sqlIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.SQL_ID); + if (sqlIdAnnotation == null) { + return; + } - private void transitionAnnotation(List spans, AnnotationReplacementCallback annotationReplacementCallback) { - for (SpanAlign spanAlign : spans) { - List annotationBoList; - if (spanAlign.isRoot()) { - annotationBoList = spanAlign.getSpan().getAnnotationBoList(); - annotationReplacementCallback.replacement(spanAlign, annotationBoList); - } else { - annotationBoList = spanAlign.getSubSpanBo().getAnnotationBoList(); - annotationReplacementCallback.replacement(spanAlign, annotationBoList); - } - } - } + String agentId = getAgentId(spanAlign); + long startTime = spanAlign.getSpan().getStartTime(); + long agentStartTime = agentInfoDao.selectAgentInfoBeforeStartTime(agentId, startTime); + logger.info("{} Agent StartTime fonud:{}", agentId, agentStartTime); - private void transitionSqlId(final List spans) { - this.transitionAnnotation(spans, new AnnotationReplacementCallback() { - @Override - public void replacement(SpanAlign spanAlign, List annotationBoList) { - AnnotationBo sqlIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.SQL_ID); - if (sqlIdAnnotation == null) { - return; - } + // TODO 일단 시간까지 조회는 하지 말고 하자. + int hashCode = (Integer) sqlIdAnnotation.getValue(); + List sqlMetaDataList = sqlMetaDataDao.getSqlMetaData(agentId, hashCode, agentStartTime); + int size = sqlMetaDataList.size(); + if (size == 0) { + AnnotationBo api = new AnnotationBo(); + api.setKey(AnnotationNames.SQL_METADATA); + api.setValue("SQL-ID not found hashCode:" + hashCode); + annotationBoList.add(api); + } else if (size == 1) { + AnnotationBo sqlParamAnnotationBo = findAnnotation(annotationBoList, AnnotationNames.SQL_PARAM); + if (sqlParamAnnotationBo == null) { + AnnotationBo sqlMeta = new AnnotationBo(); + sqlMeta.setKey(AnnotationNames.SQL_METADATA); + sqlMeta.setValue(sqlMetaDataList.get(0).getSql()); + annotationBoList.add(sqlMeta); - String agentId = getAgentId(spanAlign); - long startTime = spanAlign.getSpan().getStartTime(); - long agentStartTime = agentInfoDao.selectAgentInfoBeforeStartTime(agentId, startTime); - logger.info("{} Agent StartTime fonud:{}", agentId, agentStartTime); + AnnotationBo sql = new AnnotationBo(); + sql.setKey(AnnotationNames.SQL); + sql.setValue(sqlMetaDataList.get(0).getSql()); + annotationBoList.add(sql); + } else { + // merge 해야 된다. + } + } else { + AnnotationBo api = new AnnotationBo(); + api.setKey(AnnotationNames.SQL_METADATA); + api.setValue(collisionSqlHashCodeMessage(hashCode, sqlMetaDataList)); + annotationBoList.add(api); + } - // TODO 일단 시간까지 조회는 하지 말고 하자. - int hashCode = (Integer) sqlIdAnnotation.getValue(); - List sqlMetaDataList = sqlMetaDataDao.getSqlMetaData(agentId, hashCode, agentStartTime); - int size = sqlMetaDataList.size(); - if (size == 0) { - AnnotationBo api = new AnnotationBo(); - api.setKey(AnnotationNames.SQL_METADATA); - api.setValue("SQL-ID not found hashCode:" + hashCode); - annotationBoList.add(api); - } else if (size == 1) { - AnnotationBo sqlParamAnnotationBo = findAnnotation(annotationBoList, AnnotationNames.SQL_PARAM); - if (sqlParamAnnotationBo == null) { - AnnotationBo sqlMeta = new AnnotationBo(); - sqlMeta.setKey(AnnotationNames.SQL_METADATA); - sqlMeta.setValue(sqlMetaDataList.get(0).getSql()); - annotationBoList.add(sqlMeta); + } + }); + } - AnnotationBo sql = new AnnotationBo(); - sql.setKey(AnnotationNames.SQL); - sql.setValue(sqlMetaDataList.get(0).getSql()); - annotationBoList.add(sql); - } else { - // merge 해야 된다. - } - } else { - AnnotationBo api = new AnnotationBo(); - api.setKey(AnnotationNames.SQL_METADATA); - api.setValue(collisionSqlHashCodeMessage(hashCode, sqlMetaDataList)); - annotationBoList.add(api); - } + private AnnotationBo findAnnotation(List annotationBoList, String key) { + for (AnnotationBo annotationBo : annotationBoList) { + if (key.equals(annotationBo.getKey())) { + return annotationBo; + } + } + return null; + } - } - }); - } + private String collisionSqlHashCodeMessage(int hashCode, List sqlMetaDataList) { + // TODO 이거 체크하는 테스트를 따로 만들어야 될듯 하다. 왠간하면 확율상 hashCode 충돌 케이스를 쉽게 만들수 없음. + StringBuilder sb = new StringBuilder(64); + sb.append("Collision Sql hashCode:"); + sb.append(hashCode); + sb.append('\n'); + for (int i = 0; i < sqlMetaDataList.size(); i++) { + if (i != 0) { + sb.append("or\n"); + } + SqlMetaDataBo sqlMetaDataBo = sqlMetaDataList.get(i); + sb.append(sqlMetaDataBo.getSql()); + } + return sb.toString(); + } - private AnnotationBo findAnnotation(List annotationBoList, String key) { - for (AnnotationBo annotationBo : annotationBoList) { - if (key.equals(annotationBo.getKey())) { - return annotationBo; - } - } - return null; - } + private String getAgentId(SpanAlign spanAlign) { + if (spanAlign.isSpan()) { + return spanAlign.getSpan().getAgentId(); + } else { + return spanAlign.getSubSpanBo().getAgentId(); + } + } - private String collisionSqlHashCodeMessage(int hashCode, List sqlMetaDataList) { - // TODO 이거 체크하는 테스트를 따로 만들어야 될듯 하다. 왠간하면 확율상 hashCode 충돌 케이스를 쉽게 만들수 없음. - StringBuilder sb = new StringBuilder(64); - sb.append("Collision Sql hashCode:"); - sb.append(hashCode); - sb.append('\n'); - for (int i = 0; i < sqlMetaDataList.size(); i++) { - if (i != 0) { - sb.append("or\n"); - } - SqlMetaDataBo sqlMetaDataBo = sqlMetaDataList.get(i); - sb.append(sqlMetaDataBo.getSql()); - } - return sb.toString(); - } + private void transitionApiId(List spans) { + this.transitionAnnotation(spans, new AnnotationReplacementCallback() { + @Override + public void replacement(SpanAlign spanAlign, List annotationBoList) { + AnnotationBo apiIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.API_ID); + if (apiIdAnnotation == null) { + return; + } - private String getAgentId(SpanAlign spanAlign) { - if (spanAlign.isRoot()) { - return spanAlign.getSpan().getAgentId(); - } else { - return spanAlign.getSubSpanBo().getAgentId(); - } - } + MethodMapping methodMapping = ApiMappingTable.findMethodMapping((Integer) apiIdAnnotation.getValue()); + if (methodMapping == null) { + return; + } + 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); + } + }); + } - private void transitionApiId(List spans) { - this.transitionAnnotation(spans, new AnnotationReplacementCallback() { - @Override - public void replacement(SpanAlign spanAlign, List annotationBoList) { + public static interface AnnotationReplacementCallback { + void replacement(SpanAlign spanAlign, List annotationBoList); + } - AnnotationBo apiIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.API_ID); - if (apiIdAnnotation == null) { - return; - } + private List order(List spans) { + SpanAligner2 spanAligner = new SpanAligner2(spans); + return spanAligner.sort(); - MethodMapping methodMapping = ApiMappingTable.findMethodMapping((Integer) apiIdAnnotation.getValue()); - if (methodMapping == null) { - return; - } - 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); - - } - }); - } - - public static interface AnnotationReplacementCallback { - void replacement(SpanAlign spanAlign, List annotationBoList); - } - - private List order(List spans) { - SpanAligner spanAligner = new SpanAligner(spans); - List sort = spanAligner.sort(); - if (sort.size() != spans.size()) { - // TODO 중간 노드 데이터 분실 ? 혹은 잘못된 데이터 생성? - logger.warn("span node not complete! spans:{}, sort{}", spans, sort); - } - SpanPopulator spanPopulator = new SpanPopulator(sort); - List populatedList = spanPopulator.populateSubSpan(); - return populatedList; - } + /* + * SpanAligner spanAligner = new SpanAligner(spans); List sort = spanAligner.sort(); if (sort.size() != spans.size()) { // TODO 중간 노드 데이터 분실 ? 혹은 잘못된 데이터 생성? logger.warn("span node not complete! spans:{}, sort{}", spans, sort); } SpanPopulator spanPopulator = new SpanPopulator(sort); List populatedList = spanPopulator.populateSubSpan(); return populatedList; + */ + } } diff --git a/src/main/java/com/nhn/hippo/web/vo/callstacks/RecordSet.java b/src/main/java/com/nhn/hippo/web/vo/callstacks/RecordSet.java index a1481963d..a50ae9597 100644 --- a/src/main/java/com/nhn/hippo/web/vo/callstacks/RecordSet.java +++ b/src/main/java/com/nhn/hippo/web/vo/callstacks/RecordSet.java @@ -78,7 +78,7 @@ public class RecordSet { boolean marked = false; for (SpanAlign sa : spanAligns) { - if (sa.isRoot()) { + if (sa.isSpan()) { SpanBo span = sa.getSpan(); AnnotationUtils.sortAnnotationListByKey(span); String method = (String) AnnotationUtils.getDisplayMethod(span);