diff --git a/api/all/src/main/java/io/opentelemetry/api/common/AttributeKey.java b/api/all/src/main/java/io/opentelemetry/api/common/AttributeKey.java index 7d012aa14ca..64b101975ab 100644 --- a/api/all/src/main/java/io/opentelemetry/api/common/AttributeKey.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/AttributeKey.java @@ -70,4 +70,9 @@ static AttributeKey> longArrayKey(String key) { static AttributeKey> doubleArrayKey(String key) { return InternalAttributeKeyImpl.create(key, AttributeType.DOUBLE_ARRAY); } + + /** Returns a new AttributeKey for generic {@link Value} valued attributes. */ + static AttributeKey> valueKey(String key) { + return InternalAttributeKeyImpl.create(key, AttributeType.VALUE); + } } diff --git a/api/all/src/main/java/io/opentelemetry/api/common/AttributeType.java b/api/all/src/main/java/io/opentelemetry/api/common/AttributeType.java index 1c51e36d644..6209301f573 100644 --- a/api/all/src/main/java/io/opentelemetry/api/common/AttributeType.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/AttributeType.java @@ -17,5 +17,15 @@ public enum AttributeType { STRING_ARRAY, BOOLEAN_ARRAY, LONG_ARRAY, - DOUBLE_ARRAY + DOUBLE_ARRAY, + /** + * Simple attributes ({@link AttributeType#STRING}, {@link AttributeType#LONG}, {@link + * AttributeType#DOUBLE}, {@link AttributeType#BOOLEAN}, {@link AttributeType#STRING_ARRAY}, + * {@link AttributeType#LONG_ARRAY}, {@link AttributeType#DOUBLE_ARRAY}, {@link + * AttributeType#BOOLEAN_ARRAY}) SHOULD be used whenever possible. Instrumentations SHOULD assume + * that backends do not index individual properties of complex attributes, that querying or + * aggregating on such properties is inefficient and complicated, and that reporting complex + * attributes carries higher performance overhead. + */ + VALUE } diff --git a/api/all/src/main/java/io/opentelemetry/api/common/Attributes.java b/api/all/src/main/java/io/opentelemetry/api/common/Attributes.java index 2a9d43793a7..8ac46146e6b 100644 --- a/api/all/src/main/java/io/opentelemetry/api/common/Attributes.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/Attributes.java @@ -33,11 +33,57 @@ @Immutable public interface Attributes { - /** Returns the value for the given {@link AttributeKey}, or {@code null} if not found. */ + /** + * Returns the value for the given {@link AttributeKey}, or {@code null} if not found. + * + *

Note: this method will automatically return the corresponding {@link Value} instance when + * passed a key of type {@link AttributeType#VALUE} and a simple attribute is found. This is the + * inverse of {@link AttributesBuilder#put(AttributeKey, Object)} when the key is {@link + * AttributeType#VALUE}. + * + *

    + *
  • If {@code put(AttributeKey.stringKey("key"), "a")} was called, then {@code + * get(AttributeKey.valueKey("key"))} returns {@code Value.of("a")}. + *
  • If {@code put(AttributeKey.longKey("key"), 1L)} was called, then {@code + * get(AttributeKey.valueKey("key"))} returns {@code Value.of(1L)}. + *
  • If {@code put(AttributeKey.doubleKey("key"), 1.0)} was called, then {@code + * get(AttributeKey.valueKey("key"))} returns {@code Value.of(1.0)}. + *
  • If {@code put(AttributeKey.booleanKey("key"), true)} was called, then {@code + * get(AttributeKey.valueKey("key"))} returns {@code Value.of(true)}. + *
  • If {@code put(AttributeKey.stringArrayKey("key"), Arrays.asList("a", "b"))} was called, + * then {@code get(AttributeKey.valueKey("key"))} returns {@code Value.of(Value.of("a"), + * Value.of("b"))}. + *
  • If {@code put(AttributeKey.longArrayKey("key"), Arrays.asList(1L, 2L))} was called, then + * {@code get(AttributeKey.valueKey("key"))} returns {@code Value.of(Value.of(1L), + * Value.of(2L))}. + *
  • If {@code put(AttributeKey.doubleArrayKey("key"), Arrays.asList(1.0, 2.0))} was called, + * then {@code get(AttributeKey.valueKey("key"))} returns {@code Value.of(Value.of(1.0), + * Value.of(2.0))}. + *
  • If {@code put(AttributeKey.booleanArrayKey("key"), Arrays.asList(true, false))} was + * called, then {@code get(AttributeKey.valueKey("key"))} returns {@code + * Value.of(Value.of(true), Value.of(false))}. + *
+ * + * Further, if {@code put(AttributeKey.valueKey("key"), Value.of(emptyList()))} was called, then + * + *
    + *
  • {@code get(AttributeKey.stringArrayKey("key"))} + *
  • {@code get(AttributeKey.longArrayKey("key"))} + *
  • {@code get(AttributeKey.booleanArrayKey("key"))} + *
  • {@code get(AttributeKey.doubleArrayKey("key"))} + *
+ * + * all return an empty list (as opposed to {@code null}). + */ @Nullable T get(AttributeKey key); - /** Iterates over all the key-value pairs of attributes contained by this instance. */ + /** + * Iterates over all the key-value pairs of attributes contained by this instance. + * + *

Note: {@link AttributeType#VALUE} attributes will be represented as simple attributes if + * possible. See {@link AttributesBuilder#put(AttributeKey, Object)} for more details. + */ void forEach(BiConsumer, ? super Object> consumer); /** The number of attributes contained in this. */ @@ -46,7 +92,12 @@ public interface Attributes { /** Whether there are any attributes contained in this. */ boolean isEmpty(); - /** Returns a read-only view of this {@link Attributes} as a {@link Map}. */ + /** + * Returns a read-only view of this {@link Attributes} as a {@link Map}. + * + *

Note: {@link AttributeType#VALUE} attributes will be represented as simple attributes in + * this map if possible. See {@link AttributesBuilder#put(AttributeKey, Object)} for more details. + */ Map, Object> asMap(); /** Returns a {@link Attributes} instance with no attributes. */ diff --git a/api/all/src/main/java/io/opentelemetry/api/common/AttributesBuilder.java b/api/all/src/main/java/io/opentelemetry/api/common/AttributesBuilder.java index 6623d470137..bc246ad3e8b 100644 --- a/api/all/src/main/java/io/opentelemetry/api/common/AttributesBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/AttributesBuilder.java @@ -39,6 +39,40 @@ public interface AttributesBuilder { /** * Puts an {@link AttributeKey} with an associated value into this if the value is non-null. * Providing a null value does not remove or unset previously set values. + * + *

Simple attributes ({@link AttributeType#STRING}, {@link AttributeType#LONG}, {@link + * AttributeType#DOUBLE}, {@link AttributeType#BOOLEAN}, {@link AttributeType#STRING_ARRAY}, + * {@link AttributeType#LONG_ARRAY}, {@link AttributeType#DOUBLE_ARRAY}, {@link + * AttributeType#BOOLEAN_ARRAY}) SHOULD be used whenever possible. Instrumentations SHOULD assume + * that backends do not index individual properties of complex attributes, that querying or + * aggregating on such properties is inefficient and complicated, and that reporting complex + * attributes carries higher performance overhead. + * + *

Note: This method will automatically convert complex attributes ({@link + * AttributeType#VALUE}) to simple attributes when possible. + * + *

    + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of("a"))} is equivalent to calling + * {@code put(AttributeKey.stringKey("key"), "a")}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(1L))} is equivalent to calling + * {@code put(AttributeKey.longKey("key"), 1L)}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(1.0))} is equivalent to calling + * {@code put(AttributeKey.doubleKey("key"), 1.0)}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(true))} is equivalent to + * calling {@code put(AttributeKey.booleanKey("key"), true)}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(Value.of("a"), Value.of("b")))} + * is equivalent to calling {@code put(AttributeKey.stringArrayKey("key"), + * Arrays.asList("a", "b"))}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(Value.of(1L), Value.of(2L)))} + * is equivalent to calling {@code put(AttributeKey.longArrayKey("key"), Arrays.asList(1L, + * 2L))}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(Value.of(1.0), Value.of(2.0)))} + * is equivalent to calling {@code put(AttributeKey.doubleArrayKey("key"), + * Arrays.asList(1.0, 2.0))}. + *
  • Calling {@code put(AttributeKey.valueKey("key"), Value.of(Value.of(true), + * Value.of(false)))} is equivalent to calling {@code + * put(AttributeKey.booleanArrayKey("key"), Arrays.asList(true, false))}. + *
*/ AttributesBuilder put(AttributeKey key, @Nullable T value);