zipkin2.reporter.brave.internal.ZipkinProto3Fields Maven / Gradle / Ivy
Show all versions of zipkin-reporter-brave Show documentation
/*
 * Copyright The OpenZipkin Authors
 * SPDX-License-Identifier: Apache-2.0
 */
package zipkin2.reporter.brave.internal;
import brave.Tag;
import brave.handler.MutableSpan;
import zipkin2.reporter.brave.internal.Proto3Fields.BooleanField;
import zipkin2.reporter.brave.internal.Proto3Fields.IPv4Field;
import zipkin2.reporter.brave.internal.Proto3Fields.IPv6Field;
import zipkin2.reporter.brave.internal.Proto3Fields.Utf8Field;
import zipkin2.reporter.internal.Nullable;
import static zipkin2.reporter.brave.internal.Proto3Fields.Fixed64Field;
import static zipkin2.reporter.brave.internal.Proto3Fields.HexField;
import static zipkin2.reporter.brave.internal.Proto3Fields.LengthDelimitedField;
import static zipkin2.reporter.brave.internal.Proto3Fields.VarintField;
import static zipkin2.reporter.brave.internal.Proto3Fields.WIRETYPE_FIXED64;
import static zipkin2.reporter.brave.internal.Proto3Fields.WIRETYPE_LENGTH_DELIMITED;
import static zipkin2.reporter.brave.internal.Proto3Fields.WIRETYPE_VARINT;
import static zipkin2.reporter.brave.internal.Proto3Fields.sizeOfLengthDelimitedField;
/**
 * Stripped version of {@linkplain zipkin2.internal.Proto3ZipkinFields}, without decoding logic.
 *
 * Also, brave has no structs for things like annotations or endpoints, so we have to flatten
 * some logic.
 *
 * 
Finally, brave has more involved error logic, so this logic was derived from
 * {@link brave.internal.codec.ZipkinV2JsonWriter}.
 */
//@Immutable
final class ZipkinProto3Fields {
  static class EndpointField extends Proto3Fields.Field {
    static final int SERVICE_NAME_KEY = (1 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int IPV4_KEY = (2 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int IPV6_KEY = (3 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int PORT_KEY = (4 << 3) | WIRETYPE_VARINT;
    static final Utf8Field SERVICE_NAME = new Utf8Field(SERVICE_NAME_KEY);
    static final IPv4Field IPV4 = new IPv4Field(IPV4_KEY);
    static final IPv6Field IPV6 = new IPv6Field(IPV6_KEY);
    static final VarintField PORT = new VarintField(PORT_KEY);
    EndpointField(int key) {
      super(key);
      assert wireType == WIRETYPE_LENGTH_DELIMITED;
    }
    int sizeInBytes(@Nullable String serviceName, @Nullable String ip, int port) {
      int sizeOfValue = sizeOfValue(serviceName, ip, port);
      // size is possibly zero, so don't write an empty field!
      return sizeOfValue > 0 ? sizeOfLengthDelimitedField(sizeOfValue) : 0;
    }
    static int sizeOfValue(@Nullable String serviceName, @Nullable String ip, int port) {
      int sizeInBytes = 0;
      sizeInBytes += SERVICE_NAME.sizeInBytes(serviceName);
      // MutableSpan unwraps any Ipv4 from a mapped or compatability mode IPv6.
      if (ip != null && ip.indexOf('.') != -1) {
        sizeInBytes += IPV4.sizeInBytes(ip);
      } else {
        sizeInBytes += IPV6.sizeInBytes(ip);
      }
      sizeInBytes += PORT.sizeInBytes(port);
      return sizeInBytes;
    }
    void write(WriteBuffer b, @Nullable String serviceName, @Nullable String ip, int port) {
      int sizeOfValue = sizeOfValue(serviceName, ip, port);
      if (sizeOfValue == 0) return; // special-case empty endpoint
      b.writeByte(key);
      b.writeVarint(sizeOfValue); // length prefix
      SERVICE_NAME.write(b, serviceName);
      // MutableSpan unwraps any Ipv4 from a mapped or compatability mode IPv6.
      if (ip != null && ip.indexOf('.') != -1) {
        IPV4.write(b, ip);
      } else {
        IPV6.write(b, ip);
      }
      PORT.write(b, port);
    }
  }
  static class AnnotationField extends Proto3Fields.Field {
    static final int TIMESTAMP_KEY = (1 << 3) | WIRETYPE_FIXED64;
    static final int VALUE_KEY = (2 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final Fixed64Field TIMESTAMP = new Fixed64Field(TIMESTAMP_KEY);
    static final Utf8Field VALUE = new Utf8Field(VALUE_KEY);
    AnnotationField(int key) {
      super(key);
      assert wireType == WIRETYPE_LENGTH_DELIMITED;
    }
    int sizeInBytes(long timestamp, String value) {
      int sizeOfValue = sizeOfValue(timestamp, value);
      return sizeOfLengthDelimitedField(sizeOfValue);
    }
    static int sizeOfValue(long timestamp, String value) {
      return TIMESTAMP.sizeInBytes(timestamp) + VALUE.sizeInBytes(value);
    }
    final void write(WriteBuffer b, long timestamp, String value) {
      int sizeOfValue = sizeOfValue(timestamp, value);
      b.writeByte(key);
      b.writeVarint(sizeOfValue); // length prefix
      TIMESTAMP.write(b, timestamp);
      VALUE.write(b, value);
    }
  }
  static final class TagField extends Proto3Fields.Field {
    // map in proto is a special field with key, value
    static final int KEY_KEY = (1 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int VALUE_KEY = (2 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final Utf8Field KEY = new Utf8Field(KEY_KEY);
    static final Utf8Field VALUE = new Utf8Field(VALUE_KEY);
    TagField(int key) {
      super(key);
      assert wireType == WIRETYPE_LENGTH_DELIMITED;
    }
    int sizeInBytes(String key, String value) {
      int sizeInBytes = sizeOfValue(key, value);
      return sizeOfLengthDelimitedField(sizeInBytes);
    }
    static int sizeOfValue(String key, String value) {
      return KEY.sizeInBytes(key) + VALUE.sizeInBytes(value);
    }
    void write(WriteBuffer b, String key, String value) {
      if (value == null) return;
      int sizeOfValue = sizeOfValue(key, value);
      b.writeByte(this.key);
      b.writeVarint(sizeOfValue); // length prefix
      KEY.write(b, key);
      VALUE.write(b, value);
    }
  }
  /** This is the only field in the ListOfSpans type */
  static class SpanField extends LengthDelimitedField {
    static final int TRACE_ID_KEY = (1 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int PARENT_ID_KEY = (2 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int ID_KEY = (3 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int KIND_KEY = (4 << 3) | WIRETYPE_VARINT;
    static final int NAME_KEY = (5 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int TIMESTAMP_KEY = (6 << 3) | WIRETYPE_FIXED64;
    static final int DURATION_KEY = (7 << 3) | WIRETYPE_VARINT;
    static final int LOCAL_ENDPOINT_KEY = (8 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int REMOTE_ENDPOINT_KEY = (9 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int ANNOTATION_KEY = (10 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int TAG_KEY = (11 << 3) | WIRETYPE_LENGTH_DELIMITED;
    static final int DEBUG_KEY = (12 << 3) | WIRETYPE_VARINT;
    static final int SHARED_KEY = (13 << 3) | WIRETYPE_VARINT;
    static final HexField TRACE_ID = new HexField(TRACE_ID_KEY);
    static final HexField PARENT_ID = new HexField(PARENT_ID_KEY);
    static final HexField ID = new HexField(ID_KEY);
    static final VarintField KIND = new VarintField(KIND_KEY);
    static final Utf8Field NAME = new Utf8Field(NAME_KEY);
    static final Fixed64Field TIMESTAMP = new Fixed64Field(TIMESTAMP_KEY);
    static final VarintField DURATION = new VarintField(DURATION_KEY);
    static final EndpointField LOCAL_ENDPOINT = new EndpointField(LOCAL_ENDPOINT_KEY);
    static final EndpointField REMOTE_ENDPOINT = new EndpointField(REMOTE_ENDPOINT_KEY);
    static final AnnotationField ANNOTATION = new AnnotationField(ANNOTATION_KEY);
    static final TagField TAG = new TagField(TAG_KEY);
    static final BooleanField DEBUG = new BooleanField(DEBUG_KEY);
    static final BooleanField SHARED = new BooleanField(SHARED_KEY);
    final Tag errorTag;
    SpanField(Tag errorTag) {
      super((1 << 3) | WIRETYPE_LENGTH_DELIMITED);
      if (errorTag == null) throw new NullPointerException("errorTag == null");
      this.errorTag = errorTag;
    }
    @Override int sizeOfValue(MutableSpan span) {
      int sizeInBytes = TRACE_ID.sizeInBytes(span.traceId());
      sizeInBytes += PARENT_ID.sizeInBytes(span.parentId());
      sizeInBytes += ID.sizeInBytes(span.id());
      sizeInBytes += KIND.sizeInBytes(span.kind() != null ? 1 : 0);
      sizeInBytes += NAME.sizeInBytes(span.name());
      if (span.startTimestamp() != 0L) {
        sizeInBytes += TIMESTAMP.sizeInBytes(span.startTimestamp());
        if (span.finishTimestamp() != 0L) {
          sizeInBytes += DURATION.sizeInBytes(span.finishTimestamp() - span.startTimestamp());
        }
      }
      sizeInBytes +=
        LOCAL_ENDPOINT.sizeInBytes(span.localServiceName(), span.localIp(), span.localPort());
      sizeInBytes +=
        REMOTE_ENDPOINT.sizeInBytes(span.remoteServiceName(), span.remoteIp(), span.remotePort());
      int annotationLength = span.annotationCount();
      for (int i = 0; i < annotationLength; i++) {
        sizeInBytes +=
          ANNOTATION.sizeInBytes(span.annotationTimestampAt(i), span.annotationValueAt(i));
      }
      int tagCount = span.tagCount();
      String errorValue = errorTag.value(span.error(), null);
      String errorTagName = errorValue != null ? errorTag.key() : null;
      boolean writeError = errorTagName != null;
      if (tagCount > 0 || writeError) {
        for (int i = 0; i < tagCount; i++) {
          String key = span.tagKeyAt(i);
          if (writeError && key.equals(errorTagName)) writeError = false;
          sizeInBytes += TAG.sizeInBytes(key, span.tagValueAt(i));
        }
        if (writeError) {
          sizeInBytes += TAG.sizeInBytes(errorTagName, errorValue);
        }
      }
      sizeInBytes += DEBUG.sizeInBytes(Boolean.TRUE.equals(span.debug()));
      sizeInBytes += SHARED.sizeInBytes(Boolean.TRUE.equals(span.shared()));
      return sizeInBytes;
    }
    @Override void writeValue(WriteBuffer b, MutableSpan span) {
      TRACE_ID.write(b, span.traceId());
      PARENT_ID.write(b, span.parentId());
      ID.write(b, span.id());
      KIND.write(b, toByte(span.kind()));
      NAME.write(b, span.name());
      if (span.startTimestamp() != 0L) {
        TIMESTAMP.write(b, span.startTimestamp());
        if (span.finishTimestamp() != 0L) {
          DURATION.write(b, span.finishTimestamp() - span.startTimestamp());
        }
      }
      LOCAL_ENDPOINT.write(b, span.localServiceName(), span.localIp(), span.localPort());
      REMOTE_ENDPOINT.write(b, span.remoteServiceName(), span.remoteIp(), span.remotePort());
      int annotationLength = span.annotationCount();
      for (int i = 0; i < annotationLength; i++) {
        ANNOTATION.write(b, span.annotationTimestampAt(i), span.annotationValueAt(i));
      }
      int tagCount = span.tagCount();
      String errorValue = errorTag.value(span.error(), null);
      String errorTagName = errorValue != null ? errorTag.key() : null;
      boolean writeError = errorTagName != null;
      if (tagCount > 0 || writeError) {
        for (int i = 0; i < tagCount; i++) {
          String key = span.tagKeyAt(i);
          if (writeError && key.equals(errorTagName)) writeError = false;
          TAG.write(b, key, span.tagValueAt(i));
        }
        if (writeError) {
          TAG.write(b, errorTagName, errorValue);
        }
      }
      SpanField.DEBUG.write(b, Boolean.TRUE.equals(span.debug()));
      SpanField.SHARED.write(b, Boolean.TRUE.equals(span.shared()));
    }
    // in java, there's no zero index for unknown
    int toByte(brave.Span.Kind kind) {
      return kind != null ? kind.ordinal() + 1 : 0;
    }
  }
}