package com.navercorp.pinpoint.common.server.bo;
import com.navercorp.pinpoint.common.server.bo.filter.EmptySpanEventFilter;
import com.navercorp.pinpoint.common.server.bo.filter.SpanEventFilter;
import com.navercorp.pinpoint.common.server.util.AcceptedTimeService;
import com.navercorp.pinpoint.common.server.util.EmptyAcceptedTimeService;
import com.navercorp.pinpoint.common.util.AnnotationTranscoder;
import com.navercorp.pinpoint.common.util.TransactionId;
import com.navercorp.pinpoint.common.util.TransactionIdUtils;
import com.navercorp.pinpoint.thrift.dto.TAnnotation;
import com.navercorp.pinpoint.thrift.dto.TIntStringValue;
import com.navercorp.pinpoint.thrift.dto.TSpan;
import com.navercorp.pinpoint.thrift.dto.TSpanChunk;
import com.navercorp.pinpoint.thrift.dto.TSpanEvent;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Woonduk Kang(emeroad)
*/
@Component
public class SpanFactory {
private SpanEventFilter spanEventFilter = new EmptySpanEventFilter();
private AcceptedTimeService acceptedTimeService = new EmptyAcceptedTimeService();
private static final AnnotationTranscoder transcoder = new AnnotationTranscoder();
public SpanFactory() {
}
@Autowired(required = false)
public void setSpanEventFilter(SpanEventFilter spanEventFilter) {
this.spanEventFilter = spanEventFilter;
}
@Autowired(required = false)
public void setAcceptedTimeService(AcceptedTimeService acceptedTimeService) {
this.acceptedTimeService = acceptedTimeService;
}
public SpanBo buildSpanBo(TSpan tSpan) {
final SpanBo spanBo = newSpanBo(tSpan);
List<TSpanEvent> spanEventList = tSpan.getSpanEventList();
List<SpanEventBo> spanEventBoList = buildSpanEventBoList(spanEventList);
spanBo.addSpanEventBoList(spanEventBoList);
long acceptedTime = acceptedTimeService.getAcceptedTime();
spanBo.setCollectorAcceptTime(acceptedTime);
return spanBo;
}
// for test
SpanBo newSpanBo(TSpan tSpan) {
final SpanBo spanBo = new SpanBo();
spanBo.setAgentId(tSpan.getAgentId());
spanBo.setApplicationId(tSpan.getApplicationName());
spanBo.setAgentStartTime(tSpan.getAgentStartTime());
final TransactionId transactionId = newTransactionId(tSpan.getTransactionId(), spanBo);
spanBo.setTransactionId(transactionId);
spanBo.setSpanId(tSpan.getSpanId());
spanBo.setParentSpanId(tSpan.getParentSpanId());
spanBo.setStartTime(tSpan.getStartTime());
spanBo.setElapsed(tSpan.getElapsed());
spanBo.setRpc(tSpan.getRpc());
spanBo.setServiceType(tSpan.getServiceType());
spanBo.setEndPoint(tSpan.getEndPoint());
spanBo.setFlag(tSpan.getFlag());
spanBo.setApiId(tSpan.getApiId());
spanBo.setErrCode(tSpan.getErr());
spanBo.setAcceptorHost(tSpan.getAcceptorHost());
spanBo.setRemoteAddr(tSpan.getRemoteAddr());
spanBo.setLoggingTransactionInfo(tSpan.getLoggingTransactionInfo());
// FIXME (2015.03) Legacy - applicationServiceType added in v1.1.0
// applicationServiceType is not saved for older versions where applicationServiceType does not exist.
if (tSpan.isSetApplicationServiceType()) {
spanBo.setApplicationServiceType(tSpan.getApplicationServiceType());
} else {
spanBo.setApplicationServiceType(tSpan.getServiceType());
}
spanBo.setParentApplicationId(tSpan.getParentApplicationName());
spanBo.setParentApplicationServiceType(tSpan.getParentApplicationType());
// FIXME span.errCode contains error of span and spanEvent
// because exceptionInfo is the error information of span itself, exceptionInfo can be null even if errCode is not 0
final TIntStringValue exceptionInfo = tSpan.getExceptionInfo();
if (exceptionInfo != null) {
spanBo.setExceptionInfo(exceptionInfo.getIntValue(), exceptionInfo.getStringValue());
}
List<AnnotationBo> annotationBoList = buildAnnotationList(tSpan.getAnnotations());
spanBo.setAnnotationBoList(annotationBoList);
return spanBo;
}
private void bind(SpanEventBo spanEvent, TSpanEvent tSpanEvent) {
spanEvent.setSequence(tSpanEvent.getSequence());
spanEvent.setStartElapsed(tSpanEvent.getStartElapsed());
spanEvent.setEndElapsed(tSpanEvent.getEndElapsed());
spanEvent.setRpc(tSpanEvent.getRpc());
spanEvent.setServiceType(tSpanEvent.getServiceType());
spanEvent.setDestinationId(tSpanEvent.getDestinationId());
spanEvent.setEndPoint(tSpanEvent.getEndPoint());
spanEvent.setApiId(tSpanEvent.getApiId());
if (tSpanEvent.isSetDepth()) {
spanEvent.setDepth(tSpanEvent.getDepth());
}
if (tSpanEvent.isSetNextSpanId()) {
spanEvent.setNextSpanId(tSpanEvent.getNextSpanId());
}
List<AnnotationBo> annotationList = buildAnnotationList(tSpanEvent.getAnnotations());
spanEvent.setAnnotationBoList(annotationList);
final TIntStringValue exceptionInfo = tSpanEvent.getExceptionInfo();
if (exceptionInfo != null) {
spanEvent.setExceptionInfo(exceptionInfo.getIntValue(), exceptionInfo.getStringValue());
}
if (tSpanEvent.isSetAsyncId()) {
spanEvent.setAsyncId(tSpanEvent.getAsyncId());
}
if (tSpanEvent.isSetNextAsyncId()) {
spanEvent.setNextAsyncId(tSpanEvent.getNextAsyncId());
}
if (tSpanEvent.isSetAsyncSequence()) {
spanEvent.setAsyncSequence(tSpanEvent.getAsyncSequence());
}
}
public SpanChunkBo buildSpanChunkBo(TSpanChunk tSpanChunk) {
final SpanChunkBo spanChunkBo = newSpanChunkBo(tSpanChunk);
List<TSpanEvent> spanEventList = tSpanChunk.getSpanEventList();
List<SpanEventBo> spanEventBoList = buildSpanEventBoList(spanEventList);
spanChunkBo.addSpanEventBoList(spanEventBoList);
long acceptedTime = acceptedTimeService.getAcceptedTime();
spanChunkBo.setCollectorAcceptTime(acceptedTime);
return spanChunkBo;
}
// for test
SpanChunkBo newSpanChunkBo(TSpanChunk tSpanChunk) {
final SpanChunkBo spanChunkBo = new SpanChunkBo();
spanChunkBo.setAgentId(tSpanChunk.getAgentId());
spanChunkBo.setApplicationId(tSpanChunk.getApplicationName());
spanChunkBo.setAgentStartTime(tSpanChunk.getAgentStartTime());
spanChunkBo.setServiceType(tSpanChunk.getServiceType());
if (tSpanChunk.isSetApplicationServiceType()) {
spanChunkBo.setApplicationServiceType(tSpanChunk.getApplicationServiceType());
} else {
spanChunkBo.setApplicationServiceType(tSpanChunk.getServiceType());
}
TransactionId transactionId = newTransactionId(tSpanChunk.getTransactionId(), spanChunkBo);
spanChunkBo.setTransactionId(transactionId);
spanChunkBo.setSpanId(tSpanChunk.getSpanId());
spanChunkBo.setEndPoint(tSpanChunk.getEndPoint());
return spanChunkBo;
}
private TransactionId newTransactionId(byte[] transactionIdBytes, BasicSpan basicSpan) {
final TransactionId transactionId = TransactionIdUtils.parseTransactionId(transactionIdBytes);
String transactionAgentId = transactionId.getAgentId();
if (transactionAgentId != null) {
return transactionId;
}
String spanAgentId = basicSpan.getAgentId();
return new TransactionId(spanAgentId, transactionId.getAgentStartTime(), transactionId.getTransactionSequence());
}
private List<SpanEventBo> buildSpanEventBoList(List<TSpanEvent> spanEventList) {
if (CollectionUtils.isEmpty(spanEventList)) {
return new ArrayList<SpanEventBo>();
}
List<SpanEventBo> spanEventBoList = new ArrayList<SpanEventBo>(spanEventList.size());
for (TSpanEvent tSpanEvent : spanEventList) {
final SpanEventBo spanEventBo = buildSpanEventBo(tSpanEvent);
if (!spanEventFilter.filter(spanEventBo)) {
continue;
}
spanEventBoList.add(spanEventBo);
}
Collections.sort(spanEventBoList, SpanEventComparator.INSTANCE);
return spanEventBoList;
}
private List<AnnotationBo> buildAnnotationList(List<TAnnotation> tAnnotationList) {
if (tAnnotationList == null) {
return new ArrayList<AnnotationBo>();
}
List<AnnotationBo> boList = new ArrayList<AnnotationBo>(tAnnotationList.size());
for (TAnnotation tAnnotation : tAnnotationList) {
final AnnotationBo annotationBo = newAnnotationBo(tAnnotation);
boList.add(annotationBo);
}
Collections.sort(boList, AnnotationComparator.INSTANCE);
return boList;
}
// for test
public SpanEventBo buildSpanEventBo(TSpanEvent tSpanEvent) {
if (tSpanEvent == null) {
throw new NullPointerException("tSpanEvent must not be null");
}
final SpanEventBo spanEvent = new SpanEventBo();
bind(spanEvent, tSpanEvent);
return spanEvent;
}
private AnnotationBo newAnnotationBo(TAnnotation tAnnotation) {
if (tAnnotation == null) {
throw new NullPointerException("annotation must not be null");
}
AnnotationBo annotationBo = new AnnotationBo();
annotationBo.setKey(tAnnotation.getKey());
Object value = transcoder.getMappingValue(tAnnotation);
annotationBo.setValue(value);
return annotationBo;
}
}