package com.navercorp.pinpoint.common.server.bo.serializer.trace.v2; import com.navercorp.pinpoint.common.buffer.AutomaticBuffer; import com.navercorp.pinpoint.common.buffer.Buffer; import com.navercorp.pinpoint.common.server.bo.AnnotationBo; 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 org.apache.commons.collections.CollectionUtils; import org.springframework.stereotype.Component; import java.nio.ByteBuffer; import java.util.List; /** * @author Woonduk Kang(emeroad) */ @Component public class SpanEncoderV0 implements SpanEncoder { private static final AnnotationTranscoder transcoder = new AnnotationTranscoder(); @Override public ByteBuffer encodeSpanQualifier(SpanEncodingContext<SpanBo> encodingContext) { final SpanBo spanBo = encodingContext.getValue(); final List<SpanEventBo> spanEventBoList = spanBo.getSpanEventBoList(); final SpanEventBo firstEvent = getFirstSpanEvent(spanEventBoList); return encodeQualifier(TYPE_SPAN, spanBo.getApplicationId(), spanBo.getAgentId(), spanBo.getAgentStartTime(), spanBo.getSpanId(), firstEvent); } @Override public ByteBuffer encodeSpanChunkQualifier(SpanEncodingContext<SpanChunkBo> encodingContext) { final SpanChunkBo spanChunkBo = encodingContext.getValue(); final List<SpanEventBo> spanEventBoList = spanChunkBo.getSpanEventBoList(); final SpanEventBo firstEvent = getFirstSpanEvent(spanEventBoList); return encodeQualifier(TYPE_SPAN_CHUNK, spanChunkBo.getApplicationId(), spanChunkBo.getAgentId(), spanChunkBo.getAgentStartTime(), spanChunkBo.getSpanId(), firstEvent); } private ByteBuffer encodeQualifier(byte type, String applicationId, String agentId, long agentStartTime, long spanId, SpanEventBo firstEvent) { final Buffer buffer = new AutomaticBuffer(128); buffer.putByte(type); buffer.putPrefixedString(applicationId); buffer.putPrefixedString(agentId); buffer.putVLong(agentStartTime); buffer.putLong(spanId); if (firstEvent != null) { buffer.putSVInt(firstEvent.getSequence()); final byte bitField = SpanEventQualifierBitField.buildBitField(firstEvent); buffer.putByte(bitField); // case : async span if (SpanEventQualifierBitField.isSetAsync(bitField)) { buffer.putInt(firstEvent.getAsyncId()); buffer.putVInt(firstEvent.getAsyncSequence()); } } else { // simple trace case // buffer.putSVInt((short) -1); // byte cfBitField = SpanEventQualifierBitField.setAsync((byte) 0, false); // buffer.putByte(cfBitField); } return buffer.wrapByteBuffer(); } private SpanEventBo getFirstSpanEvent(List<SpanEventBo> spanEventBoList) { if (CollectionUtils.isEmpty(spanEventBoList)) { return null; } return spanEventBoList.get(0); } @Override public ByteBuffer encodeSpanChunkColumnValue(SpanEncodingContext<SpanChunkBo> encodingContext) { final SpanChunkBo spanChunkBo = encodingContext.getValue(); final Buffer buffer = new AutomaticBuffer(256); final byte version = spanChunkBo.getVersion(); buffer.putByte(version); final List<SpanEventBo> spanEventBoList = spanChunkBo.getSpanEventBoList(); writeSpanEventList(buffer, spanEventBoList, encodingContext); return buffer.wrapByteBuffer(); } private void writeSpanEventList(Buffer buffer, List<SpanEventBo> spanEventBoList, SpanEncodingContext<?> encodingContext) { if (CollectionUtils.isEmpty(spanEventBoList)) { buffer.putVInt(0); } else { buffer.putVInt(spanEventBoList.size()); SpanEventBo prevSpanEvent = null; for (SpanEventBo spanEventBo : spanEventBoList) { if (prevSpanEvent == null) { writeFirstSpanEvent(buffer, spanEventBo, encodingContext); } else { writeNextSpanEvent(buffer, spanEventBo, prevSpanEvent, encodingContext); } prevSpanEvent = spanEventBo; } } } @Override public ByteBuffer encodeSpanColumnValue(SpanEncodingContext<SpanBo> encodingContext) { final SpanBo span = encodingContext.getValue(); final SpanBitFiled bitField = SpanBitFiled.build(span); final Buffer buffer = new AutomaticBuffer(256); final byte version = span.getRawVersion(); buffer.putByte(version); // bit field buffer.putByte(bitField.getBitField()); final short serviceType = span.getServiceType(); buffer.putShort(serviceType); switch (bitField.getApplicationServiceTypeEncodingStrategy()) { case PREV_EQUALS: break; case RAW: buffer.putShort(span.getApplicationServiceType()); break; default: throw new IllegalStateException("applicationServiceType"); } // insert for rowkey // buffer.put(spanID); if (!bitField.isRoot()) { buffer.putLong(span.getParentSpanId()); } // prevSpanEvent coding final long startTime = span.getStartTime(); final long startTimeDelta = span.getCollectorAcceptTime() - startTime; buffer.putVLong(startTimeDelta); buffer.putVInt(span.getElapsed()); buffer.putPrefixedString(span.getRpc()); buffer.putPrefixedString(span.getEndPoint()); buffer.putPrefixedString(span.getRemoteAddr()); buffer.putSVInt(span.getApiId()); // BIT flag if (bitField.isSetErrorCode()) { buffer.putInt(span.getErrCode()); } if (bitField.isSetHasException()) { buffer.putSVInt(span.getExceptionId()); buffer.putPrefixedString(span.getExceptionMessage()); } if (bitField.isSetFlag()) { buffer.putShort(span.getFlag()); } if (bitField.isSetLoggingTransactionInfo()) { buffer.putByte(span.getLoggingTransactionInfo()); } buffer.putPrefixedString(span.getAcceptorHost()); if (bitField.isSetAnnotation()) { List<AnnotationBo> annotationBoList = span.getAnnotationBoList(); writeAnnotationList(buffer, annotationBoList, encodingContext); } final List<SpanEventBo> spanEventBoList = span.getSpanEventBoList(); writeSpanEventList(buffer, spanEventBoList, encodingContext); return buffer.wrapByteBuffer(); } public void writeFirstSpanEvent(Buffer buffer, SpanEventBo spanEventBo, SpanEncodingContext<?> encodingContext) { final SpanEventBitField bitField = SpanEventBitField.buildFirst(spanEventBo); final byte firstSpanBitField1 = (byte) bitField.getBitField(); buffer.putByte(firstSpanBitField1); buffer.putVInt(spanEventBo.getStartElapsed()); buffer.putVInt(spanEventBo.getEndElapsed()); buffer.putShort(spanEventBo.getSequence()); buffer.putSVInt(spanEventBo.getDepth()); buffer.putShort(spanEventBo.getServiceType()); if (bitField.isSetRpc()) { buffer.putPrefixedString(spanEventBo.getRpc()); } if (bitField.isSetEndPoint()) { buffer.putPrefixedString(spanEventBo.getEndPoint()); } if (bitField.isSetDestinationId()) { buffer.putPrefixedString(spanEventBo.getDestinationId()); } buffer.putSVInt(spanEventBo.getApiId()); if (bitField.isSetNextSpanId()) { buffer.putLong(spanEventBo.getNextSpanId()); } if (bitField.isSetHasException()) { buffer.putSVInt(spanEventBo.getExceptionId()); buffer.putPrefixedString(spanEventBo.getExceptionMessage()); } if (bitField.isSetAnnotation()) { final List<AnnotationBo> annotationBoList = spanEventBo.getAnnotationBoList(); writeAnnotationList(buffer, annotationBoList, encodingContext); } if (bitField.isSetNextAsyncId()) { buffer.putSVInt(spanEventBo.getNextAsyncId()); } // if (bitField.isSetAsyncId()) { // buffer.putInt(spanEventBo.getAsyncId()); // buffer.putVInt(spanEventBo.getAsyncSequence()); // } } public void writeNextSpanEvent(Buffer buffer, SpanEventBo spanEventBo, SpanEventBo prevSpanEvent, SpanEncodingContext<?> encodingContext) { final SpanEventBitField bitField = SpanEventBitField.build(spanEventBo, prevSpanEvent); buffer.putShort(bitField.getBitField()); switch (bitField.getStartElapsedEncodingStrategy()) { case PREV_DELTA: final int startTimeDelta = spanEventBo.getStartElapsed() - prevSpanEvent.getStartElapsed(); buffer.putVInt(startTimeDelta); break; case PREV_EQUALS: // skip bitfield break; default: throw new IllegalStateException("unsupported StartElapsedEncodingStrategy"); } buffer.putVInt(spanEventBo.getEndElapsed()); switch (bitField.getSequenceEncodingStrategy()) { case PREV_DELTA: final int sequenceDelta = spanEventBo.getSequence() - prevSpanEvent.getSequence(); buffer.putVInt(sequenceDelta); break; case PREV_ADD1: // skip bitfield break; default: throw new IllegalStateException("unsupported SequenceEncodingStrategy"); } switch (bitField.getDepthEncodingStrategy()) { case RAW: buffer.putSVInt(spanEventBo.getDepth()); break; case PREV_EQUALS: // skip bitfield break; default: throw new IllegalStateException("unsupported DepthEncodingStrategy"); } switch (bitField.getServiceTypeEncodingStrategy()) { case RAW: buffer.putShort(spanEventBo.getServiceType()); break; case PREV_EQUALS: // skip bitfield break; default: throw new IllegalStateException("unsupported ServiceTypeEncodingStrategy"); } buffer.putSVInt(spanEventBo.getApiId()); if (bitField.isSetRpc()) { buffer.putPrefixedString(spanEventBo.getRpc()); } if (bitField.isSetEndPoint()) { buffer.putPrefixedString(spanEventBo.getEndPoint()); } if (bitField.isSetDestinationId()) { buffer.putPrefixedString(spanEventBo.getDestinationId()); } if (bitField.isSetNextSpanId()) { buffer.putLong(spanEventBo.getNextSpanId()); } if (bitField.isSetHasException()) { buffer.putSVInt(spanEventBo.getExceptionId()); buffer.putPrefixedString(spanEventBo.getExceptionMessage()); } if (bitField.isSetAnnotation()) { List<AnnotationBo> annotationBoList = spanEventBo.getAnnotationBoList(); writeAnnotationList(buffer, annotationBoList, encodingContext); } if (bitField.isSetNextAsyncId()) { buffer.putSVInt(spanEventBo.getNextAsyncId()); } if (bitField.isSetAsyncId()) { buffer.putInt(spanEventBo.getAsyncId()); buffer.putVInt(spanEventBo.getAsyncSequence()); } } private void writeAnnotationList(Buffer buffer, List<AnnotationBo> annotationBoList, SpanEncodingContext<?> encodingContext) { if (CollectionUtils.isEmpty(annotationBoList)) { return; } buffer.putVInt(annotationBoList.size()); // AnnotationBo prev = encodingCtx.getPrevFirstAnnotationBo(); AnnotationBo prev = null; for (int i = 0; i < annotationBoList.size(); i++) { final AnnotationBo current = annotationBoList.get(i); // first row if (i == 0) { // first annotation buffer.putSVInt(current.getKey()); Object value = current.getValue(); byte valueTypeCode = transcoder.getTypeCode(value); byte[] valueBytes = transcoder.encode(value, valueTypeCode); buffer.putByte(valueTypeCode); buffer.putPrefixedBytes(valueBytes); // else { // writeDeltaAnnotationBo(buffer, prev, current); // } // save first annotation // encodingCtx.setPrevFirstAnnotationBo(current); } else { writeDeltaAnnotationBo(buffer, prev, current); } prev = current; } } private void writeDeltaAnnotationBo(Buffer buffer, AnnotationBo prev, AnnotationBo current) { // prev : -30 cur: -20 = -20 - - 30 = 10 // prev : 20 cur: 100 = 100 - 20 = 80 // prev : -40 cur: 1000 = 1000 + 40 = 10040 final int prevKey = prev.getKey(); final int currentKey = current.getKey(); buffer.putSVInt(currentKey - prevKey); Object value = current.getValue(); byte valueTypeCode = transcoder.getTypeCode(value); byte[] valueBytes = transcoder.encode(value, valueTypeCode); buffer.putByte(valueTypeCode); buffer.putPrefixedBytes(valueBytes); } }