diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKey.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKey.java index 13357a31a56..2af87227df5 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKey.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKey.java @@ -6,6 +6,7 @@ package io.opentelemetry.api.incubator.common; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.internal.InternalExtendedAttributeKeyImpl; import java.util.List; import javax.annotation.Nullable; @@ -93,8 +94,13 @@ static ExtendedAttributeKey> doubleArrayKey(String key) { return fromAttributeKey(AttributeKey.doubleArrayKey(key)); } - /** Returns a new ExtendedAttributeKey for Map valued attributes. */ - static ExtendedAttributeKey extendedAttributesKey(String key) { - return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.EXTENDED_ATTRIBUTES); + /** Returns a new ExtendedAttributeKey for map valued attributes. */ + static ExtendedAttributeKey mapKey(String key) { + return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.MAP); + } + + /** Returns a new ExtendedAttributeKey for {@link Value} valued attributes. */ + static ExtendedAttributeKey> valueKey(String key) { + return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.VALUE); } } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeType.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeType.java index 8d2c67181b6..7b026bb2a1b 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeType.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributeType.java @@ -22,5 +22,6 @@ public enum ExtendedAttributeType { LONG_ARRAY, DOUBLE_ARRAY, // Extended types unique to ExtendedAttributes - EXTENDED_ATTRIBUTES; + MAP, + VALUE; } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributes.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributes.java index 0fc88a2ea49..4fa3b278b46 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributes.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributes.java @@ -18,8 +18,9 @@ * *

"extended" refers an extended set of allowed value types compared to standard {@link * Attributes}. Notably, {@link ExtendedAttributes} values can be of type {@link - * ExtendedAttributeType#EXTENDED_ATTRIBUTES}, allowing nested {@link ExtendedAttributes} of - * arbitrary depth. + * ExtendedAttributeType#MAP}, allowing nested {@link ExtendedAttributes} of arbitrary depth, or + * {@link ExtendedAttributeType#VALUE}, enabling usage of {@link io.opentelemetry.api.common.Value} + * instances. * *

Where standard {@link Attributes} are accepted everyone that OpenTelemetry represents key / * value pairs, {@link ExtendedAttributes} are only accepted in select places, such as log records diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributesBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributesBuilder.java index 1e0de3b4c38..8fba43e4c67 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributesBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/common/ExtendedAttributesBuilder.java @@ -17,6 +17,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; @@ -94,7 +95,22 @@ default ExtendedAttributesBuilder put(String key, boolean value) { * @return this Builder */ default ExtendedAttributesBuilder put(String key, ExtendedAttributes value) { - return put(ExtendedAttributeKey.extendedAttributesKey(key), value); + return put(ExtendedAttributeKey.mapKey(key), value); + } + + /** + * Puts a {@link Value} attribute into this. + * + *

Note: It is strongly recommended to use {@link #put(ExtendedAttributeKey, Object)}, and + * pre-allocate your keys, if possible. + * + * @return this Builder + */ + default ExtendedAttributesBuilder put(String key, Value value) { + if (value == null) { + return this; + } + return put(ExtendedAttributeKey.valueKey(key), value); } /** diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/InternalExtendedAttributeKeyImpl.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/InternalExtendedAttributeKeyImpl.java index e07f72f0121..d863c5765b5 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/InternalExtendedAttributeKeyImpl.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/internal/InternalExtendedAttributeKeyImpl.java @@ -138,7 +138,8 @@ public static AttributeKey toAttributeKey(ExtendedAttributeKey extende case DOUBLE_ARRAY: return InternalAttributeKeyImpl.create( extendedAttributeKey.getKey(), AttributeType.DOUBLE_ARRAY); - case EXTENDED_ATTRIBUTES: + case MAP: + case VALUE: return null; } throw new IllegalArgumentException( diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKeyTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKeyTest.java index d2f77625d1f..1c4c546f17a 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKeyTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributeKeyTest.java @@ -76,10 +76,8 @@ private static Stream attributeKeyArgs() { "key", ExtendedAttributeType.DOUBLE_ARRAY, AttributeKey.doubleArrayKey("key")), + Arguments.of(ExtendedAttributeKey.mapKey("key"), "key", ExtendedAttributeType.MAP, null), Arguments.of( - ExtendedAttributeKey.extendedAttributesKey("key"), - "key", - ExtendedAttributeType.EXTENDED_ATTRIBUTES, - null)); + ExtendedAttributeKey.valueKey("key"), "key", ExtendedAttributeType.VALUE, null)); } } diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributesTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributesTest.java index 4481cead3d0..4e5c96a62f7 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributesTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/common/ExtendedAttributesTest.java @@ -10,6 +10,7 @@ import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -95,7 +96,7 @@ private static void assertEquals( assertThat(actual.size()).isEqualTo(expected.size()); actual.forEach( (key, value) -> { - if (key.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) { + if (key.getType() == ExtendedAttributeType.MAP) { assertEquals( ((ExtendedAttributes) value).asMap(), (Map) expected.get(key.getKey())); @@ -116,7 +117,9 @@ void asAttributes(ExtendedAttributes extendedAttributes, Map exp }); long expectedSize = - expectedMap.values().stream().filter(value -> !(value instanceof Map)).count(); + expectedMap.values().stream() + .filter(value -> !(value instanceof Map) && !(value instanceof Value)) + .count(); assertThat(attributes.size()).isEqualTo(expectedSize); } @@ -161,7 +164,7 @@ private static ExtendedAttributes fromMap(Map map) { map.forEach( (key, value) -> { ExtendedAttributeKey extendedAttributeKey = getKey(key, value); - if (extendedAttributeKey.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) { + if (extendedAttributeKey.getType() == ExtendedAttributeType.MAP) { builder.put( (ExtendedAttributeKey) extendedAttributeKey, fromMap((Map) value)); @@ -212,6 +215,9 @@ private static Stream attributesArgs() { ImmutableMap.builder() .put("key", ImmutableMap.builder().put("child", "value").build()) .build()), + Arguments.of( + ExtendedAttributes.builder().put("key", Value.of("value")).build(), + ImmutableMap.builder().put("key", Value.of("value")).build()), Arguments.of( ExtendedAttributes.builder() .put(ExtendedAttributeKey.stringKey("key"), "value") @@ -249,12 +255,17 @@ private static Stream attributesArgs() { Arguments.of( ExtendedAttributes.builder() .put( - ExtendedAttributeKey.extendedAttributesKey("key"), + ExtendedAttributeKey.mapKey("key"), ExtendedAttributes.builder().put("child", "value").build()) .build(), ImmutableMap.builder() .put("key", ImmutableMap.builder().put("child", "value").build()) .build()), + Arguments.of( + ExtendedAttributes.builder() + .put(ExtendedAttributeKey.valueKey("key"), Value.of("value")) + .build(), + ImmutableMap.builder().put("key", Value.of("value")).build()), // Multiple entries Arguments.of( ExtendedAttributes.builder() @@ -268,6 +279,7 @@ private static Stream attributesArgs() { .put("key8", 1L, 2L) .put("key9", 1.1, 2.2) .put("key10", ExtendedAttributes.builder().put("child", "value").build()) + .put("key11", Value.of("value")) .build(), ImmutableMap.builder() .put("key1", "value1") @@ -280,6 +292,7 @@ private static Stream attributesArgs() { .put("key8", Arrays.asList(1L, 2L)) .put("key9", Arrays.asList(1.1, 2.2)) .put("key10", ImmutableMap.builder().put("child", "value").build()) + .put("key11", Value.of("value")) .build())); } @@ -287,7 +300,7 @@ private static Map toMap(ExtendedAttributes extendedAttributes) Map map = new HashMap<>(); extendedAttributes.forEach( (key, value) -> { - if (key.getType() == ExtendedAttributeType.EXTENDED_ATTRIBUTES) { + if (key.getType() == ExtendedAttributeType.MAP) { map.put(key.getKey(), toMap((ExtendedAttributes) value)); return; } @@ -314,8 +327,10 @@ private static ExtendedAttributeKey getKey(String key, Object value) { return ExtendedAttributeKey.longArrayKey(key); case DOUBLE_ARRAY: return ExtendedAttributeKey.doubleArrayKey(key); - case EXTENDED_ATTRIBUTES: - return ExtendedAttributeKey.extendedAttributesKey(key); + case MAP: + return ExtendedAttributeKey.mapKey(key); + case VALUE: + return ExtendedAttributeKey.valueKey(key); } throw new IllegalArgumentException(); } @@ -353,7 +368,10 @@ private static ExtendedAttributeType getType(Object value) { } } if ((value instanceof Map)) { - return ExtendedAttributeType.EXTENDED_ATTRIBUTES; + return ExtendedAttributeType.MAP; + } + if (value instanceof Value) { + return ExtendedAttributeType.VALUE; } throw new IllegalArgumentException("Unrecognized value type: " + value); } diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java index 05c3e65f859..584be7a5742 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java @@ -11,6 +11,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.common.ExtendedAttributeKey; import io.opentelemetry.api.incubator.common.ExtendedAttributes; import io.opentelemetry.api.logs.Logger; @@ -104,8 +105,8 @@ private static String flipCoin() { AttributeKey> doubleArrKey = AttributeKey.doubleArrayKey("acme.double_array"); // Extended keys - ExtendedAttributeKey mapKey = - ExtendedAttributeKey.extendedAttributesKey("acme.map"); + ExtendedAttributeKey mapKey = ExtendedAttributeKey.mapKey("acme.map"); + ExtendedAttributeKey> valueKey = ExtendedAttributeKey.valueKey("acme.value"); @Test @SuppressLogger(ExtendedLogsBridgeApiUsageTest.class) @@ -125,6 +126,7 @@ void extendedAttributesUsage() { .put( mapKey, ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build()) + .put(valueKey, Value.of("value")) .build(); // Retrieval @@ -139,6 +141,7 @@ void extendedAttributesUsage() { assertThat(extendedAttributes.get(mapKey)) .isEqualTo( ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build()); + assertThat(extendedAttributes.get(valueKey)).isEqualTo(Value.of("value")); // Iteration // Output: @@ -148,7 +151,8 @@ void extendedAttributesUsage() { // acme.double_array(DOUBLE_ARRAY): [1.1, 2.2] // acme.long(LONG): 1 // acme.long_array(LONG_ARRAY): [1, 2] - // acme.map(EXTENDED_ATTRIBUTES): {childLong=1, childStr="value"} + // acme.map(MAP): {childLong=1, childStr="value"} + // acme.value(VALUE): ValueString{value} // acme.string(STRING): value // acme.string_array(STRING_ARRAY): [value1, value2] extendedAttributes.forEach( @@ -184,6 +188,7 @@ void logRecordBuilder_ExtendedAttributes() { .setAttribute( mapKey, ExtendedAttributes.builder().put("childStr", "value").put("childLong", 1L).build()) + .setAttribute(valueKey, Value.of("value")) .setAllAttributes(Attributes.builder().put("key1", "value").build()) .setAllAttributes(ExtendedAttributes.builder().put("key2", "value").build()) .emit(); @@ -229,6 +234,7 @@ void logRecordBuilder_ExtendedAttributes() { .put("childStr", "value") .put("childLong", 1L) .build()) + .put(valueKey, Value.of("value")) .put("key1", "value") .put("key2", "value") .build()); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ExtendedAttributeKeyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ExtendedAttributeKeyValueStatelessMarshaler.java index de31139abcb..dc42aa627c4 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ExtendedAttributeKeyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ExtendedAttributeKeyValueStatelessMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.common.ExtendedAttributeKey; import io.opentelemetry.api.incubator.common.ExtendedAttributeType; import io.opentelemetry.api.incubator.common.ExtendedAttributes; @@ -168,12 +169,15 @@ public int getBinarySerializedSize( (List) value, AttributeArrayAnyValueStatelessMarshaler.INSTANCE, context); - case EXTENDED_ATTRIBUTES: + case MAP: return StatelessMarshalerUtil.sizeMessageWithContext( AnyValue.KVLIST_VALUE, (ExtendedAttributes) value, ExtendedAttributesKeyValueListStatelessMarshaler.INSTANCE, context); + case VALUE: + return AnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( + (Value) value, context); } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported. @@ -213,13 +217,16 @@ public void writeTo( AttributeArrayAnyValueStatelessMarshaler.INSTANCE, context); return; - case EXTENDED_ATTRIBUTES: + case MAP: output.serializeMessageWithContext( AnyValue.KVLIST_VALUE, (ExtendedAttributes) value, ExtendedAttributesKeyValueListStatelessMarshaler.INSTANCE, context); return; + case VALUE: + AnyValueStatelessMarshaler.INSTANCE.writeTo(output, (Value) value, context); + return; } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported. diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java index 90660fd5a85..0bc9967095b 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/IncubatingUtil.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.common.ExtendedAttributeKey; import io.opentelemetry.api.incubator.common.ExtendedAttributes; import io.opentelemetry.api.incubator.internal.InternalExtendedAttributeKeyImpl; @@ -110,12 +111,14 @@ private static KeyValueMarshaler create(ExtendedAttributeKey attributeKey, Ob case DOUBLE_ARRAY: return new KeyValueMarshaler( keyUtf8, ArrayAnyValueMarshaler.createDouble((List) value)); - case EXTENDED_ATTRIBUTES: + case MAP: return new KeyValueMarshaler( keyUtf8, new KeyValueListAnyValueMarshaler( new KeyValueListAnyValueMarshaler.KeyValueListMarshaler( createForExtendedAttributes((ExtendedAttributes) value)))); + case VALUE: + return new KeyValueMarshaler(keyUtf8, AnyValueMarshaler.create((Value) value)); } // Error prone ensures the switch statement is complete, otherwise only can happen with // unaligned versions which are not supported.