package com.navercorp.pinpoint.common.server.bo.serializer.trace.v2;
import com.navercorp.pinpoint.common.buffer.Buffer;
import com.navercorp.pinpoint.common.server.bo.AnnotationBo;
import com.navercorp.pinpoint.common.server.bo.BasicSpan;
import com.navercorp.pinpoint.common.server.bo.SpanBo;
import com.navercorp.pinpoint.common.server.bo.SpanChunkBo;
import com.navercorp.pinpoint.common.server.bo.SpanEventBo;
import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanBitFiled;
import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventBitField;
import com.navercorp.pinpoint.common.server.bo.serializer.trace.v2.bitfield.SpanEventQualifierBitField;
import com.navercorp.pinpoint.common.util.AnnotationTranscoder;
import com.navercorp.pinpoint.common.util.TransactionId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author Woonduk Kang(emeroad)
*/
@Component
public class SpanDecoderV0 implements SpanDecoder {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private static final AnnotationTranscoder transcoder = new AnnotationTranscoder();
@Override
public Object decode(Buffer qualifier, Buffer columnValue, SpanDecodingContext decodingContext) {
final byte type = qualifier.readByte();
if (SpanEncoder.TYPE_SPAN == type) {
SpanBo span = readSpan(qualifier, columnValue, decodingContext);
return span;
} else if (SpanEncoder.TYPE_SPAN_CHUNK == type) {
SpanChunkBo spanChunk = readSpanChunk(qualifier, columnValue, decodingContext);
return spanChunk;
} else {
logger.warn("Unknown span type {}", type);
return UNKNOWN;
}
}
private SpanChunkBo readSpanChunk(Buffer qualifier, Buffer columnValue, SpanDecodingContext decodingContext) {
final SpanChunkBo spanChunk = new SpanChunkBo();
final TransactionId transactionId = decodingContext.getTransactionId();
spanChunk.setTransactionId(transactionId);
spanChunk.setCollectorAcceptTime(decodingContext.getCollectorAcceptedTime());
SpanEventBo firstSpanEvent = readQualifier(spanChunk, qualifier);
readSpanChunkValue(columnValue, spanChunk, firstSpanEvent, decodingContext);
return spanChunk;
}
private SpanBo readSpan(Buffer qualifier, Buffer columnValue, SpanDecodingContext decodingContext) {
final SpanBo span = new SpanBo();
final TransactionId transactionId = decodingContext.getTransactionId();
span.setTransactionId(transactionId);
span.setCollectorAcceptTime(decodingContext.getCollectorAcceptedTime());
SpanEventBo firstSpanEvent = readQualifier(span, qualifier);
readSpanValue(columnValue, span, firstSpanEvent, decodingContext);
return span;
}
private void readSpanChunkValue(Buffer buffer, SpanChunkBo spanChunk, SpanEventBo firstSpanEvent, SpanDecodingContext decodingContext) {
final byte version = buffer.readByte();
if (version != 0) {
throw new IllegalStateException("unknown version :" + version);
}
spanChunk.setVersion(version);
List<SpanEventBo> spanEventBoList = readSpanEvent(buffer, firstSpanEvent, decodingContext);
spanChunk.addSpanEventBoList(spanEventBoList);
}
public void readSpanValue(Buffer buffer, SpanBo span, SpanEventBo firstSpanEvent, SpanDecodingContext decodingContext) {
final byte version = buffer.readByte();
if (version != 0) {
throw new IllegalStateException("unknown version :" + version);
}
span.setVersion(version);
final SpanBitFiled bitFiled = new SpanBitFiled(buffer.readByte());
final short serviceType = buffer.readShort();
span.setServiceType(serviceType);
switch (bitFiled.getApplicationServiceTypeEncodingStrategy()) {
case PREV_EQUALS:
span.setApplicationServiceType(serviceType);
break;
case RAW:
span.setApplicationServiceType(buffer.readShort());
break;
default:
throw new IllegalStateException("applicationServiceType");
}
if (!bitFiled.isRoot()) {
span.setParentSpanId(buffer.readLong());
} else {
span.setParentSpanId(-1);
}
final long startTimeDelta = buffer.readVLong();
final long startTime = span.getCollectorAcceptTime() - startTimeDelta;
span.setStartTime(startTime);
span.setElapsed(buffer.readVInt());
span.setRpc(buffer.readPrefixedString());
span.setEndPoint(buffer.readPrefixedString());
span.setRemoteAddr(buffer.readPrefixedString());
span.setApiId(buffer.readSVInt());
if (bitFiled.isSetErrorCode()) {
span.setErrCode(buffer.readInt());
}
if (bitFiled.isSetHasException()) {
int exceptionId = buffer.readSVInt();
String exceptionMessage = buffer.readPrefixedString();
span.setExceptionInfo(exceptionId, exceptionMessage);
}
if (bitFiled.isSetFlag()) {
span.setFlag(buffer.readShort());
}
if (bitFiled.isSetLoggingTransactionInfo()) {
span.setLoggingTransactionInfo(buffer.readByte());
}
span.setAcceptorHost(buffer.readPrefixedString());
if (bitFiled.isSetAnnotation()) {
List<AnnotationBo> annotationBoList = readAnnotationList(buffer, decodingContext);
span.setAnnotationBoList(annotationBoList);
}
List<SpanEventBo> spanEventBoList = readSpanEvent(buffer, firstSpanEvent, decodingContext);
span.addSpanEventBoList(spanEventBoList);
}
private List<SpanEventBo> readSpanEvent(Buffer buffer, SpanEventBo firstSpanEvent, SpanDecodingContext decodingContext) {
final int spanEventSize = buffer.readVInt();
if (spanEventSize <= 0) {
return new ArrayList<SpanEventBo>();
}
final List<SpanEventBo> spanEventBoList = new ArrayList<SpanEventBo>();
SpanEventBo prev = null;
for (int i = 0; i < spanEventSize; i++) {
SpanEventBo spanEvent;
if (i == 0) {
spanEvent = readFirstSpanEvent(buffer, firstSpanEvent, decodingContext);
} else {
spanEvent = readNextSpanEvent(buffer, prev, decodingContext);
}
prev = spanEvent;
spanEventBoList.add(spanEvent);
}
return spanEventBoList;
}
private SpanEventBo readNextSpanEvent(final Buffer buffer, final SpanEventBo prev, SpanDecodingContext decodingContext) {
final SpanEventBo spanEventBo = new SpanEventBo();
final SpanEventBitField bitField = new SpanEventBitField(buffer.readShort());
switch (bitField.getStartElapsedEncodingStrategy()) {
case PREV_DELTA:
int startTimeDelta = buffer.readVInt();
int startTime = startTimeDelta + prev.getStartElapsed();
spanEventBo.setStartElapsed(startTime);
break;
case PREV_EQUALS:
spanEventBo.setStartElapsed(prev.getStartElapsed());
break;
default:
throw new IllegalStateException("unsupported SequenceEncodingStrategy");
}
spanEventBo.setEndElapsed(buffer.readVInt());
switch (bitField.getSequenceEncodingStrategy()) {
case PREV_DELTA:
int sequenceDelta = buffer.readVInt();
final int sequence = sequenceDelta + prev.getSequence();
spanEventBo.setSequence((short) sequence);
break;
case PREV_ADD1:
spanEventBo.setSequence((short) (prev.getSequence() + 1));
break;
default:
throw new IllegalStateException("unsupported SequenceEncodingStrategy");
}
switch (bitField.getDepthEncodingStrategy()) {
case RAW:
spanEventBo.setDepth(buffer.readSVInt());
break;
case PREV_EQUALS:
spanEventBo.setDepth(prev.getDepth());
break;
default:
throw new IllegalStateException("unsupported DepthEncodingStrategy");
}
switch (bitField.getServiceTypeEncodingStrategy()) {
case RAW:
spanEventBo.setServiceType(buffer.readShort());
break;
case PREV_EQUALS:
spanEventBo.setServiceType(prev.getServiceType());
break;
default:
throw new IllegalStateException("unsupported ServiceTypeEncodingStrategy");
}
spanEventBo.setApiId(buffer.readSVInt());
if (bitField.isSetRpc()) {
spanEventBo.setRpc(buffer.readPrefixedString());
}
if (bitField.isSetEndPoint()) {
spanEventBo.setEndPoint(buffer.readPrefixedString());
}
if (bitField.isSetDestinationId()) {
spanEventBo.setDestinationId(buffer.readPrefixedString());
}
if (bitField.isSetNextSpanId()) {
spanEventBo.setNextSpanId(buffer.readLong());
}
if (bitField.isSetHasException()) {
int exceptionId = buffer.readSVInt();
String exceptionMessage = buffer.readPrefixedString();
spanEventBo.setExceptionInfo(exceptionId, exceptionMessage);
}
if (bitField.isSetAnnotation()) {
List<AnnotationBo> annotationBoList = readAnnotationList(buffer, decodingContext);
spanEventBo.setAnnotationBoList(annotationBoList);
}
if (bitField.isSetNextAsyncId()) {
spanEventBo.setNextAsyncId(buffer.readSVInt());
}
if (bitField.isSetAsyncId()) {
spanEventBo.setAsyncId(buffer.readInt());
spanEventBo.setAsyncSequence((short) buffer.readVInt());
}
return spanEventBo;
}
private SpanEventBo readFirstSpanEvent(Buffer buffer, SpanEventBo firstSpanEvent, SpanDecodingContext decodingContext) {
SpanEventBitField bitField = new SpanEventBitField(buffer.readByte());
firstSpanEvent.setStartElapsed(buffer.readVInt());
firstSpanEvent.setEndElapsed(buffer.readVInt());
firstSpanEvent.setSequence(buffer.readShort());
firstSpanEvent.setDepth(buffer.readSVInt());
firstSpanEvent.setServiceType(buffer.readShort());
if (bitField.isSetRpc()) {
firstSpanEvent.setRpc(buffer.readPrefixedString());
}
if (bitField.isSetEndPoint()) {
firstSpanEvent.setEndPoint(buffer.readPrefixedString());
}
if (bitField.isSetDestinationId()) {
firstSpanEvent.setDestinationId(buffer.readPrefixedString());
}
firstSpanEvent.setApiId(buffer.readSVInt());
if (bitField.isSetNextSpanId()) {
firstSpanEvent.setNextSpanId(buffer.readLong());
}
if (bitField.isSetHasException()) {
int exceptionId = buffer.readSVInt();
String exceptionMessage = buffer.readPrefixedString();
firstSpanEvent.setExceptionInfo(exceptionId, exceptionMessage);
}
if (bitField.isSetAnnotation()) {
List<AnnotationBo> annotationBoList = readAnnotationList(buffer, decodingContext);
firstSpanEvent.setAnnotationBoList(annotationBoList);
}
if (bitField.isSetNextAsyncId()) {
firstSpanEvent.setNextAsyncId(buffer.readSVInt());
}
// if (bitField.isSetAsyncId()) {
// firstSpanEvent.setAsyncId(buffer.readInt());
// firstSpanEvent.setAsyncSequence((short) buffer.readVInt());
// }
return firstSpanEvent;
}
private List<AnnotationBo> readAnnotationList(Buffer buffer, SpanDecodingContext decodingContext) {
int annotationListSize = buffer.readVInt();
List<AnnotationBo> annotationBoList = new ArrayList<AnnotationBo>(annotationListSize);
// AnnotationBo prev = decodingContext.getPrevFirstAnnotationBo();
AnnotationBo prev = null;
for (int i = 0; i < annotationListSize; i++) {
AnnotationBo current;
if (i == 0) {
current = readFirstAnnotationBo(buffer);
// save first annotation for delta bitfield
// decodingContext.setPrevFirstAnnotationBo(current);
} else {
current = readDeltaAnnotationBo(buffer, prev);
}
prev = current;
annotationBoList.add(current);
}
return annotationBoList;
}
private AnnotationBo readFirstAnnotationBo(Buffer buffer) {
AnnotationBo current;
current = new AnnotationBo();
current.setKey(buffer.readSVInt());
byte valueType = buffer.readByte();
byte[] valueBytes = buffer.readPrefixedBytes();
Object value = transcoder.decode(valueType, valueBytes);
current.setValue(value);
return current;
}
private AnnotationBo readDeltaAnnotationBo(Buffer buffer, AnnotationBo prev) {
AnnotationBo annotation = new AnnotationBo();
final int prevKey = prev.getKey();
annotation.setKey(buffer.readSVInt() + prevKey);
byte valueType = buffer.readByte();
byte[] valueBytes = buffer.readPrefixedBytes();
Object value = transcoder.decode(valueType, valueBytes);
annotation.setValue(value);
return annotation;
}
private SpanEventBo readQualifier(BasicSpan basicSpan, Buffer buffer) {
String applicationId = buffer.readPrefixedString();
basicSpan.setApplicationId(applicationId);
String agentId = buffer.readPrefixedString();
basicSpan.setAgentId(agentId);
long agentStartTime = buffer.readVLong();
basicSpan.setAgentStartTime(agentStartTime);
long spanId = buffer.readLong();
basicSpan.setSpanId(spanId);
int firstSpanEventSequence = buffer.readSVInt();
if (firstSpanEventSequence == -1) {
// buffer.readByte();
// spanEvent not exist ??
logger.warn("firstSpanEvent is null. bug!!!! firstSpanEventSequence:{}", firstSpanEventSequence);
throw new IllegalStateException("firstSpanEvent is null");
} else {
return readQualifierFirstSpanEvent(buffer);
}
}
private SpanEventBo readQualifierFirstSpanEvent(Buffer buffer) {
final SpanEventBo firstSpanEvent = new SpanEventBo();
final byte bitField = buffer.readByte();
if (SpanEventQualifierBitField.isSetAsync(bitField)) {
int asyncId = buffer.readInt();
int asyncSequence = buffer.readVInt();
firstSpanEvent.setAsyncId(asyncId);
firstSpanEvent.setAsyncSequence((short) asyncSequence);
}
return firstSpanEvent;
}
@Override
public void next(SpanDecodingContext decodingContext) {
decodingContext.next();
}
}