package com.yirendai.infra.cicada.service;
import com.jcabi.aspects.Loggable;
import com.yirendai.infra.cicada.constants.AnnotationType;
import com.yirendai.infra.cicada.entity.SpanEntity;
import com.yirendai.infra.cicada.entity.model.AnnotationModel;
import com.yirendai.infra.cicada.entity.model.SpanModel;
import com.yirendai.infra.cicada.repository.AnnotationRepository;
import com.yirendai.infra.cicada.repository.SpanRepository;
import com.yirendai.infra.cicada.resource.RegisterInfoResource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
@Component
@Loggable
public class TraceService {
// private static final Logger LOG = LoggerFactory.getLogger(TraceService.class);
@Autowired
SpanRepository spanRepo;
@Autowired
AnnotationRepository annoRepo;
@Autowired
AppManagerService appManager;
/**
* <p>
* 计算spanEntity的durationClient 并将cs cr 从返回的AnnotationModel列表中删除 .
* 对annotationModel列表中的时间按照时间戳排序.
* </p>
*/
private final Set<String> excludeAnnotations;
public TraceService() {
excludeAnnotations = new HashSet<String>();
excludeAnnotations.add(AnnotationType.CLIENT_SEND.name());
excludeAnnotations.add(AnnotationType.SERVER_SEND.name());
excludeAnnotations.add(AnnotationType.CLIENT_RECEIVE.name());
excludeAnnotations.add(AnnotationType.SERVER_RECEIVE.name());
}
/**
* 根据traceId获取整个调用链的信息.
*/
public List<SpanEntity> fetchTraceChain(final String traceId) {
final List<SpanEntity> results = new LinkedList<SpanEntity>();
final List<SpanModel> spanModels = spanRepo.getTraceSpanModels(traceId);
for (final SpanModel model : spanModels) {
// 根据TraceId和SpanId获取annotation链
final List<AnnotationModel> annoModels = annoRepo.getSpanAnnotations(traceId, model.getId());
final RegisterInfoResource registerInfo = appManager.getRegisterInfo(model.getMethodId());
results.add(genSpanModel(model, registerInfo, annoModels));
}
// 排序
Collections.sort(results);
return results;
}
private SpanEntity genSpanModel(final SpanModel model, final RegisterInfoResource registerInfo,
final List<AnnotationModel> annoModels) {
final SpanEntity entity = new SpanEntity();
BeanUtils.copyProperties(model, entity);
entity.setAppName(registerInfo.getAppName());
entity.setServiceName(registerInfo.getServiceName());
entity.setMethodName(registerInfo.getMethodName());
entity.setAnnotations(annoModels);
wash(entity);
return entity;
}
private void wash(final SpanEntity span) {
long cr = -1;
long cs = -1;
final ListIterator<AnnotationModel> iter = span.getAnnotations().listIterator();
while (iter.hasNext()) {
final AnnotationModel anno = iter.next();
final String annoType = anno.getType();
if (excludeAnnotations.contains(annoType)) {
if (AnnotationType.CLIENT_SEND.name().equals(annoType)) {
cs = anno.getTimestamp();
}
if (AnnotationType.CLIENT_RECEIVE.name().equals(annoType)) {
cr = anno.getTimestamp();
}
iter.remove();
}
}
if (cr != -1 && cs != -1) {
span.setDurationClient((int) (cr - cs));
}
Collections.sort(span.getAnnotations(), new Comparator<AnnotationModel>() {
public int compare(final AnnotationModel anno1, final AnnotationModel anno2) {
return (int) (anno1.getTimestamp() - anno2.getTimestamp());
}
});
}
}