diff --git a/api/all/src/main/java/io/opentelemetry/api/common/KeyValue.java b/api/all/src/main/java/io/opentelemetry/api/common/KeyValue.java new file mode 100644 index 00000000000..341b9d1227a --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/common/KeyValue.java @@ -0,0 +1,25 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.common; + +/** + * Key-value pair of {@link String} key and {@link Value} value. + * + * @see Value#of(KeyValue...) + */ +public interface KeyValue { + + /** Returns a {@link KeyValue} for the given {@code key} and {@code value}. */ + static KeyValue of(String key, Value value) { + return KeyValueImpl.create(key, value); + } + + /** Returns the key. */ + String getKey(); + + /** Returns the value. */ + Value getValue(); +} diff --git a/api/all/src/main/java/io/opentelemetry/api/common/KeyValueImpl.java b/api/all/src/main/java/io/opentelemetry/api/common/KeyValueImpl.java new file mode 100644 index 00000000000..1525c3f3c69 --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/common/KeyValueImpl.java @@ -0,0 +1,18 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.common; + +import com.google.auto.value.AutoValue; + +@AutoValue +abstract class KeyValueImpl implements KeyValue { + + KeyValueImpl() {} + + static KeyValueImpl create(String key, Value value) { + return new AutoValue_KeyValueImpl(key, value); + } +} diff --git a/api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java b/api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java new file mode 100644 index 00000000000..42801205564 --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/common/KeyValueList.java @@ -0,0 +1,75 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.common; + +import static java.util.stream.Collectors.joining; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +final class KeyValueList implements Value> { + + private final List value; + + private KeyValueList(List value) { + this.value = value; + } + + static Value> create(KeyValue... value) { + Objects.requireNonNull(value, "value must not be null"); + List list = new ArrayList<>(value.length); + list.addAll(Arrays.asList(value)); + return new KeyValueList(Collections.unmodifiableList(list)); + } + + static Value> createFromMap(Map> value) { + Objects.requireNonNull(value, "value must not be null"); + KeyValue[] array = + value.entrySet().stream() + .map(entry -> KeyValue.of(entry.getKey(), entry.getValue())) + .toArray(KeyValue[]::new); + return create(array); + } + + @Override + public ValueType getType() { + return ValueType.KEY_VALUE_LIST; + } + + @Override + public List getValue() { + return value; + } + + @Override + public String asString() { + return value.stream() + .map(item -> item.getKey() + "=" + item.getValue().asString()) + .collect(joining(", ", "[", "]")); + } + + @Override + public String toString() { + return "KeyValueList{" + asString() + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/api/all/src/main/java/io/opentelemetry/api/common/Value.java b/api/all/src/main/java/io/opentelemetry/api/common/Value.java new file mode 100644 index 00000000000..68da725010b --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/common/Value.java @@ -0,0 +1,117 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.common; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; + +/** + * Value mirrors the proto AnyValue + * message type, and is used to model any type. + * + *

It can be used to represent: + * + *

    + *
  • Primitive values via {@link #of(long)}, {@link #of(String)}, {@link #of(boolean)}, {@link + * #of(double)}. + *
  • String-keyed maps (i.e. associative arrays, dictionaries) via {@link #of(KeyValue...)}, + * {@link #of(Map)}. Note, because map values are type {@link Value}, maps can be nested + * within other maps. + *
  • Arrays (heterogeneous or homogenous) via {@link #of(Value[])}. Note, because array values + * are type {@link Value}, arrays can contain primitives, complex types like maps or arrays, + * or any combination. + *
  • Raw bytes via {@link #of(byte[])} + *
+ * + *

Currently, Value is only used as an argument for {@link + * io.opentelemetry.api.logs.LogRecordBuilder#setBody(Value)}. + * + * @param the type. See {@link #getValue()} for description of types. + */ +public interface Value { + + /** Returns an {@link Value} for the {@link String} value. */ + static Value of(String value) { + return ValueString.create(value); + } + + /** Returns an {@link Value} for the {@code boolean} value. */ + static Value of(boolean value) { + return ValueBoolean.create(value); + } + + /** Returns an {@link Value} for the {@code long} value. */ + static Value of(long value) { + return ValueLong.create(value); + } + + /** Returns an {@link Value} for the {@code double} value. */ + static Value of(double value) { + return ValueDouble.create(value); + } + + /** Returns an {@link Value} for the {@code byte[]} value. */ + static Value of(byte[] value) { + return ValueBytes.create(value); + } + + /** Returns an {@link Value} for the array of {@link Value} values. */ + static Value>> of(Value... value) { + return ValueArray.create(value); + } + + /** Returns an {@link Value} for the list of {@link Value} values. */ + static Value>> of(List> value) { + return ValueArray.create(value); + } + + /** + * Returns an {@link Value} for the array of {@link KeyValue} values. {@link KeyValue#getKey()} + * values should not repeat - duplicates may be dropped. + */ + static Value> of(KeyValue... value) { + return KeyValueList.create(value); + } + + /** Returns an {@link Value} for the {@link Map} of key, {@link Value}. */ + static Value> of(Map> value) { + return KeyValueList.createFromMap(value); + } + + /** Returns the type of this {@link Value}. Useful for building switch statements. */ + ValueType getType(); + + /** + * Returns the value for this {@link Value}. + * + *

The return type varies by {@link #getType()} as described below: + * + *

    + *
  • {@link ValueType#STRING} returns {@link String} + *
  • {@link ValueType#BOOLEAN} returns {@code boolean} + *
  • {@link ValueType#LONG} returns {@code long} + *
  • {@link ValueType#DOUBLE} returns {@code double} + *
  • {@link ValueType#ARRAY} returns {@link List} of {@link Value} + *
  • {@link ValueType#KEY_VALUE_LIST} returns {@link List} of {@link KeyValue} + *
  • {@link ValueType#BYTES} returns read only {@link ByteBuffer}. See {@link + * ByteBuffer#asReadOnlyBuffer()}. + *
+ */ + T getValue(); + + /** + * Return a string encoding of this {@link Value}. This is intended to be a fallback serialized + * representation in case there is no suitable encoding that can utilize {@link #getType()} / + * {@link #getValue()} to serialize specific types. + * + *

WARNING: No guarantees are made about the encoding of this string response. It MAY change in + * a future minor release. If you need a reliable string encoding, write your own serializer. + */ + // TODO(jack-berg): Should this be a JSON encoding? + String asString(); +} diff --git a/api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java new file mode 100644 index 00000000000..55c9e5f42b7 --- /dev/null +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueArray.java @@ -0,0 +1,67 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.common; + +import static java.util.stream.Collectors.joining; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +final class ValueArray implements Value>> { + + private final List> value; + + private ValueArray(List> value) { + this.value = value; + } + + static Value>> create(Value... value) { + Objects.requireNonNull(value, "value must not be null"); + List> list = new ArrayList<>(value.length); + list.addAll(Arrays.asList(value)); + return new ValueArray(Collections.unmodifiableList(list)); + } + + static Value>> create(List> value) { + return new ValueArray(Collections.unmodifiableList(value)); + } + + @Override + public ValueType getType() { + return ValueType.ARRAY; + } + + @Override + public List> getValue() { + return value; + } + + @Override + public String asString() { + return value.stream().map(Value::asString).collect(joining(", ", "[", "]")); + } + + @Override + public String toString() { + return "ValueArray{" + asString() + "}"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); + } + + @Override + public int hashCode() { + return value.hashCode(); + } +} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBoolean.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueBoolean.java similarity index 55% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBoolean.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueBoolean.java index fcaa7525241..a4364d414df 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBoolean.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueBoolean.java @@ -3,25 +3,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; import java.util.Objects; -final class AnyValueBoolean implements AnyValue { +final class ValueBoolean implements Value { private final boolean value; - private AnyValueBoolean(boolean value) { + private ValueBoolean(boolean value) { this.value = value; } - static AnyValue create(boolean value) { - return new AnyValueBoolean(value); + static Value create(boolean value) { + return new ValueBoolean(value); } @Override - public AnyValueType getType() { - return AnyValueType.BOOLEAN; + public ValueType getType() { + return ValueType.BOOLEAN; } @Override @@ -36,7 +36,7 @@ public String asString() { @Override public String toString() { - return "AnyValueBoolean{" + asString() + "}"; + return "ValueBoolean{" + asString() + "}"; } @Override @@ -44,7 +44,7 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); } @Override diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBytes.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueBytes.java similarity index 61% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBytes.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueBytes.java index 4f572dee172..8d925cd174d 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueBytes.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueBytes.java @@ -3,29 +3,29 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Base64; import java.util.Objects; -final class AnyValueBytes implements AnyValue { +final class ValueBytes implements Value { private final byte[] raw; - private AnyValueBytes(byte[] value) { + private ValueBytes(byte[] value) { this.raw = value; } - static AnyValue create(byte[] value) { + static Value create(byte[] value) { Objects.requireNonNull(value, "value must not be null"); - return new AnyValueBytes(Arrays.copyOf(value, value.length)); + return new ValueBytes(Arrays.copyOf(value, value.length)); } @Override - public AnyValueType getType() { - return AnyValueType.BYTES; + public ValueType getType() { + return ValueType.BYTES; } @Override @@ -40,7 +40,7 @@ public String asString() { @Override public String toString() { - return "AnyValueBytes{" + asString() + "}"; + return "ValueBytes{" + asString() + "}"; } @Override @@ -48,7 +48,7 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (o instanceof AnyValueBytes) && Arrays.equals(this.raw, ((AnyValueBytes) o).raw); + return (o instanceof ValueBytes) && Arrays.equals(this.raw, ((ValueBytes) o).raw); } @Override diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueDouble.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueDouble.java similarity index 56% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueDouble.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueDouble.java index e1ab55f8528..21f13dd7e78 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueDouble.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueDouble.java @@ -3,25 +3,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; import java.util.Objects; -final class AnyValueDouble implements AnyValue { +final class ValueDouble implements Value { private final double value; - private AnyValueDouble(double value) { + private ValueDouble(double value) { this.value = value; } - static AnyValue create(double value) { - return new AnyValueDouble(value); + static Value create(double value) { + return new ValueDouble(value); } @Override - public AnyValueType getType() { - return AnyValueType.DOUBLE; + public ValueType getType() { + return ValueType.DOUBLE; } @Override @@ -36,7 +36,7 @@ public String asString() { @Override public String toString() { - return "AnyValueDouble{" + asString() + "}"; + return "ValueDouble{" + asString() + "}"; } @Override @@ -44,7 +44,7 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); } @Override diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueLong.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueLong.java similarity index 56% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueLong.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueLong.java index 0cc1d3beafa..8cd1bca4bf9 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueLong.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueLong.java @@ -3,25 +3,25 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; import java.util.Objects; -final class AnyValueLong implements AnyValue { +final class ValueLong implements Value { private final long value; - private AnyValueLong(long value) { + private ValueLong(long value) { this.value = value; } - static AnyValue create(long value) { - return new AnyValueLong(value); + static Value create(long value) { + return new ValueLong(value); } @Override - public AnyValueType getType() { - return AnyValueType.LONG; + public ValueType getType() { + return ValueType.LONG; } @Override @@ -36,7 +36,7 @@ public String asString() { @Override public String toString() { - return "AnyValueLong{" + asString() + "}"; + return "ValueLong{" + asString() + "}"; } @Override @@ -44,7 +44,7 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); } @Override diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueString.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueString.java similarity index 58% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueString.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueString.java index d2b8be2e729..726cb27dee3 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueString.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueString.java @@ -3,26 +3,26 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; import java.util.Objects; -final class AnyValueString implements AnyValue { +final class ValueString implements Value { private final String value; - private AnyValueString(String value) { + private ValueString(String value) { this.value = value; } - static AnyValue create(String value) { + static Value create(String value) { Objects.requireNonNull(value, "value must not be null"); - return new AnyValueString(value); + return new ValueString(value); } @Override - public AnyValueType getType() { - return AnyValueType.STRING; + public ValueType getType() { + return ValueType.STRING; } @Override @@ -37,7 +37,7 @@ public String asString() { @Override public String toString() { - return "AnyValueString{" + value + "}"; + return "ValueString{" + value + "}"; } @Override @@ -45,7 +45,7 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); + return (o instanceof Value) && Objects.equals(this.value, ((Value) o).getValue()); } @Override diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueType.java b/api/all/src/main/java/io/opentelemetry/api/common/ValueType.java similarity index 84% rename from api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueType.java rename to api/all/src/main/java/io/opentelemetry/api/common/ValueType.java index ea41d887094..99980280d2c 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueType.java +++ b/api/all/src/main/java/io/opentelemetry/api/common/ValueType.java @@ -3,14 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -package io.opentelemetry.api.incubator.logs; +package io.opentelemetry.api.common; /** * AnyValue type options, mirroring AnyValue#value * options. */ -public enum AnyValueType { +public enum ValueType { STRING, BOOLEAN, LONG, diff --git a/api/all/src/main/java/io/opentelemetry/api/logs/DefaultLogger.java b/api/all/src/main/java/io/opentelemetry/api/logs/DefaultLogger.java index 47644104dcb..56284b43cb2 100644 --- a/api/all/src/main/java/io/opentelemetry/api/logs/DefaultLogger.java +++ b/api/all/src/main/java/io/opentelemetry/api/logs/DefaultLogger.java @@ -6,6 +6,7 @@ package io.opentelemetry.api.logs; import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Value; import io.opentelemetry.context.Context; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -70,6 +71,11 @@ public LogRecordBuilder setBody(String body) { return this; } + @Override + public LogRecordBuilder setBody(Value body) { + return this; + } + @Override public LogRecordBuilder setAttribute(AttributeKey key, T value) { return this; diff --git a/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java b/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java index 1b7e24d19a9..392796065d9 100644 --- a/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java +++ b/api/all/src/main/java/io/opentelemetry/api/logs/LogRecordBuilder.java @@ -7,6 +7,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.context.Context; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -66,9 +67,19 @@ public interface LogRecordBuilder { /** Set the severity text. */ LogRecordBuilder setSeverityText(String severityText); - /** Set the body string. */ + /** + * Set the body string. + * + *

Shorthand for calling {@link #setBody(Value)} with {@link Value#of(String)}. + */ LogRecordBuilder setBody(String body); + /** Set the body {@link Value}. */ + default LogRecordBuilder setBody(Value body) { + setBody(body.asString()); + return this; + } + /** * Sets attributes. If the {@link LogRecordBuilder} previously contained a mapping for any of the * keys, the old values are replaced by the specified values. diff --git a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java b/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java index 9f43ab22b87..ffe68f37e95 100644 --- a/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java +++ b/api/all/src/test/java/io/opentelemetry/api/logs/DefaultLoggerTest.java @@ -9,6 +9,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.context.Context; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -30,6 +31,7 @@ void buildAndEmit() { .setSeverity(Severity.DEBUG) .setSeverityText("debug") .setBody("body") + .setBody(Value.of("body")) .setAttribute(AttributeKey.stringKey("key1"), "value1") .setAllAttributes(Attributes.builder().put("key2", "value2").build()) .emit()) diff --git a/api/all/src/test/java/io/opentelemetry/api/logs/ValueTest.java b/api/all/src/test/java/io/opentelemetry/api/logs/ValueTest.java new file mode 100644 index 00000000000..ae83e0dd44c --- /dev/null +++ b/api/all/src/test/java/io/opentelemetry/api/logs/ValueTest.java @@ -0,0 +1,215 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.api.logs; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.common.ValueType; +import java.nio.ByteBuffer; +import java.nio.ReadOnlyBufferException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Base64; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.stream.Stream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class ValueTest { + + @Test + void value_OfString() { + assertThat(Value.of("foo")) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.STRING); + assertThat(value.getValue()).isEqualTo("foo"); + assertThat(value).hasSameHashCodeAs(Value.of("foo")); + }); + } + + @Test + void value_OfBoolean() { + assertThat(Value.of(true)) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.BOOLEAN); + assertThat(value.getValue()).isEqualTo(true); + assertThat(value).hasSameHashCodeAs(Value.of(true)); + }); + } + + @Test + void value_OfLong() { + assertThat(Value.of(1L)) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.LONG); + assertThat(value.getValue()).isEqualTo(1L); + assertThat(value).hasSameHashCodeAs(Value.of(1L)); + }); + } + + @Test + void value_OfDouble() { + assertThat(Value.of(1.1)) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.DOUBLE); + assertThat(value.getValue()).isEqualTo(1.1); + assertThat(value).hasSameHashCodeAs(Value.of(1.1)); + }); + } + + @Test + void value_OfByteArray() { + assertThat(Value.of(new byte[] {'a', 'b'})) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.BYTES); + ByteBuffer buf = value.getValue(); + // ValueBytes returns read only view of ByteBuffer + assertThatThrownBy(buf::array).isInstanceOf(ReadOnlyBufferException.class); + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes); + assertThat(bytes).isEqualTo(new byte[] {'a', 'b'}); + assertThat(value).hasSameHashCodeAs(Value.of(new byte[] {'a', 'b'})); + }); + } + + @Test + void value_OfvalueArray() { + assertThat(Value.of(Value.of(true), Value.of(1L))) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.ARRAY); + assertThat(value.getValue()).isEqualTo(Arrays.asList(Value.of(true), Value.of(1L))); + assertThat(value).hasSameHashCodeAs(Value.of(Value.of(true), Value.of(1L))); + }); + } + + @Test + @SuppressWarnings("DoubleBraceInitialization") + void value_OfKeyValueList() { + assertThat(Value.of(KeyValue.of("bool", Value.of(true)), KeyValue.of("long", Value.of(1L)))) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.KEY_VALUE_LIST); + assertThat(value.getValue()) + .isEqualTo( + Arrays.asList( + KeyValue.of("bool", Value.of(true)), KeyValue.of("long", Value.of(1L)))); + assertThat(value) + .hasSameHashCodeAs( + Value.of( + KeyValue.of("bool", Value.of(true)), KeyValue.of("long", Value.of(1L)))); + }); + + assertThat( + Value.of( + new LinkedHashMap>() { + { + put("bool", Value.of(true)); + put("long", Value.of(1L)); + } + })) + .satisfies( + value -> { + assertThat(value.getType()).isEqualTo(ValueType.KEY_VALUE_LIST); + assertThat(value.getValue()) + .isEqualTo( + Arrays.asList( + KeyValue.of("bool", Value.of(true)), KeyValue.of("long", Value.of(1L)))); + assertThat(value) + .hasSameHashCodeAs( + Value.of( + new LinkedHashMap>() { + { + put("bool", Value.of(true)); + put("long", Value.of(1L)); + } + })); + }); + } + + @Test + void value_NullsNotAllowed() { + assertThatThrownBy(() -> Value.of((String) null)) + .isInstanceOf(NullPointerException.class) + .hasMessageContaining("value must not be null"); + assertThatThrownBy(() -> Value.of((byte[]) null)) + .isInstanceOf(NullPointerException.class) + .hasMessageContaining("value must not be null"); + assertThatThrownBy(() -> Value.of((Value[]) null)) + .isInstanceOf(NullPointerException.class) + .hasMessageContaining("value must not be null"); + assertThatThrownBy(() -> Value.of((KeyValue[]) null)) + .isInstanceOf(NullPointerException.class) + .hasMessageContaining("value must not be null"); + assertThatThrownBy(() -> Value.of((Map>) null)) + .isInstanceOf(NullPointerException.class) + .hasMessageContaining("value must not be null"); + } + + @ParameterizedTest + @MethodSource("asStringArgs") + void asString(Value value, String expectedAsString) { + assertThat(value.asString()).isEqualTo(expectedAsString); + } + + @SuppressWarnings("DoubleBraceInitialization") + private static Stream asStringArgs() { + return Stream.of( + // primitives + arguments(Value.of("str"), "str"), + arguments(Value.of(true), "true"), + arguments(Value.of(1), "1"), + arguments(Value.of(1.1), "1.1"), + // heterogeneous array + arguments( + Value.of(Value.of("str"), Value.of(true), Value.of(1), Value.of(1.1)), + "[str, true, 1, 1.1]"), + // key value list from KeyValue array + arguments( + Value.of(KeyValue.of("key1", Value.of("val1")), KeyValue.of("key2", Value.of(2))), + "[key1=val1, key2=2]"), + // key value list from map + arguments( + Value.of( + new LinkedHashMap>() { + { + put("key1", Value.of("val1")); + put("key2", Value.of(2)); + } + }), + "[key1=val1, key2=2]"), + // map of map + arguments( + Value.of( + Collections.singletonMap( + "child", Value.of(Collections.singletonMap("grandchild", Value.of("str"))))), + "[child=[grandchild=str]]"), + // bytes + arguments(Value.of("hello world".getBytes(StandardCharsets.UTF_8)), "aGVsbG8gd29ybGQ=")); + } + + @Test + void valueByteAsString() { + // TODO: add more test cases + String str = "hello world"; + String base64Encoded = Value.of(str.getBytes(StandardCharsets.UTF_8)).asString(); + byte[] decodedBytes = Base64.getDecoder().decode(base64Encoded); + assertThat(new String(decodedBytes, StandardCharsets.UTF_8)).isEqualTo(str); + } +} diff --git a/api/incubator/README.md b/api/incubator/README.md index ccd4678df43..ee29241f9fe 100644 --- a/api/incubator/README.md +++ b/api/incubator/README.md @@ -14,8 +14,7 @@ See [EventApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/events/Ev Features: -* Check if logger is enabled before emitting logs to avoid uneccessary computation -* Set AnyValue log record body with arbitrarily complex data +* Check if logger is enabled before emitting logs to avoid unnecessary computation See [ExtendedLogsBridgeApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java). @@ -31,7 +30,7 @@ See [ExtendedMetricsApiUsageTest](./src/test/java/io/opentelemetry/api/incubator Features: -* Check if instrument is enabled before recording measurements to avoid uneccessary computation +* Check if instrument is enabled before recording measurements to avoid unnecessary computation * Simplified injection / extraction of context See [ExtendedContextPropagatorsUsageTest](./src/test/java/io/opentelemetry/api/incubator/propagation/ExtendedContextPropagatorsUsageTest.java). @@ -40,7 +39,7 @@ See [ExtendedContextPropagatorsUsageTest](./src/test/java/io/opentelemetry/api/i Features: -* Check if tracer is enabled before starting spans to avoid uneccessary computation +* Check if tracer is enabled before starting spans to avoid unnecessary computation * Utility methods to reduce boilerplace using span API, including extracting context, and wrapping runnables / callables with spans See [ExtendedTraceApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/trace/ExtendedTraceApiUsageTest.java). diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/DefaultEventLogger.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/DefaultEventLogger.java index 8017965bf00..c0c795c584b 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/DefaultEventLogger.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/DefaultEventLogger.java @@ -6,7 +6,7 @@ package io.opentelemetry.api.incubator.events; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.context.Context; import java.time.Instant; @@ -32,7 +32,7 @@ private static class NoOpEventBuilder implements EventBuilder { public static final EventBuilder INSTANCE = new NoOpEventBuilder(); @Override - public EventBuilder put(String key, AnyValue value) { + public EventBuilder put(String key, Value value) { return this; } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/EventBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/EventBuilder.java index 9aca02b3077..a2c43a47a0e 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/EventBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/events/EventBuilder.java @@ -9,7 +9,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.context.Context; import java.time.Instant; @@ -22,58 +22,58 @@ public interface EventBuilder { /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, String value) { - return put(key, AnyValue.of(value)); + return put(key, Value.of(value)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, long value) { - return put(key, AnyValue.of(value)); + return put(key, Value.of(value)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, double value) { - return put(key, AnyValue.of(value)); + return put(key, Value.of(value)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, boolean value) { - return put(key, AnyValue.of(value)); + return put(key, Value.of(value)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, String... value) { - List> values = new ArrayList<>(value.length); + List> values = new ArrayList<>(value.length); for (String val : value) { - values.add(AnyValue.of(val)); + values.add(Value.of(val)); } - return put(key, AnyValue.of(values)); + return put(key, Value.of(values)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, long... value) { - List> values = new ArrayList<>(value.length); + List> values = new ArrayList<>(value.length); for (long val : value) { - values.add(AnyValue.of(val)); + values.add(Value.of(val)); } - return put(key, AnyValue.of(values)); + return put(key, Value.of(values)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, double... value) { - List> values = new ArrayList<>(value.length); + List> values = new ArrayList<>(value.length); for (double val : value) { - values.add(AnyValue.of(val)); + values.add(Value.of(val)); } - return put(key, AnyValue.of(values)); + return put(key, Value.of(values)); } /** Put the given {@code key} and {@code value} in the payload. */ default EventBuilder put(String key, boolean... value) { - List> values = new ArrayList<>(value.length); + List> values = new ArrayList<>(value.length); for (boolean val : value) { - values.add(AnyValue.of(val)); + values.add(Value.of(val)); } - return put(key, AnyValue.of(values)); + return put(key, Value.of(values)); } /** @@ -97,25 +97,24 @@ default EventBuilder put(AttributeKey key, T value) { case STRING_ARRAY: return put( key.getKey(), - AnyValue.of(((List) value).stream().map(AnyValue::of).collect(toList()))); + Value.of(((List) value).stream().map(Value::of).collect(toList()))); case BOOLEAN_ARRAY: return put( key.getKey(), - AnyValue.of(((List) value).stream().map(AnyValue::of).collect(toList()))); + Value.of(((List) value).stream().map(Value::of).collect(toList()))); case LONG_ARRAY: return put( - key.getKey(), - AnyValue.of(((List) value).stream().map(AnyValue::of).collect(toList()))); + key.getKey(), Value.of(((List) value).stream().map(Value::of).collect(toList()))); case DOUBLE_ARRAY: return put( key.getKey(), - AnyValue.of(((List) value).stream().map(AnyValue::of).collect(toList()))); + Value.of(((List) value).stream().map(Value::of).collect(toList()))); } return this; } /** Put the given {@code key} and {@code value} in the payload. */ - EventBuilder put(String key, AnyValue value); + EventBuilder put(String key, Value value); /** * Set the epoch {@code timestamp}, using the timestamp and unit. @@ -143,9 +142,9 @@ default EventBuilder put(AttributeKey key, T value) { * Set the attributes. * *

Event {@link io.opentelemetry.api.common.Attributes} provide additional details about the - * Event which are not part of the well-defined {@link AnyValue} payload. Setting event attributes - * is less common than adding entries to the event payload. Most users will want to call one of - * the {@code #put(String, ?)} methods instead. + * Event which are not part of the well-defined {@link Value} payload. Setting event attributes is + * less common than adding entries to the event payload. Most users will want to call one of the + * {@code #put(String, ?)} methods instead. */ EventBuilder setAttributes(Attributes attributes); diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValue.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValue.java deleted file mode 100644 index 602e9e289b7..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValue.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -import java.nio.ByteBuffer; -import java.util.List; -import java.util.Map; - -/** - * AnyValue mirrors the proto AnyValue - * message type, and is used to model any type. - * - *

It can be used to represent: - * - *

    - *
  • Primitive values via {@link #of(long)}, {@link #of(String)}, {@link #of(boolean)}, {@link - * #of(double)}. - *
  • String-keyed maps (i.e. associative arrays, dictionaries) via {@link #of(KeyAnyValue...)}, - * {@link #of(Map)}. Note, because map values are type {@link AnyValue}, maps can be nested - * within other maps. - *
  • Arrays (heterogeneous or homogenous) via {@link #of(AnyValue[])}. Note, because array - * values are type {@link AnyValue}, arrays can contain primitives, complex types like maps or - * arrays, or any combination. - *
  • Raw bytes via {@link #of(byte[])} - *
- * - * @param the type. See {@link #getValue()} for description of types. - */ -public interface AnyValue { - - /** Returns an {@link AnyValue} for the {@link String} value. */ - static AnyValue of(String value) { - return AnyValueString.create(value); - } - - /** Returns an {@link AnyValue} for the {@code boolean} value. */ - static AnyValue of(boolean value) { - return AnyValueBoolean.create(value); - } - - /** Returns an {@link AnyValue} for the {@code long} value. */ - static AnyValue of(long value) { - return AnyValueLong.create(value); - } - - /** Returns an {@link AnyValue} for the {@code double} value. */ - static AnyValue of(double value) { - return AnyValueDouble.create(value); - } - - /** Returns an {@link AnyValue} for the {@code byte[]} value. */ - static AnyValue of(byte[] value) { - return AnyValueBytes.create(value); - } - - /** Returns an {@link AnyValue} for the array of {@link AnyValue} values. */ - static AnyValue>> of(AnyValue... value) { - return AnyValueArray.create(value); - } - - /** Returns an {@link AnyValue} for the list of {@link AnyValue} values. */ - static AnyValue>> of(List> value) { - return AnyValueArray.create(value); - } - - /** - * Returns an {@link AnyValue} for the array of {@link KeyAnyValue} values. {@link - * KeyAnyValue#getKey()} values should not repeat - duplicates may be dropped. - */ - static AnyValue> of(KeyAnyValue... value) { - return KeyAnyValueList.create(value); - } - - /** Returns an {@link AnyValue} for the {@link Map} of key, {@link AnyValue}. */ - static AnyValue> of(Map> value) { - return KeyAnyValueList.createFromMap(value); - } - - /** Returns the type of this {@link AnyValue}. Useful for building switch statements. */ - AnyValueType getType(); - - /** - * Returns the value for this {@link AnyValue}. - * - *

The return type varies by {@link #getType()} as described below: - * - *

    - *
  • {@link AnyValueType#STRING} returns {@link String} - *
  • {@link AnyValueType#BOOLEAN} returns {@code boolean} - *
  • {@link AnyValueType#LONG} returns {@code long} - *
  • {@link AnyValueType#DOUBLE} returns {@code double} - *
  • {@link AnyValueType#ARRAY} returns {@link List} of {@link AnyValue} - *
  • {@link AnyValueType#KEY_VALUE_LIST} returns {@link List} of {@link KeyAnyValue} - *
  • {@link AnyValueType#BYTES} returns read only {@link ByteBuffer}. See {@link - * ByteBuffer#asReadOnlyBuffer()}. - *
- */ - T getValue(); - - /** - * Return a string encoding of this {@link AnyValue}. This is intended to be a fallback serialized - * representation in case there is no suitable encoding that can utilize {@link #getType()} / - * {@link #getValue()} to serialize specific types. - */ - // TODO(jack-berg): Should this be a JSON encoding? - String asString(); -} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueArray.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueArray.java deleted file mode 100644 index 2332c253392..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/AnyValueArray.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -import static java.util.stream.Collectors.joining; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -final class AnyValueArray implements AnyValue>> { - - private final List> value; - - private AnyValueArray(List> value) { - this.value = value; - } - - static AnyValue>> create(AnyValue... value) { - Objects.requireNonNull(value, "value must not be null"); - List> list = new ArrayList<>(value.length); - list.addAll(Arrays.asList(value)); - return new AnyValueArray(Collections.unmodifiableList(list)); - } - - static AnyValue>> create(List> value) { - return new AnyValueArray(Collections.unmodifiableList(value)); - } - - @Override - public AnyValueType getType() { - return AnyValueType.ARRAY; - } - - @Override - public List> getValue() { - return value; - } - - @Override - public String asString() { - return value.stream().map(AnyValue::asString).collect(joining(", ", "[", "]")); - } - - @Override - public String toString() { - return "AnyValueArray{" + asString() + "}"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); - } - - @Override - public int hashCode() { - return value.hashCode(); - } -} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogRecordBuilder.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogRecordBuilder.java index d0a48afaf56..4e8af8eee70 100644 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogRecordBuilder.java +++ b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/ExtendedLogRecordBuilder.java @@ -10,6 +10,6 @@ /** Extended {@link LogRecordBuilder} with experimental APIs. */ public interface ExtendedLogRecordBuilder extends LogRecordBuilder { - /** Set the body {@link AnyValue}. */ - LogRecordBuilder setBody(AnyValue body); + // Nothing at the moment, but experimental methods may be added in the future. + } diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValue.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValue.java deleted file mode 100644 index e6cc24ad250..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValue.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -/** - * Key-value pair of {@link String} key and {@link AnyValue} value. - * - * @see AnyValue#of(KeyAnyValue...) - */ -public interface KeyAnyValue { - - /** Returns a {@link KeyAnyValue} for the given {@code key} and {@code value}. */ - static KeyAnyValue of(String key, AnyValue value) { - return KeyAnyValueImpl.create(key, value); - } - - /** Returns the key. */ - String getKey(); - - /** Returns the value. */ - AnyValue getAnyValue(); -} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueImpl.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueImpl.java deleted file mode 100644 index 3792353e717..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueImpl.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -import com.google.auto.value.AutoValue; - -@AutoValue -abstract class KeyAnyValueImpl implements KeyAnyValue { - - KeyAnyValueImpl() {} - - static KeyAnyValueImpl create(String key, AnyValue value) { - return new AutoValue_KeyAnyValueImpl(key, value); - } -} diff --git a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueList.java b/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueList.java deleted file mode 100644 index caddcbe7f46..00000000000 --- a/api/incubator/src/main/java/io/opentelemetry/api/incubator/logs/KeyAnyValueList.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -import static java.util.stream.Collectors.joining; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -final class KeyAnyValueList implements AnyValue> { - - private final List value; - - private KeyAnyValueList(List value) { - this.value = value; - } - - static AnyValue> create(KeyAnyValue... value) { - Objects.requireNonNull(value, "value must not be null"); - List list = new ArrayList<>(value.length); - list.addAll(Arrays.asList(value)); - return new KeyAnyValueList(Collections.unmodifiableList(list)); - } - - static AnyValue> createFromMap(Map> value) { - Objects.requireNonNull(value, "value must not be null"); - KeyAnyValue[] array = - value.entrySet().stream() - .map(entry -> KeyAnyValue.of(entry.getKey(), entry.getValue())) - .toArray(KeyAnyValue[]::new); - return create(array); - } - - @Override - public AnyValueType getType() { - return AnyValueType.KEY_VALUE_LIST; - } - - @Override - public List getValue() { - return value; - } - - @Override - public String asString() { - return value.stream() - .map(item -> item.getKey() + "=" + item.getAnyValue().asString()) - .collect(joining(", ", "[", "]")); - } - - @Override - public String toString() { - return "KeyAnyValueList{" + asString() + "}"; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - return (o instanceof AnyValue) && Objects.equals(this.value, ((AnyValue) o).getValue()); - } - - @Override - public int hashCode() { - return value.hashCode(); - } -} diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/DefaultEventLoggerTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/DefaultEventLoggerTest.java index 054e09d2c35..ff525646ef6 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/DefaultEventLoggerTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/DefaultEventLoggerTest.java @@ -9,7 +9,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.context.Context; import java.time.Instant; @@ -38,13 +38,13 @@ void builder() { .put("longArrKey", 1L, 2L) .put("doubleArrKey", 1.0, 2.0) .put("boolArrKey", true, false) - // Set AnyValue types to encode complex data + // Set complex data .put( - "anyValueKey", - AnyValue.of( - new HashMap>() { + "valueKey", + Value.of( + new HashMap>() { { - put("key", AnyValue.of("value")); + put("key", Value.of("value")); } })) // Helper methods to set AttributeKey types diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/EventApiUsageTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/EventApiUsageTest.java index 4b074ae5b13..3194978ed4f 100644 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/EventApiUsageTest.java +++ b/api/incubator/src/test/java/io/opentelemetry/api/incubator/events/EventApiUsageTest.java @@ -9,10 +9,9 @@ import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.logs.internal.AnyValueBody; import io.opentelemetry.sdk.logs.internal.SdkEventLoggerProvider; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; @@ -42,21 +41,20 @@ void eventApiUsage() { eventLogger .builder("org.foo.my-event") // Add fields to the payload. The API has helpers for adding field values which are - // primitives or arrays of primitives, but you can also add a field with type AnyValue, + // primitives or arrays of primitives, but you can also add a field with type Value, // allowing for arbitrarily complex payloads. .put("key1", "value1") .put( "key2", - AnyValue.of( - ImmutableMap.of( - "childKey1", AnyValue.of("value2"), "childKey2", AnyValue.of("value3")))) + Value.of( + ImmutableMap.of("childKey1", Value.of("value2"), "childKey2", Value.of("value3")))) // Optionally set other fields, including timestamp, severity, context, and attributes // (attributes provide additional details about the event which are not part of the well // defined payload) .emit(); // Events manifest as log records with an event.name attribute, and with the payload fields in - // the AnyValue log record body + // the Value log record body loggerProvider.forceFlush().join(10, TimeUnit.SECONDS); assertThat(exporter.getFinishedLogRecordItems()) .satisfiesExactly( @@ -64,19 +62,20 @@ void eventApiUsage() { assertThat(logData) .hasAttributes( Attributes.builder().put("event.name", "org.foo.my-event").build()); - assertThat(((AnyValueBody) logData.getBody()).asAnyValue()) + assertThat(logData.getBodyValue()) + .isNotNull() .isEqualTo( - AnyValue.of( + Value.of( ImmutableMap.of( "key1", - AnyValue.of("value1"), + Value.of("value1"), "key2", - AnyValue.of( + Value.of( ImmutableMap.of( "childKey1", - AnyValue.of("value2"), + Value.of("value2"), "childKey2", - AnyValue.of("value3")))))); + Value.of("value3")))))); }); } } diff --git a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/AnyValueTest.java b/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/AnyValueTest.java deleted file mode 100644 index 4f52637f575..00000000000 --- a/api/incubator/src/test/java/io/opentelemetry/api/incubator/logs/AnyValueTest.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.api.incubator.logs; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.params.provider.Arguments.arguments; - -import java.nio.ByteBuffer; -import java.nio.ReadOnlyBufferException; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Base64; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -class AnyValueTest { - - @Test - void anyValue_OfString() { - assertThat(AnyValue.of("foo")) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.STRING); - assertThat(anyValue.getValue()).isEqualTo("foo"); - assertThat(anyValue).hasSameHashCodeAs(AnyValue.of("foo")); - }); - } - - @Test - void anyValue_OfBoolean() { - assertThat(AnyValue.of(true)) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.BOOLEAN); - assertThat(anyValue.getValue()).isEqualTo(true); - assertThat(anyValue).hasSameHashCodeAs(AnyValue.of(true)); - }); - } - - @Test - void anyValue_OfLong() { - assertThat(AnyValue.of(1L)) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.LONG); - assertThat(anyValue.getValue()).isEqualTo(1L); - assertThat(anyValue).hasSameHashCodeAs(AnyValue.of(1L)); - }); - } - - @Test - void anyValue_OfDouble() { - assertThat(AnyValue.of(1.1)) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.DOUBLE); - assertThat(anyValue.getValue()).isEqualTo(1.1); - assertThat(anyValue).hasSameHashCodeAs(AnyValue.of(1.1)); - }); - } - - @Test - void anyValue_OfByteArray() { - assertThat(AnyValue.of(new byte[] {'a', 'b'})) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.BYTES); - ByteBuffer value = anyValue.getValue(); - // AnyValueBytes returns read only view of ByteBuffer - assertThatThrownBy(value::array).isInstanceOf(ReadOnlyBufferException.class); - byte[] bytes = new byte[value.remaining()]; - value.get(bytes); - assertThat(bytes).isEqualTo(new byte[] {'a', 'b'}); - assertThat(anyValue).hasSameHashCodeAs(AnyValue.of(new byte[] {'a', 'b'})); - }); - } - - @Test - void anyValue_OfAnyValueArray() { - assertThat(AnyValue.of(AnyValue.of(true), AnyValue.of(1L))) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.ARRAY); - assertThat(anyValue.getValue()) - .isEqualTo(Arrays.asList(AnyValue.of(true), AnyValue.of(1L))); - assertThat(anyValue) - .hasSameHashCodeAs(AnyValue.of(AnyValue.of(true), AnyValue.of(1L))); - }); - } - - @Test - @SuppressWarnings("DoubleBraceInitialization") - void anyValue_OfKeyValueList() { - assertThat( - AnyValue.of( - KeyAnyValue.of("bool", AnyValue.of(true)), KeyAnyValue.of("long", AnyValue.of(1L)))) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.KEY_VALUE_LIST); - assertThat(anyValue.getValue()) - .isEqualTo( - Arrays.asList( - KeyAnyValue.of("bool", AnyValue.of(true)), - KeyAnyValue.of("long", AnyValue.of(1L)))); - assertThat(anyValue) - .hasSameHashCodeAs( - AnyValue.of( - KeyAnyValue.of("bool", AnyValue.of(true)), - KeyAnyValue.of("long", AnyValue.of(1L)))); - }); - - assertThat( - AnyValue.of( - new LinkedHashMap>() { - { - put("bool", AnyValue.of(true)); - put("long", AnyValue.of(1L)); - } - })) - .satisfies( - anyValue -> { - assertThat(anyValue.getType()).isEqualTo(AnyValueType.KEY_VALUE_LIST); - assertThat(anyValue.getValue()) - .isEqualTo( - Arrays.asList( - KeyAnyValue.of("bool", AnyValue.of(true)), - KeyAnyValue.of("long", AnyValue.of(1L)))); - assertThat(anyValue) - .hasSameHashCodeAs( - AnyValue.of( - new LinkedHashMap>() { - { - put("bool", AnyValue.of(true)); - put("long", AnyValue.of(1L)); - } - })); - }); - } - - @Test - void anyValue_NullsNotAllowed() { - assertThatThrownBy(() -> AnyValue.of((String) null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("value must not be null"); - assertThatThrownBy(() -> AnyValue.of((byte[]) null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("value must not be null"); - assertThatThrownBy(() -> AnyValue.of((AnyValue[]) null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("value must not be null"); - assertThatThrownBy(() -> AnyValue.of((KeyAnyValue[]) null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("value must not be null"); - assertThatThrownBy(() -> AnyValue.of((Map>) null)) - .isInstanceOf(NullPointerException.class) - .hasMessageContaining("value must not be null"); - } - - @ParameterizedTest - @MethodSource("asStringArgs") - void asString(AnyValue value, String expectedAsString) { - assertThat(value.asString()).isEqualTo(expectedAsString); - } - - @SuppressWarnings("DoubleBraceInitialization") - private static Stream asStringArgs() { - return Stream.of( - // primitives - arguments(AnyValue.of("str"), "str"), - arguments(AnyValue.of(true), "true"), - arguments(AnyValue.of(1), "1"), - arguments(AnyValue.of(1.1), "1.1"), - // heterogeneous array - arguments( - AnyValue.of(AnyValue.of("str"), AnyValue.of(true), AnyValue.of(1), AnyValue.of(1.1)), - "[str, true, 1, 1.1]"), - // key value list from KeyAnyValue array - arguments( - AnyValue.of( - KeyAnyValue.of("key1", AnyValue.of("val1")), - KeyAnyValue.of("key2", AnyValue.of(2))), - "[key1=val1, key2=2]"), - // key value list from map - arguments( - AnyValue.of( - new LinkedHashMap>() { - { - put("key1", AnyValue.of("val1")); - put("key2", AnyValue.of(2)); - } - }), - "[key1=val1, key2=2]"), - // map of map - arguments( - AnyValue.of( - Collections.singletonMap( - "child", - AnyValue.of(Collections.singletonMap("grandchild", AnyValue.of("str"))))), - "[child=[grandchild=str]]"), - // bytes - arguments(AnyValue.of("hello world".getBytes(StandardCharsets.UTF_8)), "aGVsbG8gd29ybGQ=")); - } - - @Test - void anyValueByteAsString() { - // TODO: add more test cases - String str = "hello world"; - String base64Encoded = AnyValue.of(str.getBytes(StandardCharsets.UTF_8)).asString(); - byte[] decodedBytes = Base64.getDecoder().decode(base64Encoded); - assertThat(new String(decodedBytes, StandardCharsets.UTF_8)).isEqualTo(str); - } -} 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 7a3d7c82e17..2d9c494ee3e 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 @@ -9,18 +9,14 @@ import static io.opentelemetry.sdk.logs.internal.LoggerConfig.disabled; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import com.google.common.collect.ImmutableMap; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.logs.Logger; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.SdkLoggerProviderBuilder; import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.logs.internal.AnyValueBody; import io.opentelemetry.sdk.logs.internal.SdkLoggerProviderUtil; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; import java.util.Random; -import java.util.concurrent.TimeUnit; import org.junit.jupiter.api.Test; /** Demonstrating usage of extended Logs Bridge API. */ @@ -80,56 +76,4 @@ void loggerEnabled() { private static String flipCoin() { return random.nextBoolean() ? "heads" : "tails"; } - - @Test - void extendedLogRecordBuilderUsage() { - // Setup SdkLoggerProvider - InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); - SdkLoggerProvider loggerProvider = - SdkLoggerProvider.builder() - // Default resource used for demonstration purposes - .setResource(Resource.getDefault()) - // Simple processor w/ in-memory exporter used for demonstration purposes - .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) - .build(); - - // Get a Logger for a scope - Logger logger = loggerProvider.get("org.foo.my-scope"); - - // Cast to ExtendedLogRecordBuilder, and emit a log - ((ExtendedLogRecordBuilder) logger.logRecordBuilder()) - // ...can set AnyValue log record body, allowing for arbitrarily complex data - .setBody( - AnyValue.of( - ImmutableMap.of( - "key1", - AnyValue.of("value1"), - "key2", - AnyValue.of( - ImmutableMap.of( - "childKey1", - AnyValue.of("value2"), - "childKey2", - AnyValue.of("value3")))))) - .emit(); - - // SDK can access AnyValue body by casting to AnyValueBody - loggerProvider.forceFlush().join(10, TimeUnit.SECONDS); - assertThat(exporter.getFinishedLogRecordItems()) - .satisfiesExactly( - logData -> - assertThat(((AnyValueBody) logData.getBody()).asAnyValue()) - .isEqualTo( - AnyValue.of( - ImmutableMap.of( - "key1", - AnyValue.of("value1"), - "key2", - AnyValue.of( - ImmutableMap.of( - "childKey1", - AnyValue.of("value2"), - "childKey2", - AnyValue.of("value3"))))))); - } } diff --git a/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts b/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts index 3c420e1719a..6a7a4139d6e 100644 --- a/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/otel.japicmp-conventions.gradle.kts @@ -29,18 +29,21 @@ class AllowNewAbstractMethodOnAutovalueClasses : AbstractRecordingSeenMembers() override fun maybeAddViolation(member: JApiCompatibility): Violation? { val allowableAutovalueChanges = setOf(JApiCompatibilityChange.METHOD_ABSTRACT_ADDED_TO_CLASS, JApiCompatibilityChange.METHOD_ADDED_TO_PUBLIC_CLASS) if (member.compatibilityChanges.filter { !allowableAutovalueChanges.contains(it) }.isEmpty() && - member is JApiMethod && - member.getjApiClass().newClass.get().getAnnotation(AutoValue::class.java) != null - ) { + member is JApiMethod && isAutoValueClass(member.getjApiClass())) + { return Violation.accept(member, "Autovalue will automatically add implementation") } if (member.compatibilityChanges.isEmpty() && - member is JApiClass && - member.newClass.get().getAnnotation(AutoValue::class.java) != null) { + member is JApiClass && isAutoValueClass(member)) { return Violation.accept(member, "Autovalue class modification is allowed") } return null } + + fun isAutoValueClass(japiClass: JApiClass): Boolean { + return japiClass.newClass.get().getAnnotation(AutoValue::class.java) != null || + japiClass.newClass.get().getAnnotation(AutoValue.Builder::class.java) != null + } } class SourceIncompatibleRule : AbstractRecordingSeenMembers() { diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt index 58efc24b59d..2b8bdd18bad 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-api.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-api.txt @@ -1,2 +1,41 @@ Comparing source compatibility of opentelemetry-api-1.42.0-SNAPSHOT.jar against opentelemetry-api-1.41.0.jar -No changes. \ No newline at end of file ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.common.KeyValue (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String getKey() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.common.Value getValue() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.KeyValue of(java.lang.String, io.opentelemetry.api.common.Value) ++++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.common.Value (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + GENERIC TEMPLATES: +++ T:java.lang.Object + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.String asString() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.common.ValueType getType() + +++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Object getValue() + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value of(java.lang.String) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value of(boolean) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value of(long) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value of(double) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value of(byte[]) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value>> of(io.opentelemetry.api.common.Value[]) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value>> of(java.util.List>) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value> of(io.opentelemetry.api.common.KeyValue[]) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.Value> of(java.util.Map>) ++++ NEW ENUM: PUBLIC(+) FINAL(+) io.opentelemetry.api.common.ValueType (compatible) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW INTERFACE: java.lang.constant.Constable + +++ NEW INTERFACE: java.lang.Comparable + +++ NEW INTERFACE: java.io.Serializable + +++ NEW SUPERCLASS: java.lang.Enum + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType BYTES + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType ARRAY + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType KEY_VALUE_LIST + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType STRING + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType DOUBLE + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType BOOLEAN + +++ NEW FIELD: PUBLIC(+) STATIC(+) FINAL(+) io.opentelemetry.api.common.ValueType LONG + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.ValueType valueOf(java.lang.String) + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.api.common.ValueType[] values() +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.api.logs.LogRecordBuilder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.logs.LogRecordBuilder setBody(io.opentelemetry.api.common.Value) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt index 3f689fe94cc..b096d42eb98 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-logs.txt @@ -1,2 +1,15 @@ Comparing source compatibility of opentelemetry-sdk-logs-1.42.0-SNAPSHOT.jar against opentelemetry-sdk-logs-1.41.0.jar -No changes. \ No newline at end of file +=== UNCHANGED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.logs.data.Body (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + === UNCHANGED METHOD: PUBLIC ABSTRACT io.opentelemetry.sdk.logs.data.Body$Type getType() + +++ NEW ANNOTATION: java.lang.Deprecated + +++ NEW ANNOTATION: java.lang.Deprecated +=== UNCHANGED ENUM: PUBLIC STATIC FINAL io.opentelemetry.sdk.logs.data.Body$Type (compatible) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW ANNOTATION: java.lang.Deprecated +*** MODIFIED INTERFACE: PUBLIC ABSTRACT io.opentelemetry.sdk.logs.data.LogRecordData (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + === UNCHANGED METHOD: PUBLIC ABSTRACT io.opentelemetry.sdk.logs.data.Body getBody() + +++ NEW ANNOTATION: java.lang.Deprecated + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.common.Value getBodyValue() + +++ NEW ANNOTATION: javax.annotation.Nullable diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt index 7c4d542dd50..988fe184f0f 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt @@ -1,2 +1,15 @@ Comparing source compatibility of opentelemetry-sdk-testing-1.42.0-SNAPSHOT.jar against opentelemetry-sdk-testing-1.41.0.jar -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.testing.assertj.LogRecordDataAssert (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.LogRecordDataAssert hasBody(io.opentelemetry.api.common.Value) +**** MODIFIED CLASS: PUBLIC ABSTRACT io.opentelemetry.sdk.testing.logs.TestLogRecordData (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.logs.data.Body getBody() + +++ NEW ANNOTATION: java.lang.Deprecated + +++* NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.api.common.Value getBodyValue() + +++ NEW ANNOTATION: javax.annotation.Nullable +**** MODIFIED CLASS: PUBLIC ABSTRACT STATIC io.opentelemetry.sdk.testing.logs.TestLogRecordData$Builder (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + *** MODIFIED METHOD: PUBLIC (<- PACKAGE_PROTECTED) NON_ABSTRACT (<- ABSTRACT) io.opentelemetry.sdk.testing.logs.TestLogRecordData$Builder setBody(io.opentelemetry.sdk.logs.data.Body) + +++ NEW ANNOTATION: java.lang.Deprecated + +++* NEW METHOD: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.testing.logs.TestLogRecordData$Builder setBodyValue(io.opentelemetry.api.common.Value) diff --git a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/SystemOutLogRecordExporter.java b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/SystemOutLogRecordExporter.java index 6655c12453a..3848bf0225a 100644 --- a/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/SystemOutLogRecordExporter.java +++ b/exporters/logging/src/main/java/io/opentelemetry/exporter/logging/SystemOutLogRecordExporter.java @@ -7,6 +7,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; +import io.opentelemetry.api.common.Value; import io.opentelemetry.sdk.common.CompletableResultCode; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.logs.data.LogRecordData; @@ -63,6 +64,7 @@ public CompletableResultCode flush() { // VisibleForTesting static void formatLog(StringBuilder stringBuilder, LogRecordData log) { InstrumentationScopeInfo instrumentationScopeInfo = log.getInstrumentationScopeInfo(); + Value body = log.getBodyValue(); stringBuilder .append( ISO_FORMAT.format( @@ -71,7 +73,7 @@ static void formatLog(StringBuilder stringBuilder, LogRecordData log) { .append(" ") .append(log.getSeverity()) .append(" '") - .append(log.getBody().asString()) + .append(body == null ? "" : body.asString()) .append("' : ") .append(log.getSpanContext().getTraceId()) .append(" ") diff --git a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/LogsRequestMarshalerBenchmark.java b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/LogsRequestMarshalerBenchmark.java index 289f6f77845..2d25476f42a 100644 --- a/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/LogsRequestMarshalerBenchmark.java +++ b/exporters/otlp/common/src/jmh/java/io/opentelemetry/exporter/internal/otlp/LogsRequestMarshalerBenchmark.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.events.EventLogger; -import io.opentelemetry.api.incubator.logs.AnyValue; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.exporter.internal.otlp.logs.LogsRequestMarshaler; @@ -98,9 +98,8 @@ public class LogsRequestMarshalerBenchmark { .put("longArrKey", 1L, 2L) .put("doubleArrKey", 1.0, 2.0) .put("boolArrKey", true, false) - // Set AnyValue types to encode complex data - .put( - "anyValueKey", AnyValue.of(Collections.singletonMap("childKey1", AnyValue.of("value")))) + // Set complex data + .put("key", Value.of(Collections.singletonMap("childKey1", Value.of("value")))) .emit(); LOGS = logRecordExporter.getFinishedLogRecordItems(); diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshaler.java index 0b39d15df29..327ad471e4e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshaler.java @@ -5,8 +5,8 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.AnyValue; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import java.nio.ByteBuffer; import java.util.List; @@ -22,23 +22,23 @@ public final class AnyValueMarshaler { private AnyValueMarshaler() {} @SuppressWarnings("unchecked") - public static MarshalerWithSize create(AnyValue anyValue) { - switch (anyValue.getType()) { + public static MarshalerWithSize create(Value value) { + switch (value.getType()) { case STRING: - return StringAnyValueMarshaler.create((String) anyValue.getValue()); + return StringAnyValueMarshaler.create((String) value.getValue()); case BOOLEAN: - return BoolAnyValueMarshaler.create((boolean) anyValue.getValue()); + return BoolAnyValueMarshaler.create((boolean) value.getValue()); case LONG: - return IntAnyValueMarshaler.create((long) anyValue.getValue()); + return IntAnyValueMarshaler.create((long) value.getValue()); case DOUBLE: - return DoubleAnyValueMarshaler.create((double) anyValue.getValue()); + return DoubleAnyValueMarshaler.create((double) value.getValue()); case ARRAY: - return ArrayAnyValueMarshaler.createAnyValue((List>) anyValue.getValue()); + return ArrayAnyValueMarshaler.createAnyValue((List>) value.getValue()); case KEY_VALUE_LIST: - return KeyValueListAnyValueMarshaler.create((List) anyValue.getValue()); + return KeyValueListAnyValueMarshaler.create((List) value.getValue()); case BYTES: - return BytesAnyValueMarshaler.create((ByteBuffer) anyValue.getValue()); + return BytesAnyValueMarshaler.create((ByteBuffer) value.getValue()); } - throw new IllegalArgumentException("Unsupported AnyValue type: " + anyValue.getType()); + throw new IllegalArgumentException("Unsupported Value type: " + value.getType()); } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueStatelessMarshaler.java index f9cbb05589f..bad0d9060d5 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/AnyValueStatelessMarshaler.java @@ -5,8 +5,8 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.AnyValue; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; @@ -21,7 +21,7 @@ *

This class is internal and is hence not for public use. Its APIs are unstable and can change * at any time. */ -public final class AnyValueStatelessMarshaler implements StatelessMarshaler> { +public final class AnyValueStatelessMarshaler implements StatelessMarshaler> { public static final AnyValueStatelessMarshaler INSTANCE = new AnyValueStatelessMarshaler(); @@ -29,7 +29,7 @@ private AnyValueStatelessMarshaler() {} @SuppressWarnings("unchecked") @Override - public void writeTo(Serializer output, AnyValue value, MarshalerContext context) + public void writeTo(Serializer output, Value value, MarshalerContext context) throws IOException { switch (value.getType()) { case STRING: @@ -50,14 +50,14 @@ public void writeTo(Serializer output, AnyValue value, MarshalerContext conte case ARRAY: output.serializeMessageWithContext( io.opentelemetry.proto.common.v1.internal.AnyValue.ARRAY_VALUE, - (List>) value.getValue(), + (List>) value.getValue(), ArrayAnyValueStatelessMarshaler.INSTANCE, context); return; case KEY_VALUE_LIST: output.serializeMessageWithContext( io.opentelemetry.proto.common.v1.internal.AnyValue.KVLIST_VALUE, - (List) value.getValue(), + (List) value.getValue(), KeyValueListAnyValueStatelessMarshaler.INSTANCE, context); return; @@ -73,7 +73,7 @@ public void writeTo(Serializer output, AnyValue value, MarshalerContext conte @SuppressWarnings("unchecked") @Override - public int getBinarySerializedSize(AnyValue value, MarshalerContext context) { + public int getBinarySerializedSize(Value value, MarshalerContext context) { switch (value.getType()) { case STRING: return StringAnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize( @@ -90,13 +90,13 @@ public int getBinarySerializedSize(AnyValue value, MarshalerContext context) case ARRAY: return StatelessMarshalerUtil.sizeMessageWithContext( io.opentelemetry.proto.common.v1.internal.AnyValue.ARRAY_VALUE, - (List>) value.getValue(), + (List>) value.getValue(), ArrayAnyValueStatelessMarshaler.INSTANCE, context); case KEY_VALUE_LIST: return StatelessMarshalerUtil.sizeMessageWithContext( io.opentelemetry.proto.common.v1.internal.AnyValue.KVLIST_VALUE, - (List) value.getValue(), + (List) value.getValue(), KeyValueListAnyValueStatelessMarshaler.INSTANCE, context); case BYTES: diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java index aa1c25e9c14..9b9ba2fc26e 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueMarshaler.java @@ -5,6 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; +import io.opentelemetry.api.common.Value; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; @@ -23,8 +24,7 @@ private ArrayAnyValueMarshaler(ArrayValueMarshaler value) { this.value = value; } - static MarshalerWithSize createAnyValue( - List> values) { + static MarshalerWithSize createAnyValue(List> values) { return createInternal(values, AnyValueMarshaler::create); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java index a558953514c..2ccc4a4eca3 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/ArrayAnyValueStatelessMarshaler.java @@ -5,7 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; @@ -15,21 +15,21 @@ import java.util.List; /** A Marshaler of key value pairs. See {@link ArrayAnyValueMarshaler}. */ -final class ArrayAnyValueStatelessMarshaler implements StatelessMarshaler>> { +final class ArrayAnyValueStatelessMarshaler implements StatelessMarshaler>> { static final ArrayAnyValueStatelessMarshaler INSTANCE = new ArrayAnyValueStatelessMarshaler(); private ArrayAnyValueStatelessMarshaler() {} @Override - public void writeTo(Serializer output, List> value, MarshalerContext context) + public void writeTo(Serializer output, List> value, MarshalerContext context) throws IOException { output.serializeRepeatedMessageWithContext( ArrayValue.VALUES, value, AnyValueStatelessMarshaler.INSTANCE, context); } @Override - public int getBinarySerializedSize(List> value, MarshalerContext context) { + public int getBinarySerializedSize(List> value, MarshalerContext context) { return StatelessMarshalerUtil.sizeRepeatedMessageWithContext( ArrayValue.VALUES, value, AnyValueStatelessMarshaler.INSTANCE, context); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueMarshaler.java index afb884a2d86..1e5b345acae 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueMarshaler.java @@ -5,7 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; @@ -24,11 +24,11 @@ private KeyValueListAnyValueMarshaler(KeyValueListMarshaler value) { this.value = value; } - static MarshalerWithSize create(List values) { + static MarshalerWithSize create(List values) { int len = values.size(); KeyValueMarshaler[] marshalers = new KeyValueMarshaler[values.size()]; for (int i = 0; i < len; i++) { - marshalers[i] = KeyValueMarshaler.createForKeyAnyValue(values.get(i)); + marshalers[i] = KeyValueMarshaler.createForKeyValue(values.get(i)); } return new KeyValueListAnyValueMarshaler(new KeyValueListMarshaler(marshalers)); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueStatelessMarshaler.java index 854eb2cea6e..6bb7ef8d210 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueListAnyValueStatelessMarshaler.java @@ -5,7 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; @@ -15,8 +15,7 @@ import java.util.List; /** A Marshaler of key value pairs. See {@link KeyValueListAnyValueMarshaler}. */ -final class KeyValueListAnyValueStatelessMarshaler - implements StatelessMarshaler> { +final class KeyValueListAnyValueStatelessMarshaler implements StatelessMarshaler> { static final KeyValueListAnyValueStatelessMarshaler INSTANCE = new KeyValueListAnyValueStatelessMarshaler(); @@ -24,14 +23,14 @@ final class KeyValueListAnyValueStatelessMarshaler private KeyValueListAnyValueStatelessMarshaler() {} @Override - public void writeTo(Serializer output, List value, MarshalerContext context) + public void writeTo(Serializer output, List value, MarshalerContext context) throws IOException { output.serializeRepeatedMessageWithContext( KeyValueList.VALUES, value, KeyValueStatelessMarshaler.INSTANCE, context); } @Override - public int getBinarySerializedSize(List value, MarshalerContext context) { + public int getBinarySerializedSize(List value, MarshalerContext context) { return StatelessMarshalerUtil.sizeRepeatedMessageWithContext( KeyValueList.VALUES, value, KeyValueStatelessMarshaler.INSTANCE, context); } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java index 56a3fa06461..47a0a32a759 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueMarshaler.java @@ -7,13 +7,12 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; import io.opentelemetry.api.internal.InternalAttributeKeyImpl; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.internal.marshal.MarshalerUtil; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; import io.opentelemetry.exporter.internal.marshal.Serializer; -import io.opentelemetry.proto.common.v1.internal.KeyValue; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; @@ -39,11 +38,11 @@ private KeyValueMarshaler(byte[] keyUtf8, Marshaler value) { this.value = value; } - /** Returns Marshaler for the given KeyAnyValue. */ - public static KeyValueMarshaler createForKeyAnyValue(KeyAnyValue keyAnyValue) { + /** Returns Marshaler for the given KeyValue. */ + public static KeyValueMarshaler createForKeyValue(KeyValue keyValue) { return new KeyValueMarshaler( - keyAnyValue.getKey().getBytes(StandardCharsets.UTF_8), - AnyValueMarshaler.create(keyAnyValue.getAnyValue())); + keyValue.getKey().getBytes(StandardCharsets.UTF_8), + AnyValueMarshaler.create(keyValue.getValue())); } /** Returns Marshalers for the given Attributes. */ @@ -104,14 +103,16 @@ private static KeyValueMarshaler create(AttributeKey attributeKey, Object val @Override public void writeTo(Serializer output) throws IOException { - output.serializeString(KeyValue.KEY, keyUtf8); - output.serializeMessage(KeyValue.VALUE, value); + output.serializeString(io.opentelemetry.proto.common.v1.internal.KeyValue.KEY, keyUtf8); + output.serializeMessage(io.opentelemetry.proto.common.v1.internal.KeyValue.VALUE, value); } private static int calculateSize(byte[] keyUtf8, Marshaler value) { int size = 0; - size += MarshalerUtil.sizeBytes(KeyValue.KEY, keyUtf8); - size += MarshalerUtil.sizeMessage(KeyValue.VALUE, value); + size += + MarshalerUtil.sizeBytes(io.opentelemetry.proto.common.v1.internal.KeyValue.KEY, keyUtf8); + size += + MarshalerUtil.sizeMessage(io.opentelemetry.proto.common.v1.internal.KeyValue.VALUE, value); return size; } } diff --git a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java index 4b095d640d6..cd7defa9aa6 100644 --- a/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java +++ b/exporters/otlp/common/src/main/java/io/opentelemetry/exporter/internal/otlp/KeyValueStatelessMarshaler.java @@ -5,16 +5,15 @@ package io.opentelemetry.exporter.internal.otlp; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.Serializer; import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; import io.opentelemetry.exporter.internal.marshal.StatelessMarshalerUtil; -import io.opentelemetry.proto.common.v1.internal.KeyValue; import java.io.IOException; /** A Marshaler of key value pairs. See {@link AnyValueMarshaler}. */ -public final class KeyValueStatelessMarshaler implements StatelessMarshaler { +public final class KeyValueStatelessMarshaler implements StatelessMarshaler { public static final KeyValueStatelessMarshaler INSTANCE = new KeyValueStatelessMarshaler(); private static final byte[] EMPTY_BYTES = new byte[0]; @@ -22,28 +21,37 @@ public final class KeyValueStatelessMarshaler implements StatelessMarshaler { - - private static final BodyMarshaler INSTANCE = new BodyMarshaler(); - private static final AnyValue EMPTY_BODY = AnyValue.of(""); - - private BodyMarshaler() {} - - @Override - public void writeTo(Serializer output, Body value, MarshalerContext context) - throws IOException { - AnyValue anyValue; - if (value instanceof AnyValueBody) { - anyValue = ((AnyValueBody) value).asAnyValue(); - } else { - switch (value.getType()) { - case STRING: - anyValue = context.getData(AnyValue.class); - break; - case EMPTY: - anyValue = EMPTY_BODY; - break; - default: - throw new IllegalStateException("Unsupported Body type: " + value.getType()); - } - } - AnyValueStatelessMarshaler.INSTANCE.writeTo(output, anyValue, context); - } - - @Override - public int getBinarySerializedSize(Body value, MarshalerContext context) { - AnyValue anyValue; - if (value instanceof AnyValueBody) { - anyValue = ((AnyValueBody) value).asAnyValue(); - } else { - switch (value.getType()) { - case STRING: - anyValue = AnyValue.of(value.asString()); - context.addData(anyValue); - break; - case EMPTY: - anyValue = EMPTY_BODY; - break; - default: - throw new IllegalStateException("Unsupported Body type: " + value.getType()); - } - } - return AnyValueStatelessMarshaler.INSTANCE.getBinarySerializedSize(anyValue, context); - } - } } diff --git a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshalerTest.java b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/ValueMarshalerTest.java similarity index 89% rename from exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshalerTest.java rename to exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/ValueMarshalerTest.java index cd56af8fd84..d9e38900b7e 100644 --- a/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/AnyValueMarshalerTest.java +++ b/exporters/otlp/common/src/test/java/io/opentelemetry/exporter/internal/otlp/ValueMarshalerTest.java @@ -5,7 +5,7 @@ package io.opentelemetry.exporter.internal.otlp; -import static io.opentelemetry.api.incubator.logs.AnyValue.of; +import static io.opentelemetry.api.common.Value.of; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.params.provider.Arguments.arguments; @@ -13,7 +13,8 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import com.google.protobuf.util.JsonFormat; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.exporter.internal.marshal.Marshaler; import io.opentelemetry.exporter.internal.marshal.MarshalerContext; import io.opentelemetry.exporter.internal.marshal.MarshalerWithSize; @@ -21,7 +22,6 @@ import io.opentelemetry.exporter.internal.marshal.StatelessMarshaler; import io.opentelemetry.proto.common.v1.AnyValue; import io.opentelemetry.proto.common.v1.ArrayValue; -import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.common.v1.KeyValueList; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -34,22 +34,20 @@ import org.junit.jupiter.params.provider.MethodSource; @SuppressWarnings("BadImport") -class AnyValueMarshalerTest { +class ValueMarshalerTest { @ParameterizedTest @MethodSource("serializeAnyValueArgs") - void anyValueString_StatefulMarshaler( - io.opentelemetry.api.incubator.logs.AnyValue anyValue, AnyValue expectedSerializedValue) { - MarshalerWithSize marshaler = AnyValueMarshaler.create(anyValue); + void anyValueString_StatefulMarshaler(Value value, AnyValue expectedSerializedValue) { + MarshalerWithSize marshaler = AnyValueMarshaler.create(value); AnyValue serializedValue = parse(AnyValue.getDefaultInstance(), marshaler); assertThat(serializedValue).isEqualTo(expectedSerializedValue); } @ParameterizedTest @MethodSource("serializeAnyValueArgs") - void anyValueString_StatelessMarshaler( - io.opentelemetry.api.incubator.logs.AnyValue anyValue, AnyValue expectedSerializedValue) { - Marshaler marshaler = createMarshaler(AnyValueStatelessMarshaler.INSTANCE, anyValue); + void anyValueString_StatelessMarshaler(Value value, AnyValue expectedSerializedValue) { + Marshaler marshaler = createMarshaler(AnyValueStatelessMarshaler.INSTANCE, value); AnyValue serializedValue = parse(AnyValue.getDefaultInstance(), marshaler); assertThat(serializedValue).isEqualTo(expectedSerializedValue); } @@ -75,17 +73,17 @@ private static Stream serializeAnyValueArgs() { .build()), // map arguments( - of(KeyAnyValue.of("key1", of("val1")), KeyAnyValue.of("key2", of(2))), + of(KeyValue.of("key1", of("val1")), KeyValue.of("key2", of(2))), AnyValue.newBuilder() .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key1") .setValue(AnyValue.newBuilder().setStringValue("val1").build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key2") .setValue(AnyValue.newBuilder().setIntValue(2).build()) .build()) @@ -100,14 +98,15 @@ private static Stream serializeAnyValueArgs() { .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("child") .setValue( AnyValue.newBuilder() .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue + .newBuilder() .setKey("grandchild") .setValue( AnyValue.newBuilder() diff --git a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java index e90c9efe28f..9a0ffec76c6 100644 --- a/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java +++ b/integration-tests/otlp/src/main/java/io/opentelemetry/integrationtest/OtlpExporterIntegrationTest.java @@ -5,7 +5,7 @@ package io.opentelemetry.integrationtest; -import static io.opentelemetry.api.incubator.logs.AnyValue.of; +import static io.opentelemetry.api.common.Value.of; import static java.util.concurrent.CompletableFuture.completedFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; @@ -21,9 +21,9 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.KeyValue; import io.opentelemetry.api.incubator.events.EventLogger; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.metrics.LongCounter; @@ -50,7 +50,6 @@ import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse; import io.opentelemetry.proto.common.v1.AnyValue; import io.opentelemetry.proto.common.v1.ArrayValue; -import io.opentelemetry.proto.common.v1.KeyValue; import io.opentelemetry.proto.common.v1.KeyValueList; import io.opentelemetry.proto.logs.v1.ResourceLogs; import io.opentelemetry.proto.logs.v1.ScopeLogs; @@ -329,7 +328,7 @@ private static void testTraceExport(SpanExporter spanExporter) { ResourceSpans resourceSpans = request.getResourceSpans(0); assertThat(resourceSpans.getResource().getAttributesList()) .contains( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey(SERVICE_NAME.getKey()) .setValue(AnyValue.newBuilder().setStringValue("integration test").build()) .build()); @@ -348,7 +347,7 @@ private static void testTraceExport(SpanExporter spanExporter) { assertThat(protoSpan.getAttributesList()) .isEqualTo( Collections.singletonList( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key") .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build())); @@ -494,7 +493,7 @@ private static void testMetricExport(MetricExporter metricExporter) { ResourceMetrics resourceMetrics = request.getResourceMetrics(0); assertThat(resourceMetrics.getResource().getAttributesList()) .contains( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey(SERVICE_NAME.getKey()) .setValue(AnyValue.newBuilder().setStringValue("integration test").build()) .build()); @@ -519,7 +518,7 @@ private static void testMetricExport(MetricExporter metricExporter) { assertThat(dataPoint.getAttributesList()) .isEqualTo( Collections.singletonList( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key") .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build())); @@ -653,19 +652,19 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { ((ExtendedLogRecordBuilder) logger.logRecordBuilder()) .setBody( of( - KeyAnyValue.of("str_key", of("value")), - KeyAnyValue.of("bool_key", of(true)), - KeyAnyValue.of("int_key", of(1L)), - KeyAnyValue.of("double_key", of(1.1)), - KeyAnyValue.of("bytes_key", of("value".getBytes(StandardCharsets.UTF_8))), - KeyAnyValue.of("arr_key", of(of("value"), of(1L))), - KeyAnyValue.of( + KeyValue.of("str_key", of("value")), + KeyValue.of("bool_key", of(true)), + KeyValue.of("int_key", of(1L)), + KeyValue.of("double_key", of(1.1)), + KeyValue.of("bytes_key", of("value".getBytes(StandardCharsets.UTF_8))), + KeyValue.of("arr_key", of(of("value"), of(1L))), + KeyValue.of( "kv_list", of( - KeyAnyValue.of("child_str_key", of("value")), - KeyAnyValue.of( + KeyValue.of("child_str_key", of("value")), + KeyValue.of( "child_kv_list", - of(KeyAnyValue.of("grandchild_str_key", of("value")))))))) + of(KeyValue.of("grandchild_str_key", of("value")))))))) .setTimestamp(100, TimeUnit.NANOSECONDS) .setAllAttributes(Attributes.builder().put("key", "value").build()) .setSeverity(Severity.DEBUG) @@ -688,7 +687,7 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { ResourceLogs resourceLogs = request.getResourceLogs(0); assertThat(resourceLogs.getResource().getAttributesList()) .contains( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey(SERVICE_NAME.getKey()) .setValue(AnyValue.newBuilder().setStringValue("integration test").build()) .build()); @@ -706,27 +705,27 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("str_key") .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("bool_key") .setValue(AnyValue.newBuilder().setBoolValue(true).build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("int_key") .setValue(AnyValue.newBuilder().setIntValue(1).build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("double_key") .setValue(AnyValue.newBuilder().setDoubleValue(1.1).build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("bytes_key") .setValue( AnyValue.newBuilder() @@ -736,7 +735,7 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { .build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("arr_key") .setValue( AnyValue.newBuilder() @@ -752,14 +751,15 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { .build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("kv_list") .setValue( AnyValue.newBuilder() .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue + .newBuilder() .setKey("child_str_key") .setValue( AnyValue.newBuilder() @@ -767,14 +767,17 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { .build()) .build()) .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue + .newBuilder() .setKey("child_kv_list") .setValue( AnyValue.newBuilder() .setKvlistValue( KeyValueList.newBuilder() .addValues( - KeyValue.newBuilder() + io.opentelemetry.proto + .common.v1.KeyValue + .newBuilder() .setKey( "grandchild_str_key") .setValue( @@ -795,7 +798,7 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { assertThat(protoLog1.getAttributesList()) .isEqualTo( Collections.singletonList( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key") .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build())); @@ -814,13 +817,13 @@ private static void testLogRecordExporter(LogRecordExporter logRecordExporter) { io.opentelemetry.proto.logs.v1.LogRecord protoLog2 = ilLogs.getLogRecords(1); assertThat(protoLog2.getBody().getKvlistValue().getValuesList()) .containsExactlyInAnyOrder( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("key") .setValue(AnyValue.newBuilder().setStringValue("value").build()) .build()); assertThat(protoLog2.getAttributesList()) .containsExactlyInAnyOrder( - KeyValue.newBuilder() + io.opentelemetry.proto.common.v1.KeyValue.newBuilder() .setKey("event.name") .setValue(AnyValue.newBuilder().setStringValue("namespace.event-name").build()) .build()); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java index 6ab1cafe648..ce77d076730 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilder.java @@ -6,7 +6,7 @@ package io.opentelemetry.sdk.logs; import io.opentelemetry.api.common.AttributeKey; -import io.opentelemetry.api.incubator.logs.AnyValue; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; @@ -14,8 +14,6 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.AttributesMap; -import io.opentelemetry.sdk.logs.data.Body; -import io.opentelemetry.sdk.logs.internal.AnyValueBody; import java.time.Instant; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; @@ -32,7 +30,7 @@ final class SdkLogRecordBuilder implements ExtendedLogRecordBuilder { @Nullable private Context context; private Severity severity = Severity.UNDEFINED_SEVERITY_NUMBER; @Nullable private String severityText; - private Body body = Body.empty(); + @Nullable private Value body; @Nullable private AttributesMap attributes; SdkLogRecordBuilder( @@ -88,13 +86,12 @@ public SdkLogRecordBuilder setSeverityText(String severityText) { @Override public SdkLogRecordBuilder setBody(String body) { - this.body = AnyValueBody.create(AnyValue.of(body)); - return this; + return setBody(Value.of(body)); } @Override - public LogRecordBuilder setBody(AnyValue value) { - this.body = AnyValueBody.create(value); + public SdkLogRecordBuilder setBody(Value value) { + this.body = value; return this; } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordData.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordData.java index dd77c488f89..1927a0ec572 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordData.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkLogRecordData.java @@ -7,10 +7,10 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import javax.annotation.Nullable; @@ -31,7 +31,7 @@ static SdkLogRecordData create( SpanContext spanContext, Severity severity, @Nullable String severityText, - Body body, + @Nullable Value body, Attributes attributes, int totalAttributeCount) { return new AutoValue_SdkLogRecordData( @@ -42,8 +42,21 @@ static SdkLogRecordData create( spanContext, severity, severityText, - body, attributes, - totalAttributeCount); + totalAttributeCount, + body); + } + + @Override + @Nullable + public abstract Value getBodyValue(); + + @Override + @SuppressWarnings("deprecation") // Implementation of deprecated method + public io.opentelemetry.sdk.logs.data.Body getBody() { + Value valueBody = getBodyValue(); + return valueBody == null + ? io.opentelemetry.sdk.logs.data.Body.empty() + : io.opentelemetry.sdk.logs.data.Body.string(valueBody.asString()); } } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkReadWriteLogRecord.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkReadWriteLogRecord.java index c237edff511..881f1d124ee 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkReadWriteLogRecord.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/SdkReadWriteLogRecord.java @@ -7,12 +7,12 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.internal.GuardedBy; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.AttributesMap; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import javax.annotation.Nullable; @@ -29,7 +29,7 @@ class SdkReadWriteLogRecord implements ReadWriteLogRecord { private final SpanContext spanContext; private final Severity severity; @Nullable private final String severityText; - private final Body body; + @Nullable private final Value body; private final Object lock = new Object(); @GuardedBy("lock") @@ -45,7 +45,7 @@ private SdkReadWriteLogRecord( SpanContext spanContext, Severity severity, @Nullable String severityText, - Body body, + @Nullable Value body, @Nullable AttributesMap attributes) { this.logLimits = logLimits; this.resource = resource; @@ -69,7 +69,7 @@ static SdkReadWriteLogRecord create( SpanContext spanContext, Severity severity, @Nullable String severityText, - Body body, + @Nullable Value body, @Nullable AttributesMap attributes) { return new SdkReadWriteLogRecord( logLimits, diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/Body.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/Body.java index 2dc7957de91..fda485f5eaf 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/Body.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/Body.java @@ -5,6 +5,8 @@ package io.opentelemetry.sdk.logs.data; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.common.ValueType; import javax.annotation.concurrent.Immutable; /** @@ -14,16 +16,21 @@ * log data model. * * @since 1.27.0 + * @deprecated Use {@link LogRecordData#getBodyValue()} and {@link Value}. */ @Immutable +@Deprecated public interface Body { - /** An enum that represents all the possible value types for an {@code Body}. */ + /** + * An enum that represents all the possible value types for an {@code Body}. + * + * @deprecated Use {@link Value#getType()}. + */ + @Deprecated enum Type { EMPTY, STRING - // TODO (jack-berg): Add ANY_VALUE type when API for setting body to AnyValue is stable - // ANY_VALUE } /** @@ -45,9 +52,20 @@ static Body empty() { return EmptyBody.INSTANCE; } - /** Returns the String value of this {@code Body}. */ + /** + * Returns the String value of this {@code Body}. + * + *

If the log record body is some {@link ValueType} other than {@link ValueType#STRING}, this + * returns {@link Value#asString()}. Consumers should use {@link LogRecordData#getBodyValue()} + * instead. + */ String asString(); - /** Returns the type of the {@code Body}. */ + /** + * Returns the type of the {@code Body}. + * + * @deprecated Use {@link Value#getType()}. + */ + @Deprecated Type getType(); } diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/EmptyBody.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/EmptyBody.java index c70e866ee78..921895e6125 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/EmptyBody.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/EmptyBody.java @@ -5,6 +5,7 @@ package io.opentelemetry.sdk.logs.data; +@SuppressWarnings("deprecation") // Implementation of deprecated Body enum EmptyBody implements Body { INSTANCE; diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordData.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordData.java index eb2f8dcde81..6a896e48530 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordData.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/LogRecordData.java @@ -6,6 +6,8 @@ package io.opentelemetry.sdk.logs.data; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.common.ValueType; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; @@ -46,9 +48,25 @@ public interface LogRecordData { @Nullable String getSeverityText(); - /** Returns the body for this log, or {@link Body#empty()} if unset. */ + /** + * Returns the body for this log, or {@link Body#empty()} if unset. + * + *

If the body has been set to some {@link ValueType} other than {@link ValueType#STRING}, this + * will return a {@link Body} with a string representation of the {@link Value}. + * + * @deprecated Use {@link #getBodyValue()} instead. + */ + @Deprecated Body getBody(); + /** Returns the {@link Value} representation of the log body, of null if unset. */ + @Nullable + @SuppressWarnings("deprecation") // Default impl uses deprecated code for backwards compatibility + default Value getBodyValue() { + Body body = getBody(); + return body.getType() == Body.Type.EMPTY ? null : Value.of(body.asString()); + } + /** Returns the attributes for this log, or {@link Attributes#empty()} if unset. */ Attributes getAttributes(); diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/StringBody.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/StringBody.java index 4496528f7f0..a08dcab55fa 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/StringBody.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/data/StringBody.java @@ -10,6 +10,7 @@ @Immutable @AutoValue +@SuppressWarnings("deprecation") // Implementation of deprecated Body abstract class StringBody implements Body { StringBody() {} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/AnyValueBody.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/AnyValueBody.java deleted file mode 100644 index fdf2b936cd1..00000000000 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/AnyValueBody.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs.internal; - -import io.opentelemetry.api.incubator.logs.AnyValue; -import io.opentelemetry.sdk.logs.data.Body; -import javax.annotation.concurrent.Immutable; - -@Immutable -public final class AnyValueBody implements Body { - - private final AnyValue value; - - private AnyValueBody(AnyValue value) { - this.value = value; - } - - public static Body create(AnyValue value) { - return new AnyValueBody(value); - } - - @Override - public Type getType() { - return Type.STRING; - } - - @Override - public String asString() { - return value.asString(); - } - - public AnyValue asAnyValue() { - return value; - } - - @Override - public String toString() { - return "AnyValueBody{" + asString() + "}"; - } -} diff --git a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java index 5daa5ae56f4..2378d9e6dad 100644 --- a/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java +++ b/sdk/logs/src/main/java/io/opentelemetry/sdk/logs/internal/SdkEventBuilder.java @@ -7,8 +7,8 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.incubator.events.EventBuilder; -import io.opentelemetry.api.incubator.logs.AnyValue; import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; import io.opentelemetry.api.logs.LogRecordBuilder; import io.opentelemetry.api.logs.Severity; @@ -23,7 +23,7 @@ class SdkEventBuilder implements EventBuilder { private static final AttributeKey EVENT_NAME = AttributeKey.stringKey("event.name"); - private final Map> payload = new HashMap<>(); + private final Map> payload = new HashMap<>(); private final Clock clock; private final LogRecordBuilder logRecordBuilder; private final String eventName; @@ -36,7 +36,7 @@ class SdkEventBuilder implements EventBuilder { } @Override - public EventBuilder put(String key, AnyValue value) { + public EventBuilder put(String key, Value value) { payload.put(key, value); return this; } @@ -76,7 +76,7 @@ public EventBuilder setAttributes(Attributes attributes) { @Override public void emit() { if (!payload.isEmpty()) { - ((ExtendedLogRecordBuilder) logRecordBuilder).setBody(AnyValue.of(payload)); + ((ExtendedLogRecordBuilder) logRecordBuilder).setBody(Value.of(payload)); } if (!hasTimestamp) { logRecordBuilder.setTimestamp(clock.now(), TimeUnit.NANOSECONDS); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/AnyValueBodyTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/AnyValueBodyTest.java deleted file mode 100644 index 8ac803c5c7e..00000000000 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/AnyValueBodyTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.sdk.logs; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; - -import io.opentelemetry.api.incubator.logs.AnyValue; -import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; -import io.opentelemetry.api.incubator.logs.KeyAnyValue; -import io.opentelemetry.api.logs.Logger; -import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.logs.internal.AnyValueBody; -import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; -import java.nio.charset.StandardCharsets; -import java.util.LinkedHashMap; -import org.junit.jupiter.api.Test; - -class AnyValueBodyTest { - - @Test - @SuppressWarnings("DoubleBraceInitialization") - void anyValueBody() { - InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); - SdkLoggerProvider provider = - SdkLoggerProvider.builder() - .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) - .build(); - Logger logger = provider.get(AnyValueBodyTest.class.getName()); - - // AnyValue can be a primitive type, like a string, long, double, boolean - extendedLogRecordBuilder(logger).setBody(AnyValue.of(1)).emit(); - assertThat(exporter.getFinishedLogRecordItems()) - .hasSize(1) - .satisfiesExactly( - logRecordData -> { - // TODO (jack-berg): add assertion when ANY_VALUE is added to Body.Type - // assertThat(logRecordData.getBody().getType()).isEqualTo(Body.Type.ANY_VALUE); - assertThat(logRecordData.getBody().asString()).isEqualTo("1"); - assertThat(((AnyValueBody) logRecordData.getBody()).asAnyValue()) - .isEqualTo(AnyValue.of(1)); - }); - exporter.reset(); - - // ...or a byte array of raw data - extendedLogRecordBuilder(logger) - .setBody(AnyValue.of("hello world".getBytes(StandardCharsets.UTF_8))) - .emit(); - assertThat(exporter.getFinishedLogRecordItems()) - .hasSize(1) - .satisfiesExactly( - logRecordData -> { - // TODO (jack-berg): add assertion when ANY_VALUE is added to Body.Type - // assertThat(logRecordData.getBody().getType()).isEqualTo(Body.Type.ANY_VALUE); - assertThat(logRecordData.getBody().asString()).isEqualTo("aGVsbG8gd29ybGQ="); - assertThat(((AnyValueBody) logRecordData.getBody()).asAnyValue()) - .isEqualTo(AnyValue.of("hello world".getBytes(StandardCharsets.UTF_8))); - }); - exporter.reset(); - - // But most commonly it will be used to represent complex structured like a map - extendedLogRecordBuilder(logger) - .setBody( - // The protocol data structure uses a repeated KeyValue to represent a map: - // https://github.com/open-telemetry/opentelemetry-proto/blob/ac3242b03157295e4ee9e616af53b81517b06559/opentelemetry/proto/common/v1/common.proto#L59 - // The comment says that keys aren't allowed to repeat themselves, and because its - // represented as a repeated KeyValue, we need to at least offer the ability to preserve - // order. - // Accepting a Map> makes for a cleaner API, but ordering of the - // entries is lost. To accommodate use cases where ordering should be preserved we - // accept an array of key value pairs, but also a map based alternative (see the - // key_value_list_key entry). - AnyValue.of( - KeyAnyValue.of("str_key", AnyValue.of("value")), - KeyAnyValue.of("bool_key", AnyValue.of(true)), - KeyAnyValue.of("long_key", AnyValue.of(1L)), - KeyAnyValue.of("double_key", AnyValue.of(1.1)), - KeyAnyValue.of("bytes_key", AnyValue.of("bytes".getBytes(StandardCharsets.UTF_8))), - KeyAnyValue.of( - "arr_key", - AnyValue.of(AnyValue.of("entry1"), AnyValue.of(2), AnyValue.of(3.3))), - KeyAnyValue.of( - "key_value_list_key", - AnyValue.of( - new LinkedHashMap>() { - { - put("child_str_key1", AnyValue.of("child_value1")); - put("child_str_key2", AnyValue.of("child_value2")); - } - })))) - .emit(); - assertThat(exporter.getFinishedLogRecordItems()) - .hasSize(1) - .satisfiesExactly( - logRecordData -> { - // TODO (jack-berg): add assertion when ANY_VALUE is added to Body.Type - // assertThat(logRecordData.getBody().getType()).isEqualTo(Body.Type.ANY_VALUE); - assertThat(logRecordData.getBody().asString()) - .isEqualTo( - "[" - + "str_key=value, " - + "bool_key=true, " - + "long_key=1, " - + "double_key=1.1, " - + "bytes_key=Ynl0ZXM=, " - + "arr_key=[entry1, 2, 3.3], " - + "key_value_list_key=[child_str_key1=child_value1, child_str_key2=child_value2]" - + "]"); - assertThat(((AnyValueBody) logRecordData.getBody()).asAnyValue()) - .isEqualTo( - AnyValue.of( - KeyAnyValue.of("str_key", AnyValue.of("value")), - KeyAnyValue.of("bool_key", AnyValue.of(true)), - KeyAnyValue.of("long_key", AnyValue.of(1L)), - KeyAnyValue.of("double_key", AnyValue.of(1.1)), - KeyAnyValue.of( - "bytes_key", AnyValue.of("bytes".getBytes(StandardCharsets.UTF_8))), - KeyAnyValue.of( - "arr_key", - AnyValue.of(AnyValue.of("entry1"), AnyValue.of(2), AnyValue.of(3.3))), - KeyAnyValue.of( - "key_value_list_key", - AnyValue.of( - new LinkedHashMap>() { - { - put("child_str_key1", AnyValue.of("child_value1")); - put("child_str_key2", AnyValue.of("child_value2")); - } - })))); - }); - exporter.reset(); - - // ..or an array (optionally with heterogeneous types) - extendedLogRecordBuilder(logger) - .setBody(AnyValue.of(AnyValue.of("entry1"), AnyValue.of("entry2"), AnyValue.of(3))) - .emit(); - assertThat(exporter.getFinishedLogRecordItems()) - .hasSize(1) - .satisfiesExactly( - logRecordData -> { - // TODO (jack-berg): add assertion when ANY_VALUE is added to Body.Type - // assertThat(logRecordData.getBody().getType()).isEqualTo(Body.Type.ANY_VALUE); - assertThat(logRecordData.getBody().asString()).isEqualTo("[entry1, entry2, 3]"); - assertThat(((AnyValueBody) logRecordData.getBody()).asAnyValue()) - .isEqualTo( - AnyValue.of(AnyValue.of("entry1"), AnyValue.of("entry2"), AnyValue.of(3))); - }); - exporter.reset(); - } - - ExtendedLogRecordBuilder extendedLogRecordBuilder(Logger logger) { - return (ExtendedLogRecordBuilder) logger.logRecordBuilder(); - } -} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ReadWriteLogRecordTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ReadWriteLogRecordTest.java index ccb6c56ebbc..e671372c515 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ReadWriteLogRecordTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ReadWriteLogRecordTest.java @@ -9,11 +9,11 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; import io.opentelemetry.sdk.internal.AttributesMap; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.resources.Resource; import org.junit.jupiter.api.Test; @@ -49,7 +49,7 @@ void allHandlesEmpty() { } SdkReadWriteLogRecord buildLogRecord() { - Body body = Body.string("bod"); + Value body = Value.of("bod"); AttributesMap initialAttributes = AttributesMap.create(100, 200); initialAttributes.put(stringKey("foo"), "aaiosjfjioasdiojfjioasojifja"); initialAttributes.put(stringKey("untouched"), "yes"); diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java index ff191032265..3c5743e673d 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/SdkLogRecordBuilderTest.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanContext; @@ -18,7 +19,6 @@ import io.opentelemetry.context.Context; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.resources.Resource; import java.time.Instant; import java.util.concurrent.TimeUnit; @@ -105,7 +105,7 @@ void emit_NoFields() { assertThat(emittedLog.get().toLogRecordData()) .hasResource(RESOURCE) .hasInstrumentationScope(SCOPE_INFO) - .hasBody(Body.empty().asString()) + .hasBody((Value) null) .hasTimestamp(0L) .hasObservedTimestamp(10L) .hasAttributes(Attributes.empty()) diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ValueBodyTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ValueBodyTest.java new file mode 100644 index 00000000000..cd5820bb974 --- /dev/null +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/ValueBodyTest.java @@ -0,0 +1,171 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.logs; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import io.opentelemetry.api.common.KeyValue; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.common.ValueType; +import io.opentelemetry.api.incubator.logs.ExtendedLogRecordBuilder; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.LinkedHashMap; +import org.junit.jupiter.api.Test; + +class ValueBodyTest { + + @Test + @SuppressWarnings("DoubleBraceInitialization") + void valueBody() { + InMemoryLogRecordExporter exporter = InMemoryLogRecordExporter.create(); + SdkLoggerProvider provider = + SdkLoggerProvider.builder() + .addLogRecordProcessor(SimpleLogRecordProcessor.create(exporter)) + .build(); + Logger logger = provider.get(ValueBodyTest.class.getName()); + + // Value can be a primitive type, like a string, long, double, boolean + extendedLogRecordBuilder(logger).setBody(Value.of(1)).emit(); + assertThat(exporter.getFinishedLogRecordItems()) + .hasSize(1) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getBodyValue()) + .isNotNull() + .satisfies( + body -> { + assertThat(body.getType()).isEqualTo(ValueType.LONG); + assertThat((Long) body.getValue()).isEqualTo(1L); + }); + }); + exporter.reset(); + + // ...or a byte array of raw data + extendedLogRecordBuilder(logger) + .setBody(Value.of("hello world".getBytes(StandardCharsets.UTF_8))) + .emit(); + assertThat(exporter.getFinishedLogRecordItems()) + .hasSize(1) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getBodyValue()) + .isNotNull() + .satisfies( + body -> { + assertThat(body.getType()).isEqualTo(ValueType.BYTES); + assertThat((ByteBuffer) body.getValue()) + .isEqualTo( + ByteBuffer.wrap("hello world".getBytes(StandardCharsets.UTF_8))); + }); + }); + exporter.reset(); + + // But most commonly it will be used to represent complex structured like a map + extendedLogRecordBuilder(logger) + .setBody( + // The protocol data structure uses a repeated KeyValue to represent a map: + // https://github.com/open-telemetry/opentelemetry-proto/blob/ac3242b03157295e4ee9e616af53b81517b06559/opentelemetry/proto/common/v1/common.proto#L59 + // The comment says that keys aren't allowed to repeat themselves, and because its + // represented as a repeated KeyValue, we need to at least offer the ability to preserve + // order. + // Accepting a Map> makes for a cleaner API, but ordering of the + // entries is lost. To accommodate use cases where ordering should be preserved we + // accept an array of key value pairs, but also a map based alternative (see the + // key_value_list_key entry). + Value.of( + KeyValue.of("str_key", Value.of("value")), + KeyValue.of("bool_key", Value.of(true)), + KeyValue.of("long_key", Value.of(1L)), + KeyValue.of("double_key", Value.of(1.1)), + KeyValue.of("bytes_key", Value.of("bytes".getBytes(StandardCharsets.UTF_8))), + KeyValue.of("arr_key", Value.of(Value.of("entry1"), Value.of(2), Value.of(3.3))), + KeyValue.of( + "key_value_list_key", + Value.of( + new LinkedHashMap>() { + { + put("child_str_key1", Value.of("child_value1")); + put("child_str_key2", Value.of("child_value2")); + } + })))) + .emit(); + assertThat(exporter.getFinishedLogRecordItems()) + .hasSize(1) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getBodyValue()) + .isNotNull() + // TODO: use fluent asserts when available. See + // https://github.com/open-telemetry/opentelemetry-java/pull/6509 + .satisfies( + body -> { + assertThat(body.getType()).isEqualTo(ValueType.KEY_VALUE_LIST); + assertThat(body) + .isEqualTo( + Value.of( + KeyValue.of("str_key", Value.of("value")), + KeyValue.of("bool_key", Value.of(true)), + KeyValue.of("long_key", Value.of(1L)), + KeyValue.of("double_key", Value.of(1.1)), + KeyValue.of( + "bytes_key", + Value.of("bytes".getBytes(StandardCharsets.UTF_8))), + KeyValue.of( + "arr_key", + Value.of(Value.of("entry1"), Value.of(2), Value.of(3.3))), + KeyValue.of( + "key_value_list_key", + Value.of( + new LinkedHashMap>() { + { + put("child_str_key1", Value.of("child_value1")); + put("child_str_key2", Value.of("child_value2")); + } + })))); + assertThat(body.asString()) + .isEqualTo( + "[" + + "str_key=value, " + + "bool_key=true, " + + "long_key=1, " + + "double_key=1.1, " + + "bytes_key=Ynl0ZXM=, " + + "arr_key=[entry1, 2, 3.3], " + + "key_value_list_key=[child_str_key1=child_value1, child_str_key2=child_value2]" + + "]"); + }); + }); + exporter.reset(); + + // ..or an array (optionally with heterogeneous types) + extendedLogRecordBuilder(logger) + .setBody(Value.of(Value.of("entry1"), Value.of("entry2"), Value.of(3))) + .emit(); + assertThat(exporter.getFinishedLogRecordItems()) + .hasSize(1) + .satisfiesExactly( + logRecordData -> { + assertThat(logRecordData.getBodyValue()) + .isNotNull() + .satisfies( + body -> { + assertThat(body.getType()).isEqualTo(ValueType.ARRAY); + assertThat(body) + .isEqualTo( + Value.of(Value.of("entry1"), Value.of("entry2"), Value.of(3))); + }); + }); + exporter.reset(); + } + + ExtendedLogRecordBuilder extendedLogRecordBuilder(Logger logger) { + return (ExtendedLogRecordBuilder) logger.logRecordBuilder(); + } +} diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/BodyTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/BodyTest.java index d57fb085fb0..57143d4f49f 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/BodyTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/data/BodyTest.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; +@SuppressWarnings("deprecation") // Testing deprecated code class BodyTest { @Test diff --git a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventLoggerProviderTest.java b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventLoggerProviderTest.java index 71f48757207..d033ba9bc15 100644 --- a/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventLoggerProviderTest.java +++ b/sdk/logs/src/test/java/io/opentelemetry/sdk/logs/internal/SdkEventLoggerProviderTest.java @@ -12,8 +12,8 @@ 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 io.opentelemetry.api.incubator.events.EventLogger; -import io.opentelemetry.api.incubator.logs.AnyValue; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; @@ -69,10 +69,8 @@ void builder() { .put("extra-attribute", "value") .build()); assertThat(seenLog.get().toLogRecordData().getObservedTimestampEpochNanos()).isPositive(); - AnyValue expectedPayload = - AnyValue.of(Collections.singletonMap("key1", AnyValue.of("value1"))); - assertThat(((AnyValueBody) seenLog.get().toLogRecordData().getBody()).asAnyValue()) - .isEqualTo(expectedPayload); + Value expectedPayload = Value.of(Collections.singletonMap("key1", Value.of("value1"))); + assertThat(seenLog.get().toLogRecordData().getBodyValue()).isEqualTo(expectedPayload); } @Test @@ -91,13 +89,13 @@ void eventBuilder_FullPayload() { .put("longArrKey", 1L, 2L) .put("doubleArrKey", 1.0, 2.0) .put("boolArrKey", true, false) - // Set AnyValue types to encode complex data + // Set complex data .put( - "anyValueKey", - AnyValue.of( + "valueKey", + Value.of( ImmutableMap.of( - "childKey1", AnyValue.of("value"), - "childKey2", AnyValue.of("value")))) + "childKey1", Value.of("value"), + "childKey2", Value.of("value")))) // Helper methods to set AttributeKey types .put(AttributeKey.stringKey("attrStringKey"), "value") .put(AttributeKey.longKey("attrLongKey"), 1L) @@ -109,38 +107,31 @@ void eventBuilder_FullPayload() { .put(AttributeKey.booleanArrayKey("attrBoolArrKey"), Arrays.asList(true, false)) .emit(); - Map> expectedPayload = new HashMap<>(); - expectedPayload.put("stringKey", AnyValue.of("value")); - expectedPayload.put("longKey", AnyValue.of(1L)); - expectedPayload.put("doubleKey", AnyValue.of(1.0)); - expectedPayload.put("boolKey", AnyValue.of(true)); + Map> expectedPayload = new HashMap<>(); + expectedPayload.put("stringKey", Value.of("value")); + expectedPayload.put("longKey", Value.of(1L)); + expectedPayload.put("doubleKey", Value.of(1.0)); + expectedPayload.put("boolKey", Value.of(true)); expectedPayload.put( - "stringArrKey", AnyValue.of(Arrays.asList(AnyValue.of("value1"), AnyValue.of("value2")))); - expectedPayload.put("longArrKey", AnyValue.of(Arrays.asList(AnyValue.of(1L), AnyValue.of(2L)))); + "stringArrKey", Value.of(Arrays.asList(Value.of("value1"), Value.of("value2")))); + expectedPayload.put("longArrKey", Value.of(Arrays.asList(Value.of(1L), Value.of(2L)))); + expectedPayload.put("doubleArrKey", Value.of(Arrays.asList(Value.of(1.0), Value.of(2.0)))); + expectedPayload.put("boolArrKey", Value.of(Arrays.asList(Value.of(true), Value.of(false)))); expectedPayload.put( - "doubleArrKey", AnyValue.of(Arrays.asList(AnyValue.of(1.0), AnyValue.of(2.0)))); - expectedPayload.put( - "boolArrKey", AnyValue.of(Arrays.asList(AnyValue.of(true), AnyValue.of(false)))); - expectedPayload.put( - "anyValueKey", - AnyValue.of( + "valueKey", + Value.of( ImmutableMap.of( - "childKey1", AnyValue.of("value"), - "childKey2", AnyValue.of("value")))); - expectedPayload.put("attrStringKey", AnyValue.of("value")); - expectedPayload.put("attrLongKey", AnyValue.of(1L)); - expectedPayload.put("attrDoubleKey", AnyValue.of(1.0)); - expectedPayload.put("attrBoolKey", AnyValue.of(true)); - expectedPayload.put( - "attrStringArrKey", - AnyValue.of(Arrays.asList(AnyValue.of("value1"), AnyValue.of("value2")))); - expectedPayload.put( - "attrLongArrKey", AnyValue.of(Arrays.asList(AnyValue.of(1L), AnyValue.of(2L)))); - expectedPayload.put( - "attrDoubleArrKey", AnyValue.of(Arrays.asList(AnyValue.of(1.0), AnyValue.of(2.0)))); + "childKey1", Value.of("value"), + "childKey2", Value.of("value")))); + expectedPayload.put("attrStringKey", Value.of("value")); + expectedPayload.put("attrLongKey", Value.of(1L)); + expectedPayload.put("attrDoubleKey", Value.of(1.0)); + expectedPayload.put("attrBoolKey", Value.of(true)); expectedPayload.put( - "attrBoolArrKey", AnyValue.of(Arrays.asList(AnyValue.of(true), AnyValue.of(false)))); - assertThat(((AnyValueBody) seenLog.get().toLogRecordData().getBody()).asAnyValue()) - .isEqualTo(AnyValue.of(expectedPayload)); + "attrStringArrKey", Value.of(Arrays.asList(Value.of("value1"), Value.of("value2")))); + expectedPayload.put("attrLongArrKey", Value.of(Arrays.asList(Value.of(1L), Value.of(2L)))); + expectedPayload.put("attrDoubleArrKey", Value.of(Arrays.asList(Value.of(1.0), Value.of(2.0)))); + expectedPayload.put("attrBoolArrKey", Value.of(Arrays.asList(Value.of(true), Value.of(false)))); + assertThat(seenLog.get().toLogRecordData().getBodyValue()).isEqualTo(Value.of(expectedPayload)); } } diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/assertj/LogRecordDataAssert.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/assertj/LogRecordDataAssert.java index 7489cb135b5..11031aa9ef4 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/assertj/LogRecordDataAssert.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/assertj/LogRecordDataAssert.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.common.AttributesBuilder; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; @@ -17,6 +18,7 @@ import io.opentelemetry.sdk.resources.Resource; import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.function.Consumer; import javax.annotation.Nullable; import org.assertj.core.api.AbstractAssert; @@ -54,8 +56,7 @@ public LogRecordDataAssert hasResource(Resource resource) { public LogRecordDataAssert hasResourceSatisfying(Consumer resource) { isNotNull(); resource.accept( - new ResourceAssert( - actual.getResource(), String.format("log [%s]", actual.getBody().asString()))); + new ResourceAssert(actual.getResource(), String.format("log [%s]", actual.getBodyValue()))); return this; } @@ -149,13 +150,19 @@ public LogRecordDataAssert hasSeverityText(String severityText) { /** Asserts the log has the given body. */ public LogRecordDataAssert hasBody(String body) { isNotNull(); - if (!actual.getBody().asString().equals(body)) { + return hasBody(Value.of(body)); + } + + /** Asserts the log has the given body. */ + public LogRecordDataAssert hasBody(@Nullable Value body) { + isNotNull(); + if (!Objects.equals(actual.getBodyValue(), body)) { failWithActualExpectedAndMessage( - actual.getBody(), + actual.getBodyValue(), body, "Expected log to have body <%s> but was <%s>", body, - actual.getBody().asString()); + actual.getBodyValue()); } return this; } diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/logs/TestLogRecordData.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/logs/TestLogRecordData.java index 7de560fac49..efb2fee37ca 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/logs/TestLogRecordData.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/logs/TestLogRecordData.java @@ -7,14 +7,15 @@ import com.google.auto.value.AutoValue; import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Severity; import io.opentelemetry.api.trace.SpanContext; import io.opentelemetry.sdk.common.InstrumentationScopeInfo; -import io.opentelemetry.sdk.logs.data.Body; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.resources.Resource; import java.time.Instant; import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** @@ -24,6 +25,9 @@ */ @Immutable @AutoValue +@AutoValue.CopyAnnotations +// Carry suppression for Body to AutoValue implementation via @AutoValue.CopyAnnotations +@SuppressWarnings("deprecation") public abstract class TestLogRecordData implements LogRecordData { /** Creates a new Builder for creating an {@link LogRecordData} instance. */ @@ -35,11 +39,22 @@ public static Builder builder() { .setObservedTimestamp(0, TimeUnit.NANOSECONDS) .setSpanContext(SpanContext.getInvalid()) .setSeverity(Severity.UNDEFINED_SEVERITY_NUMBER) - .setBody("") .setAttributes(Attributes.empty()) .setTotalAttributeCount(0); } + @Deprecated + public io.opentelemetry.sdk.logs.data.Body getBody() { + Value valueBody = getBodyValue(); + return valueBody == null + ? io.opentelemetry.sdk.logs.data.Body.empty() + : io.opentelemetry.sdk.logs.data.Body.string(valueBody.asString()); + } + + @Override + @Nullable + public abstract Value getBodyValue(); + TestLogRecordData() {} /** A {@code Builder} class for {@link TestLogRecordData}. */ @@ -123,11 +138,26 @@ public Builder setObservedTimestamp(long timestamp, TimeUnit unit) { /** Set the body string. */ public Builder setBody(String body) { - return setBody(Body.string(body)); + return setBodyValue(Value.of(body)); + } + + /** + * Set the body. + * + * @deprecated Use {@link #setBodyValue(Value)}. + */ + @Deprecated + public Builder setBody(io.opentelemetry.sdk.logs.data.Body body) { + if (body.getType() == io.opentelemetry.sdk.logs.data.Body.Type.STRING) { + setBodyValue(Value.of(body.asString())); + } else if (body.getType() == io.opentelemetry.sdk.logs.data.Body.Type.EMPTY) { + setBodyValue(null); + } + return this; } /** Set the body. */ - abstract Builder setBody(Body body); + public abstract Builder setBodyValue(@Nullable Value body); /** Set the attributes. */ public abstract Builder setAttributes(Attributes attributes); diff --git a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRuleTest.java b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRuleTest.java index b8a14c5975d..a068d40bd0e 100644 --- a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRuleTest.java +++ b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRuleTest.java @@ -7,6 +7,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; @@ -94,12 +95,12 @@ public void getLogRecords() { assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); // Logs cleared between tests, not when retrieving assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); } // We have two tests to verify logs get cleared up between tests. @@ -110,11 +111,11 @@ public void getLogRecordsAgain() { assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); // Logs cleared between tests, not when retrieving assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); } } diff --git a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtensionTest.java b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtensionTest.java index f2e7257b2bd..e91d3f036ea 100644 --- a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtensionTest.java +++ b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtensionTest.java @@ -10,6 +10,7 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Value; import io.opentelemetry.api.logs.Logger; import io.opentelemetry.api.metrics.LongCounter; import io.opentelemetry.api.metrics.Meter; @@ -184,12 +185,12 @@ public void getLogRecords() { assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); // Logs cleared between tests, not when retrieving assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); } // We have two tests to verify spans get cleared up between tests. @@ -200,12 +201,12 @@ public void getLogRecordsAgain() { assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); // Logs cleared between tests, not when retrieving assertThat(otelTesting.getLogRecords()) .singleElement() .satisfies( - logRecordData -> assertThat(logRecordData.getBody().asString()).isEqualTo("body")); + logRecordData -> assertThat(logRecordData.getBodyValue()).isEqualTo(Value.of("body"))); } @Test