/**
* Copyright 2015-2016 The OpenZipkin Authors
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package zipkin;
import java.util.Arrays;
import zipkin.internal.Nullable;
import zipkin.internal.Util;
import static zipkin.internal.Util.checkNotNull;
import static zipkin.internal.Util.equal;
/**
* Binary annotations are tags applied to a Span to give it context. For example, a binary
* annotation of {@link TraceKeys#HTTP_PATH "http.path"} could the path to a resource in a RPC call.
*
* <p>Binary annotations of type {@link Type#STRING} are always queryable, though more a historical
* implementation detail than a structural concern.
*
* <p>Binary annotations can repeat, and vary on the host. Similar to Annotation, the host
* indicates who logged the event. This allows you to tell the difference between the client and
* server side of the same key. For example, the key "http.path" might be different on the client and
* server side due to rewriting, like "/api/v1/myresource" vs "/myresource. Via the host field, you
* can see the different points of view, which often help in debugging.
*/
public final class BinaryAnnotation implements Comparable<BinaryAnnotation> {
/** A subset of thrift base types, except BYTES. */
public enum Type {
/**
* Set to 0x01 when {@link BinaryAnnotation#key} is {@link Constants#CLIENT_ADDR} or {@link
* Constants#SERVER_ADDR}
*/
BOOL(0),
/** No encoding, or type is unknown. */
BYTES(1),
I16(2),
I32(3),
I64(4),
DOUBLE(5),
/** The only type zipkin v1 supports search against. */
STRING(6);
public final int value;
Type(int value) {
this.value = value;
}
/** Returns {@link Type#BYTES} if unknown. */
public static Type fromValue(int value) {
switch (value) {
case 0:
return BOOL;
case 1:
return BYTES;
case 2:
return I16;
case 3:
return I32;
case 4:
return I64;
case 5:
return DOUBLE;
case 6:
return STRING;
default:
return BYTES;
}
}
}
/**
* Special-cased form supporting {@link Constants#CLIENT_ADDR} and
* {@link Constants#SERVER_ADDR}.
*
* @param key {@link Constants#CLIENT_ADDR} or {@link Constants#SERVER_ADDR}
* @param endpoint associated endpoint.
*/
public static BinaryAnnotation address(String key, Endpoint endpoint) {
return new BinaryAnnotation(key, new byte[]{1}, Type.BOOL, checkNotNull(endpoint, "endpoint"));
}
/** String values are the only queryable type of binary annotation. */
public static BinaryAnnotation create(String key, String value, @Nullable Endpoint endpoint) {
return new BinaryAnnotation(key, value.getBytes(Util.UTF_8), Type.STRING, endpoint);
}
public static BinaryAnnotation create(String key, byte[] value, Type type, @Nullable Endpoint endpoint) {
return new BinaryAnnotation(key, value, type, endpoint);
}
/**
* Name used to lookup spans, such as {@link TraceKeys#HTTP_PATH "http.path"} or {@link
* Constants#ERROR "error"}
*/
public final String key;
/**
* Serialized thrift bytes, in TBinaryProtocol format.
*
* <p>For legacy reasons, byte order is big-endian. See THRIFT-3217.
*/
public final byte[] value;
/**
* The thrift type of value, most often STRING.
*
* <p>Note: type shouldn't vary for the same key.
*/
public final Type type;
/**
* The host that recorded {@link #value}, allowing query by service name or address.
*
* <p>There are two exceptions: when {@link #key} is {@link Constants#CLIENT_ADDR} or {@link
* Constants#SERVER_ADDR}, this is the source or destination of an RPC. This exception allows
* zipkin to display network context of uninstrumented services, such as browsers or databases.
*/
@Nullable
public final Endpoint endpoint;
BinaryAnnotation(String key, byte[] value, Type type, Endpoint endpoint) {
this.key = checkNotNull(key, "key");
this.value = checkNotNull(value, "value");
this.type = checkNotNull(type, "type");
this.endpoint = endpoint;
}
public Builder toBuilder(){
return new Builder(this);
}
public static Builder builder(){
return new Builder();
}
public static final class Builder {
private String key;
private byte[] value;
private Type type;
private Endpoint endpoint;
Builder() {
}
Builder(BinaryAnnotation source) {
this.key = source.key;
this.value = source.value;
this.type = source.type;
this.endpoint = source.endpoint;
}
/** @see BinaryAnnotation#key */
public BinaryAnnotation.Builder key(String key) {
this.key = key;
return this;
}
/** @see BinaryAnnotation#value */
public BinaryAnnotation.Builder value(byte[] value) {
this.value = value.clone();
return this;
}
/** @see BinaryAnnotation#value */
public BinaryAnnotation.Builder value(String value) {
this.value = value.getBytes(Util.UTF_8);
this.type = Type.STRING;
return this;
}
/** @see BinaryAnnotation#type */
public Builder type(Type type) {
this.type = type;
return this;
}
/** @see BinaryAnnotation#endpoint */
public BinaryAnnotation.Builder endpoint(@Nullable Endpoint endpoint) {
this.endpoint = endpoint;
return this;
}
public BinaryAnnotation build() {
return new BinaryAnnotation(key, value, type, endpoint);
}
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof BinaryAnnotation) {
BinaryAnnotation that = (BinaryAnnotation) o;
return (this.key.equals(that.key))
&& (Arrays.equals(this.value, that.value))
&& (this.type.equals(that.type))
&& equal(this.endpoint, that.endpoint);
}
return false;
}
@Override
public int hashCode() {
int h = 1;
h *= 1000003;
h ^= key.hashCode();
h *= 1000003;
h ^= Arrays.hashCode(value);
h *= 1000003;
h ^= type.hashCode();
h *= 1000003;
h ^= (endpoint == null) ? 0 : endpoint.hashCode();
return h;
}
/** Provides consistent iteration by {@link #key} */
@Override
public int compareTo(BinaryAnnotation that) {
if (this == that) return 0;
return key.compareTo(that.key);
}
}