Preencode attribute keys into utf8 bytes. (#3576)

* Use constants for AttributeKeys in JMH

* Preencode attribute keys into utf8 bytes.

* Spot

* Ignore

* Be lazy

* Boil
This commit is contained in:
Anuraag Agrawal 2021-09-10 10:35:26 +09:00 committed by GitHub
parent 060e50ed5f
commit ece161f6e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 19 deletions

View File

@ -5,6 +5,7 @@
package io.opentelemetry.api.common; package io.opentelemetry.api.common;
import io.opentelemetry.api.internal.InternalAttributeKeyImpl;
import java.util.List; import java.util.List;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
@ -27,41 +28,41 @@ public interface AttributeKey<T> {
/** Returns a new AttributeKey for String valued attributes. */ /** Returns a new AttributeKey for String valued attributes. */
static AttributeKey<String> stringKey(String key) { static AttributeKey<String> stringKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.STRING); return InternalAttributeKeyImpl.create(key, AttributeType.STRING);
} }
/** Returns a new AttributeKey for Boolean valued attributes. */ /** Returns a new AttributeKey for Boolean valued attributes. */
static AttributeKey<Boolean> booleanKey(String key) { static AttributeKey<Boolean> booleanKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.BOOLEAN); return InternalAttributeKeyImpl.create(key, AttributeType.BOOLEAN);
} }
/** Returns a new AttributeKey for Long valued attributes. */ /** Returns a new AttributeKey for Long valued attributes. */
static AttributeKey<Long> longKey(String key) { static AttributeKey<Long> longKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.LONG); return InternalAttributeKeyImpl.create(key, AttributeType.LONG);
} }
/** Returns a new AttributeKey for Double valued attributes. */ /** Returns a new AttributeKey for Double valued attributes. */
static AttributeKey<Double> doubleKey(String key) { static AttributeKey<Double> doubleKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.DOUBLE); return InternalAttributeKeyImpl.create(key, AttributeType.DOUBLE);
} }
/** Returns a new AttributeKey for List&lt;String&gt; valued attributes. */ /** Returns a new AttributeKey for List&lt;String&gt; valued attributes. */
static AttributeKey<List<String>> stringArrayKey(String key) { static AttributeKey<List<String>> stringArrayKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.STRING_ARRAY); return InternalAttributeKeyImpl.create(key, AttributeType.STRING_ARRAY);
} }
/** Returns a new AttributeKey for List&lt;Boolean&gt; valued attributes. */ /** Returns a new AttributeKey for List&lt;Boolean&gt; valued attributes. */
static AttributeKey<List<Boolean>> booleanArrayKey(String key) { static AttributeKey<List<Boolean>> booleanArrayKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.BOOLEAN_ARRAY); return InternalAttributeKeyImpl.create(key, AttributeType.BOOLEAN_ARRAY);
} }
/** Returns a new AttributeKey for List&lt;Long&gt; valued attributes. */ /** Returns a new AttributeKey for List&lt;Long&gt; valued attributes. */
static AttributeKey<List<Long>> longArrayKey(String key) { static AttributeKey<List<Long>> longArrayKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.LONG_ARRAY); return InternalAttributeKeyImpl.create(key, AttributeType.LONG_ARRAY);
} }
/** Returns a new AttributeKey for List&lt;Double&gt; valued attributes. */ /** Returns a new AttributeKey for List&lt;Double&gt; valued attributes. */
static AttributeKey<List<Double>> doubleArrayKey(String key) { static AttributeKey<List<Double>> doubleArrayKey(String key) {
return AttributeKeyImpl.create(key, AttributeType.DOUBLE_ARRAY); return InternalAttributeKeyImpl.create(key, AttributeType.DOUBLE_ARRAY);
} }
} }

View File

@ -3,18 +3,28 @@
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
package io.opentelemetry.api.common; package io.opentelemetry.api.internal;
import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.AttributeType;
import java.nio.charset.StandardCharsets;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@SuppressWarnings("rawtypes") /**
final class AttributeKeyImpl<T> implements AttributeKey<T> { * Default AttributeKey implementation which preencodes to UTF8 for OTLP export.
*
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
* at any time.
*/
public final class InternalAttributeKeyImpl<T> implements AttributeKey<T> {
private final AttributeType type; private final AttributeType type;
private final String key; private final String key;
private final int hashCode; private final int hashCode;
private AttributeKeyImpl(AttributeType type, String key) { private byte[] keyUtf8;
private InternalAttributeKeyImpl(AttributeType type, String key) {
if (type == null) { if (type == null) {
throw new NullPointerException("Null type"); throw new NullPointerException("Null type");
} }
@ -38,8 +48,8 @@ final class AttributeKeyImpl<T> implements AttributeKey<T> {
// the class loader automatically resolves its super classes (interfaces), which in this case is // the class loader automatically resolves its super classes (interfaces), which in this case is
// Context, which would be the same class (interface) being instrumented at that time, // Context, which would be the same class (interface) being instrumented at that time,
// which would lead to the JVM throwing a LinkageError "attempted duplicate interface definition" // which would lead to the JVM throwing a LinkageError "attempted duplicate interface definition"
static <T> AttributeKey<T> create(@Nullable String key, AttributeType type) { public static <T> AttributeKey<T> create(@Nullable String key, AttributeType type) {
return new AttributeKeyImpl<>(type, key != null ? key : ""); return new InternalAttributeKeyImpl<>(type, key != null ? key : "");
} }
@Override @Override
@ -52,13 +62,23 @@ final class AttributeKeyImpl<T> implements AttributeKey<T> {
return key; return key;
} }
/** Returns the key, encoded as UTF-8 bytes. */
public byte[] getKeyUtf8() {
byte[] keyUtf8 = this.keyUtf8;
if (keyUtf8 == null) {
keyUtf8 = key.getBytes(StandardCharsets.UTF_8);
this.keyUtf8 = keyUtf8;
}
return keyUtf8;
}
@Override @Override
public boolean equals(@Nullable Object o) { public boolean equals(@Nullable Object o) {
if (o == this) { if (o == this) {
return true; return true;
} }
if (o instanceof AttributeKeyImpl) { if (o instanceof InternalAttributeKeyImpl) {
AttributeKeyImpl<?> that = (AttributeKeyImpl<?>) o; InternalAttributeKeyImpl<?> that = (InternalAttributeKeyImpl<?>) o;
return this.type.equals(that.getType()) && this.key.equals(that.getKey()); return this.type.equals(that.getType()) && this.key.equals(that.getKey());
} }
return false; return false;

View File

@ -7,6 +7,7 @@ package io.opentelemetry.api.common;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.internal.InternalAttributeKeyImpl;
import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -14,9 +15,12 @@ class AttributeKeyTest {
@Test @Test
void equalsVerifier() { void equalsVerifier() {
EqualsVerifier.forClass(AttributeKeyImpl.class) EqualsVerifier.forClass(InternalAttributeKeyImpl.class)
.withIgnoredFields("keyUtf8")
.withCachedHashCode( .withCachedHashCode(
"hashCode", "buildHashCode", (AttributeKeyImpl<?>) AttributeKey.stringKey("test")) "hashCode",
"buildHashCode",
(InternalAttributeKeyImpl<?>) AttributeKey.stringKey("test"))
.verify(); .verify();
} }

View File

@ -7,6 +7,7 @@ package io.opentelemetry.exporter.otlp.internal;
import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.AttributeKey;
import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.Attributes;
import io.opentelemetry.api.internal.InternalAttributeKeyImpl;
import io.opentelemetry.proto.common.v1.internal.AnyValue; import io.opentelemetry.proto.common.v1.internal.AnyValue;
import io.opentelemetry.proto.common.v1.internal.ArrayValue; import io.opentelemetry.proto.common.v1.internal.ArrayValue;
import io.opentelemetry.proto.common.v1.internal.KeyValue; import io.opentelemetry.proto.common.v1.internal.KeyValue;
@ -41,7 +42,14 @@ final class KeyValueMarshaler extends MarshalerWithSize {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static KeyValueMarshaler create(AttributeKey<?> attributeKey, Object value) { static KeyValueMarshaler create(AttributeKey<?> attributeKey, Object value) {
byte[] keyUtf8 = MarshalerUtil.toBytes(attributeKey.getKey()); final byte[] keyUtf8;
if (attributeKey.getKey().isEmpty()) {
keyUtf8 = MarshalerUtil.EMPTY_BYTES;
} else if (attributeKey instanceof InternalAttributeKeyImpl) {
keyUtf8 = ((InternalAttributeKeyImpl<?>) attributeKey).getKeyUtf8();
} else {
keyUtf8 = attributeKey.getKey().getBytes(StandardCharsets.UTF_8);
}
switch (attributeKey.getType()) { switch (attributeKey.getType()) {
case STRING: case STRING:
return new KeyValueMarshaler( return new KeyValueMarshaler(