mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-19 09:47:27 +10:00
[유치수] [NOBTS] represent depth of each methods
git-svn-id: http://svn.bds.nhncorp.com/pe/hippo-web/trunk@1114 84d0f5b1-2673-498c-a247-62c4ff18d310
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.profiler.common.bo.SpanBo;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class SpanAligner {
|
||||
|
||||
public static final Long SPAN_ROOT = -1L;
|
||||
|
||||
@@ -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<Long, SpanBo> spanMap;
|
||||
|
||||
public SpanAligner2(List<SpanBo> spans) {
|
||||
spanMap = new HashMap<Long, SpanBo>(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<SpanAlign> sort() {
|
||||
List<SpanAlign> list = new ArrayList<SpanAlign>();
|
||||
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<SpanAlign> container) {
|
||||
int depth = spanDepth + 1;
|
||||
|
||||
SpanAlign element = new SpanAlign(depth, parentSpan);
|
||||
container.add(element);
|
||||
|
||||
List<SubSpanBo> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import java.util.List;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Deprecated
|
||||
public class SpanPopulator {
|
||||
private List<SpanAlign> 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) {
|
||||
|
||||
@@ -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<SpanAlign> selectSpan(String uuid) {
|
||||
UUID id = UUID.fromString(uuid);
|
||||
List<SpanBo> spans = traceDao.selectSpanAndAnnotation(id);
|
||||
if (spans == null || spans.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@Override
|
||||
public List<SpanAlign> selectSpan(String uuid) {
|
||||
UUID id = UUID.fromString(uuid);
|
||||
List<SpanBo> spans = traceDao.selectSpanAndAnnotation(id);
|
||||
if (spans == null || spans.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<SpanAlign> order = order(spans);
|
||||
transitionApiId(order);
|
||||
transitionSqlId(order);
|
||||
// TODO root span not found시 row data라도 보여줘야 됨.
|
||||
List<SpanAlign> order = order(spans);
|
||||
transitionApiId(order);
|
||||
transitionSqlId(order);
|
||||
// TODO root span not found시 row data라도 보여줘야 됨.
|
||||
|
||||
return order;
|
||||
return order;
|
||||
}
|
||||
|
||||
}
|
||||
private void transitionAnnotation(List<SpanAlign> spans, AnnotationReplacementCallback annotationReplacementCallback) {
|
||||
for (SpanAlign spanAlign : spans) {
|
||||
List<AnnotationBo> 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<SpanAlign> spans) {
|
||||
this.transitionAnnotation(spans, new AnnotationReplacementCallback() {
|
||||
@Override
|
||||
public void replacement(SpanAlign spanAlign, List<AnnotationBo> annotationBoList) {
|
||||
AnnotationBo sqlIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.SQL_ID);
|
||||
if (sqlIdAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
private void transitionAnnotation(List<SpanAlign> spans, AnnotationReplacementCallback annotationReplacementCallback) {
|
||||
for (SpanAlign spanAlign : spans) {
|
||||
List<AnnotationBo> 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<SpanAlign> spans) {
|
||||
this.transitionAnnotation(spans, new AnnotationReplacementCallback() {
|
||||
@Override
|
||||
public void replacement(SpanAlign spanAlign, List<AnnotationBo> annotationBoList) {
|
||||
AnnotationBo sqlIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.SQL_ID);
|
||||
if (sqlIdAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
// TODO 일단 시간까지 조회는 하지 말고 하자.
|
||||
int hashCode = (Integer) sqlIdAnnotation.getValue();
|
||||
List<SqlMetaDataBo> 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<SqlMetaDataBo> 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<AnnotationBo> annotationBoList, String key) {
|
||||
for (AnnotationBo annotationBo : annotationBoList) {
|
||||
if (key.equals(annotationBo.getKey())) {
|
||||
return annotationBo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
private String collisionSqlHashCodeMessage(int hashCode, List<SqlMetaDataBo> 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<AnnotationBo> 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<SqlMetaDataBo> 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<SpanAlign> spans) {
|
||||
this.transitionAnnotation(spans, new AnnotationReplacementCallback() {
|
||||
@Override
|
||||
public void replacement(SpanAlign spanAlign, List<AnnotationBo> 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<SpanAlign> spans) {
|
||||
this.transitionAnnotation(spans, new AnnotationReplacementCallback() {
|
||||
@Override
|
||||
public void replacement(SpanAlign spanAlign, List<AnnotationBo> annotationBoList) {
|
||||
public static interface AnnotationReplacementCallback {
|
||||
void replacement(SpanAlign spanAlign, List<AnnotationBo> annotationBoList);
|
||||
}
|
||||
|
||||
AnnotationBo apiIdAnnotation = findAnnotation(annotationBoList, AnnotationNames.API_ID);
|
||||
if (apiIdAnnotation == null) {
|
||||
return;
|
||||
}
|
||||
private List<SpanAlign> order(List<SpanBo> 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<AnnotationBo> annotationBoList);
|
||||
}
|
||||
|
||||
private List<SpanAlign> order(List<SpanBo> spans) {
|
||||
SpanAligner spanAligner = new SpanAligner(spans);
|
||||
List<SpanAlign> 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<SpanAlign> populatedList = spanPopulator.populateSubSpan();
|
||||
return populatedList;
|
||||
}
|
||||
/*
|
||||
* SpanAligner spanAligner = new SpanAligner(spans); List<SpanAlign> 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<SpanAlign> populatedList = spanPopulator.populateSubSpan(); return populatedList;
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user