diff --git a/api/src/main/java/io/opentelemetry/common/AttributeValue.java b/api/src/main/java/io/opentelemetry/common/AttributeValue.java index bf86a586cfb..8fc8d00fdf5 100644 --- a/api/src/main/java/io/opentelemetry/common/AttributeValue.java +++ b/api/src/main/java/io/opentelemetry/common/AttributeValue.java @@ -17,6 +17,10 @@ package io.opentelemetry.common; import com.google.auto.value.AutoValue; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; @@ -39,7 +43,11 @@ public enum Type { STRING, BOOLEAN, LONG, - DOUBLE + DOUBLE, + STRING_ARRAY, + BOOLEAN_ARRAY, + LONG_ARRAY, + DOUBLE_ARRAY } /** @@ -86,6 +94,50 @@ public static AttributeValue doubleAttributeValue(double doubleValue) { return AttributeValueDouble.create(doubleValue); } + /** + * Returns an {@code AttributeValue} with a String array value. + * + * @param stringValues The new values. + * @return an {@code AttributeValue} with a String array value. + * @since 0.3.0 + */ + public static AttributeValue arrayAttributeValue(String... stringValues) { + return AttributeValueStringArray.create(stringValues); + } + + /** + * Returns an {@code AttributeValue} with a boolean array value. + * + * @param booleanValues The new values. + * @return an {@code AttributeValue} with a boolean array value. + * @since 0.3.0 + */ + public static AttributeValue arrayAttributeValue(Boolean... booleanValues) { + return AttributeValueBooleanArray.create(booleanValues); + } + + /** + * Returns an {@code AttributeValue} with a long array value. + * + * @param longValues The new values. + * @return an {@code AttributeValue} with a long array value. + * @since 0.3.0 + */ + public static AttributeValue arrayAttributeValue(Long... longValues) { + return AttributeValueLongArray.create(longValues); + } + + /** + * Returns an {@code AttributeValue} with a double array value. + * + * @param doubleValues The new values. + * @return an {@code AttributeValue} with a double array value. + * @since 0.3.0 + */ + public static AttributeValue arrayAttributeValue(Double... doubleValues) { + return AttributeValueDoubleArray.create(doubleValues); + } + AttributeValue() {} /** @@ -136,6 +188,54 @@ public double getDoubleValue() { String.format("This type can only return %s data", getType().name())); } + /** + * Returns the String array value of this {@code AttributeValue}. An UnsupportedOperationException + * will be thrown if getType() is not {@link Type#STRING_ARRAY}. + * + * @return the array values of this {@code AttributeValue}. + * @since 0.3.0 + */ + public List getStringArrayValue() { + throw new UnsupportedOperationException( + String.format("This type can only return %s data", getType().name())); + } + + /** + * Returns the boolean array value of this {@code AttributeValue}. An + * UnsupportedOperationException will be thrown if getType() is not {@link Type#BOOLEAN_ARRAY}. + * + * @return the array values of this {@code AttributeValue}. + * @since 0.3.0 + */ + public List getBooleanArrayValue() { + throw new UnsupportedOperationException( + String.format("This type can only return %s data", getType().name())); + } + + /** + * Returns the long array value of this {@code AttributeValue}. An UnsupportedOperationException + * will be thrown if getType() is not {@link Type#LONG_ARRAY}. + * + * @return the array values of this {@code AttributeValue}. + * @since 0.3.0 + */ + public List getLongArrayValue() { + throw new UnsupportedOperationException( + String.format("This type can only return %s data", getType().name())); + } + + /** + * Returns the double array value of this {@code AttributeValue}. An UnsupportedOperationException + * will be thrown if getType() is not {@link Type#DOUBLE_ARRAY}. + * + * @return the array values of this {@code AttributeValue}. + * @since 0.3.0 + */ + public List getDoubleArrayValue() { + throw new UnsupportedOperationException( + String.format("This type can only return %s data", getType().name())); + } + /** * Returns a {@code Type} corresponding to the underlying value of this {@code AttributeValue}. * @@ -220,4 +320,111 @@ public final Type getType() { @Override public abstract double getDoubleValue(); } + + @Immutable + @AutoValue + abstract static class AttributeValueStringArray extends AttributeValue { + + AttributeValueStringArray() {} + + static AttributeValue create(String... stringValues) { + if (stringValues == null) { + return new AutoValue_AttributeValue_AttributeValueStringArray( + Collections.emptyList()); + } + return new AutoValue_AttributeValue_AttributeValueStringArray( + Collections.unmodifiableList(Arrays.asList(stringValues))); + } + + @Override + public final Type getType() { + return Type.STRING_ARRAY; + } + + @Override + public abstract List getStringArrayValue(); + } + + @Immutable + @AutoValue + abstract static class AttributeValueBooleanArray extends AttributeValue { + + AttributeValueBooleanArray() {} + + static AttributeValue create(Boolean... booleanValues) { + if (booleanValues == null) { + return new AutoValue_AttributeValue_AttributeValueBooleanArray( + Collections.emptyList()); + } + List values = new ArrayList<>(booleanValues.length); + for (Boolean value : booleanValues) { + values.add(value); + } + return new AutoValue_AttributeValue_AttributeValueBooleanArray( + Collections.unmodifiableList(values)); + } + + @Override + public final Type getType() { + return Type.BOOLEAN_ARRAY; + } + + @Override + public abstract List getBooleanArrayValue(); + } + + @Immutable + @AutoValue + abstract static class AttributeValueLongArray extends AttributeValue { + + AttributeValueLongArray() {} + + static AttributeValue create(Long... longValues) { + if (longValues == null) { + return new AutoValue_AttributeValue_AttributeValueLongArray(Collections.emptyList()); + } + List values = new ArrayList<>(longValues.length); + for (Long value : longValues) { + values.add(value); + } + return new AutoValue_AttributeValue_AttributeValueLongArray( + Collections.unmodifiableList(values)); + } + + @Override + public final Type getType() { + return Type.LONG_ARRAY; + } + + @Override + public abstract List getLongArrayValue(); + } + + @Immutable + @AutoValue + abstract static class AttributeValueDoubleArray extends AttributeValue { + + AttributeValueDoubleArray() {} + + static AttributeValue create(Double... doubleValues) { + if (doubleValues == null) { + return new AutoValue_AttributeValue_AttributeValueDoubleArray( + Collections.emptyList()); + } + List values = new ArrayList<>(doubleValues.length); + for (Double value : doubleValues) { + values.add(value); + } + return new AutoValue_AttributeValue_AttributeValueDoubleArray( + Collections.unmodifiableList(values)); + } + + @Override + public final Type getType() { + return Type.DOUBLE_ARRAY; + } + + @Override + public abstract List getDoubleArrayValue(); + } } diff --git a/api/src/test/java/io/opentelemetry/common/AttributeValueTest.java b/api/src/test/java/io/opentelemetry/common/AttributeValueTest.java index c9755b9700d..713227bbca6 100644 --- a/api/src/test/java/io/opentelemetry/common/AttributeValueTest.java +++ b/api/src/test/java/io/opentelemetry/common/AttributeValueTest.java @@ -43,9 +43,36 @@ public void attributeValue_EqualsAndHashCode() { tester.addEqualityGroup( AttributeValue.doubleAttributeValue(1.23456), AttributeValue.doubleAttributeValue(1.23456)); tester.addEqualityGroup(AttributeValue.doubleAttributeValue(1.234567)); + tester.addEqualityGroup( + AttributeValue.arrayAttributeValue( + "MyArrayStringAttributeValue1", "MyArrayStringAttributeValue2"), + AttributeValue.arrayAttributeValue( + "MyArrayStringAttributeValue1", "MyArrayStringAttributeValue2")); + tester.addEqualityGroup(AttributeValue.arrayAttributeValue("MyArrayStringAttributeDiffValue")); + tester.addEqualityGroup( + AttributeValue.arrayAttributeValue(true, false, true), + AttributeValue.arrayAttributeValue(true, false, true)); + tester.addEqualityGroup(AttributeValue.arrayAttributeValue(false)); + tester.addEqualityGroup( + AttributeValue.arrayAttributeValue(123456L, 7890L), + AttributeValue.arrayAttributeValue(123456L, 7890L)); + tester.addEqualityGroup(AttributeValue.arrayAttributeValue(1234567L)); + tester.addEqualityGroup( + AttributeValue.arrayAttributeValue(1.23456, 7.890), + AttributeValue.arrayAttributeValue(1.23456, 7.890)); + tester.addEqualityGroup(AttributeValue.arrayAttributeValue(1.234567)); tester.testEquals(); } + @Test + public void doNotCrashOnNull() { + AttributeValue.stringAttributeValue(null); + AttributeValue.arrayAttributeValue((String[]) null); + AttributeValue.arrayAttributeValue((Boolean[]) null); + AttributeValue.arrayAttributeValue((Long[]) null); + AttributeValue.arrayAttributeValue((Double[]) null); + } + @Test public void attributeValue_ToString() { AttributeValue attribute = AttributeValue.stringAttributeValue("MyStringAttributeValue"); @@ -56,5 +83,36 @@ public void attributeValue_ToString() { assertThat(attribute.toString()).contains("123456"); attribute = AttributeValue.doubleAttributeValue(1.23456); assertThat(attribute.toString()).contains("1.23456"); + attribute = + AttributeValue.arrayAttributeValue( + "MyArrayStringAttributeValue1", "MyArrayStringAttributeValue2"); + assertThat(attribute.toString()).contains("MyArrayStringAttributeValue1"); + assertThat(attribute.toString()).contains("MyArrayStringAttributeValue2"); + attribute = AttributeValue.arrayAttributeValue(true, false); + assertThat(attribute.toString()).contains("true"); + assertThat(attribute.toString()).contains("false"); + attribute = AttributeValue.arrayAttributeValue(12345L, 67890L); + assertThat(attribute.toString()).contains("12345"); + assertThat(attribute.toString()).contains("67890"); + attribute = AttributeValue.arrayAttributeValue(1.2345, 6.789); + assertThat(attribute.toString()).contains("1.2345"); + assertThat(attribute.toString()).contains("6.789"); + } + + @Test + public void arrayAttributeValue_nullValuesWithinArray() { + AttributeValue attribute; + + attribute = AttributeValue.arrayAttributeValue("string", null, "", "string"); + assertThat(attribute.getStringArrayValue().size()).isEqualTo(4); + + attribute = AttributeValue.arrayAttributeValue(10L, null, 20L); + assertThat(attribute.getLongArrayValue().size()).isEqualTo(3); + + attribute = AttributeValue.arrayAttributeValue(true, null, false); + assertThat(attribute.getBooleanArrayValue().size()).isEqualTo(3); + + attribute = AttributeValue.arrayAttributeValue(1.2, null, 3.4); + assertThat(attribute.getDoubleArrayValue().size()).isEqualTo(3); } } diff --git a/api/src/test/java/io/opentelemetry/trace/DefaultSpanTest.java b/api/src/test/java/io/opentelemetry/trace/DefaultSpanTest.java index 0a930e0a342..c27e606c68b 100644 --- a/api/src/test/java/io/opentelemetry/trace/DefaultSpanTest.java +++ b/api/src/test/java/io/opentelemetry/trace/DefaultSpanTest.java @@ -56,6 +56,10 @@ public void doNotCrash() { span.setAttribute("MyLongAttributeKey", AttributeValue.longAttributeValue(123)); span.setAttribute("NullString", (String) null); span.setAttribute("EmptyString", ""); + span.setAttribute("NullArrayString", AttributeValue.arrayAttributeValue((String[]) null)); + span.setAttribute("NullArrayBoolean", AttributeValue.arrayAttributeValue((Boolean[]) null)); + span.setAttribute("NullArrayLong", AttributeValue.arrayAttributeValue((Long[]) null)); + span.setAttribute("NullArrayDouble", AttributeValue.arrayAttributeValue((Double[]) null)); span.addEvent("event"); span.addEvent("event", 0); span.addEvent( diff --git a/exporters/jaeger/src/main/java/io/opentelemetry/exporters/jaeger/Adapter.java b/exporters/jaeger/src/main/java/io/opentelemetry/exporters/jaeger/Adapter.java index aad633147f8..56fcfeb2619 100644 --- a/exporters/jaeger/src/main/java/io/opentelemetry/exporters/jaeger/Adapter.java +++ b/exporters/jaeger/src/main/java/io/opentelemetry/exporters/jaeger/Adapter.java @@ -17,6 +17,7 @@ package io.opentelemetry.exporters.jaeger; import com.google.common.annotations.VisibleForTesting; +import com.google.gson.Gson; import com.google.protobuf.Timestamp; import com.google.protobuf.util.Timestamps; import io.opentelemetry.common.AttributeValue; @@ -193,8 +194,23 @@ static Model.KeyValue toKeyValue(String key, AttributeValue value) { builder.setVFloat64(value.getDoubleValue()); builder.setVType(Model.ValueType.FLOAT64); break; + case STRING_ARRAY: + builder.setVStr(new Gson().toJson(value.getStringArrayValue())); + builder.setVType(Model.ValueType.STRING); + break; + case LONG_ARRAY: + builder.setVStr(new Gson().toJson(value.getLongArrayValue())); + builder.setVType(Model.ValueType.STRING); + break; + case BOOLEAN_ARRAY: + builder.setVStr(new Gson().toJson(value.getBooleanArrayValue())); + builder.setVType(Model.ValueType.STRING); + break; + case DOUBLE_ARRAY: + builder.setVStr(new Gson().toJson(value.getDoubleArrayValue())); + builder.setVType(Model.ValueType.STRING); + break; } - return builder.build(); } diff --git a/exporters/jaeger/src/test/java/io/opentelemetry/exporters/jaeger/AdapterTest.java b/exporters/jaeger/src/test/java/io/opentelemetry/exporters/jaeger/AdapterTest.java index 891a5cd2702..c41b1617906 100644 --- a/exporters/jaeger/src/test/java/io/opentelemetry/exporters/jaeger/AdapterTest.java +++ b/exporters/jaeger/src/test/java/io/opentelemetry/exporters/jaeger/AdapterTest.java @@ -167,12 +167,20 @@ public void testKeyValue() { AttributeValue valueD = AttributeValue.doubleAttributeValue(1.); AttributeValue valueI = AttributeValue.longAttributeValue(2); AttributeValue valueS = AttributeValue.stringAttributeValue("foobar"); + AttributeValue valueArrayB = AttributeValue.arrayAttributeValue(true, false); + AttributeValue valueArrayD = AttributeValue.arrayAttributeValue(1.2345, 6.789); + AttributeValue valueArrayI = AttributeValue.arrayAttributeValue(12345L, 67890L); + AttributeValue valueArrayS = AttributeValue.arrayAttributeValue("foobar", "barfoo"); // test Model.KeyValue kvB = Adapter.toKeyValue("valueB", valueB); Model.KeyValue kvD = Adapter.toKeyValue("valueD", valueD); Model.KeyValue kvI = Adapter.toKeyValue("valueI", valueI); Model.KeyValue kvS = Adapter.toKeyValue("valueS", valueS); + Model.KeyValue kvArrayB = Adapter.toKeyValue("valueArrayB", valueArrayB); + Model.KeyValue kvArrayD = Adapter.toKeyValue("valueArrayD", valueArrayD); + Model.KeyValue kvArrayI = Adapter.toKeyValue("valueArrayI", valueArrayI); + Model.KeyValue kvArrayS = Adapter.toKeyValue("valueArrayS", valueArrayS); // verify assertTrue(kvB.getVBool()); @@ -184,6 +192,18 @@ public void testKeyValue() { assertEquals("foobar", kvS.getVStr()); assertEquals("foobar", kvS.getVStrBytes().toStringUtf8()); assertEquals(Model.ValueType.STRING, kvS.getVType()); + assertEquals("[true,false]", kvArrayB.getVStr()); + assertEquals("[true,false]", kvArrayB.getVStrBytes().toStringUtf8()); + assertEquals(Model.ValueType.STRING, kvArrayB.getVType()); + assertEquals("[1.2345,6.789]", kvArrayD.getVStr()); + assertEquals("[1.2345,6.789]", kvArrayD.getVStrBytes().toStringUtf8()); + assertEquals(Model.ValueType.STRING, kvArrayD.getVType()); + assertEquals("[12345,67890]", kvArrayI.getVStr()); + assertEquals("[12345,67890]", kvArrayI.getVStrBytes().toStringUtf8()); + assertEquals(Model.ValueType.STRING, kvArrayI.getVType()); + assertEquals("[\"foobar\",\"barfoo\"]", kvArrayS.getVStr()); + assertEquals("[\"foobar\",\"barfoo\"]", kvArrayS.getVStrBytes().toStringUtf8()); + assertEquals(Model.ValueType.STRING, kvArrayS.getVType()); } @Test diff --git a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/CommonAdapter.java b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/CommonAdapter.java index a66524faf2c..e6c1f03d4f7 100644 --- a/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/CommonAdapter.java +++ b/exporters/otlp/src/main/java/io/opentelemetry/exporters/otlp/CommonAdapter.java @@ -43,6 +43,11 @@ static AttributeKeyValue toProtoAttribute(String key, AttributeValue attributeVa .setType(ValueType.DOUBLE) .setDoubleValue(attributeValue.getDoubleValue()) .build(); + case BOOLEAN_ARRAY: + case LONG_ARRAY: + case DOUBLE_ARRAY: + case STRING_ARRAY: + return builder.setType(ValueType.UNRECOGNIZED).build(); } return builder.setType(ValueType.UNRECOGNIZED).build(); } diff --git a/opentracing_shim/src/test/java/io/opentelemetry/opentracingshim/testbed/TestUtils.java b/opentracing_shim/src/test/java/io/opentelemetry/opentracingshim/testbed/TestUtils.java index f7ca497b11c..2f70d8f9304 100644 --- a/opentracing_shim/src/test/java/io/opentelemetry/opentracingshim/testbed/TestUtils.java +++ b/opentracing_shim/src/test/java/io/opentelemetry/opentracingshim/testbed/TestUtils.java @@ -67,6 +67,14 @@ public boolean check(SpanData span) { return value.equals(attrValue.getBooleanValue()); case DOUBLE: return value.equals(attrValue.getDoubleValue()); + case STRING_ARRAY: + return value.equals(attrValue.getStringArrayValue()); + case LONG_ARRAY: + return value.equals(attrValue.getLongArrayValue()); + case BOOLEAN_ARRAY: + return value.equals(attrValue.getBooleanArrayValue()); + case DOUBLE_ARRAY: + return value.equals(attrValue.getDoubleArrayValue()); } return false; diff --git a/sdk/src/main/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpan.java b/sdk/src/main/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpan.java index ad9c9719bf3..54c7f7b48c7 100644 --- a/sdk/src/main/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpan.java +++ b/sdk/src/main/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpan.java @@ -16,11 +16,11 @@ package io.opentelemetry.sdk.trace; +import static io.opentelemetry.common.AttributeValue.Type.STRING; + import com.google.common.base.Preconditions; import com.google.common.collect.EvictingQueue; import io.opentelemetry.common.AttributeValue; -import io.opentelemetry.common.AttributeValue.Type; -import io.opentelemetry.internal.StringUtils; import io.opentelemetry.sdk.common.Clock; import io.opentelemetry.sdk.common.InstrumentationLibraryInfo; import io.opentelemetry.sdk.resources.Resource; @@ -332,8 +332,10 @@ public void setAttribute(String key, boolean value) { @Override public void setAttribute(String key, AttributeValue value) { Preconditions.checkNotNull(key, "key"); - Preconditions.checkNotNull(value, "value"); - if (value.getType() == Type.STRING && StringUtils.isNullOrEmpty(value.getStringValue())) { + if (value == null || (value.getType().equals(STRING) && value.getStringValue() == null)) { + synchronized (lock) { + attributes.remove(key); + } return; } synchronized (lock) { diff --git a/sdk/src/main/java/io/opentelemetry/sdk/trace/SpanBuilderSdk.java b/sdk/src/main/java/io/opentelemetry/sdk/trace/SpanBuilderSdk.java index cf3d9fef1b4..0ce9df556c9 100644 --- a/sdk/src/main/java/io/opentelemetry/sdk/trace/SpanBuilderSdk.java +++ b/sdk/src/main/java/io/opentelemetry/sdk/trace/SpanBuilderSdk.java @@ -168,7 +168,8 @@ public Span.Builder setAttribute(String key, boolean value) { @Override public Span.Builder setAttribute(String key, AttributeValue value) { Utils.checkNotNull(key, "key"); - if (isRemovedValue(value)) { + if (value == null + || (value.getType().equals(AttributeValue.Type.STRING) && value.getStringValue() == null)) { attributes.remove(key); } else { attributes.putAttribute(key, value); @@ -176,21 +177,6 @@ public Span.Builder setAttribute(String key, AttributeValue value) { return this; } - private static boolean isRemovedValue(AttributeValue value) { - if (value == null) { - return true; - } - switch (value.getType()) { - case STRING: - return value.getStringValue() == null; - case BOOLEAN: - case LONG: - case DOUBLE: - return false; - } - return false; - } - @Override public Span.Builder setStartTimestamp(long startTimestamp) { Utils.checkArgument(startTimestamp >= 0, "Negative startTimestamp"); diff --git a/sdk/src/test/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpanTest.java b/sdk/src/test/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpanTest.java index 88c06de0432..30feab4f5e3 100644 --- a/sdk/src/test/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpanTest.java +++ b/sdk/src/test/java/io/opentelemetry/sdk/trace/RecordEventsReadableSpanTest.java @@ -294,11 +294,82 @@ public void setAttribute() { span.setAttribute("LongKey", 1000L); span.setAttribute("DoubleKey", 10.0); span.setAttribute("BooleanKey", false); + span.setAttribute( + "ArrayStringKey", + AttributeValue.arrayAttributeValue("StringVal", null, "", "StringVal2")); + span.setAttribute("ArrayLongKey", AttributeValue.arrayAttributeValue(1L, 2L, 3L, 4L, 5L)); + span.setAttribute( + "ArrayDoubleKey", AttributeValue.arrayAttributeValue(0.1, 2.3, 4.5, 6.7, 8.9)); + span.setAttribute( + "ArrayBooleanKey", AttributeValue.arrayAttributeValue(true, false, false, true)); + span.setAttribute("NullArrayStringKey", AttributeValue.arrayAttributeValue((String[]) null)); + span.setAttribute("NullArrayLongKey", AttributeValue.arrayAttributeValue((Long[]) null)); + span.setAttribute("NullArrayDoubleKey", AttributeValue.arrayAttributeValue((Double[]) null)); + span.setAttribute( + "NullArrayBooleanKey", AttributeValue.arrayAttributeValue((Boolean[]) null)); } finally { span.end(); } SpanData spanData = span.toSpanData(); - assertThat(spanData.getAttributes().size()).isEqualTo(4); + assertThat(spanData.getAttributes().size()).isEqualTo(14); + assertThat(spanData.getAttributes().get("ArrayStringKey").getStringArrayValue().size()) + .isEqualTo(4); + assertThat(spanData.getAttributes().get("ArrayLongKey").getLongArrayValue().size()) + .isEqualTo(5); + assertThat(spanData.getAttributes().get("ArrayDoubleKey").getDoubleArrayValue().size()) + .isEqualTo(5); + assertThat(spanData.getAttributes().get("ArrayBooleanKey").getBooleanArrayValue().size()) + .isEqualTo(4); + } + + @Test + public void setAttribute_emptyArrayAttributeValue() throws Exception { + RecordEventsReadableSpan span = createTestRootSpan(); + span.setAttribute("stringArrayAttribute", AttributeValue.arrayAttributeValue(new String[0])); + span.setAttribute("boolArrayAttribute", AttributeValue.arrayAttributeValue(new Boolean[0])); + span.setAttribute("longArrayAttribute", AttributeValue.arrayAttributeValue(new Long[0])); + span.setAttribute("doubleArrayAttribute", AttributeValue.arrayAttributeValue(new Double[0])); + assertThat(span.toSpanData().getAttributes().size()).isEqualTo(4); + } + + @Test + public void setAttribute_nullStringValue() throws Exception { + RecordEventsReadableSpan span = createTestRootSpan(); + span.setAttribute("emptyString", ""); + span.setAttribute("nullString", (String) null); + span.setAttribute("nullStringAttributeValue", AttributeValue.stringAttributeValue(null)); + span.setAttribute("emptyStringAttributeValue", AttributeValue.stringAttributeValue("")); + assertThat(span.toSpanData().getAttributes().size()).isEqualTo(2); + span.setAttribute("emptyString", (String) null); + span.setAttribute("emptyStringAttributeValue", (String) null); + assertThat(span.toSpanData().getAttributes()).isEmpty(); + } + + @Test + public void setAttribute_nullAttributeValue() throws Exception { + RecordEventsReadableSpan span = createTestRootSpan(); + span.setAttribute("emptyString", ""); + span.setAttribute("nullString", (AttributeValue) null); + span.setAttribute("nullStringAttributeValue", AttributeValue.stringAttributeValue(null)); + span.setAttribute("emptyStringAttributeValue", AttributeValue.stringAttributeValue("")); + span.setAttribute("longAttribute", 0L); + span.setAttribute("boolAttribute", false); + span.setAttribute("doubleAttribute", 0.12345f); + span.setAttribute("stringArrayAttribute", AttributeValue.arrayAttributeValue("", null)); + span.setAttribute("boolArrayAttribute", AttributeValue.arrayAttributeValue(true, null)); + span.setAttribute("longArrayAttribute", AttributeValue.arrayAttributeValue(12345L, null)); + span.setAttribute("doubleArrayAttribute", AttributeValue.arrayAttributeValue(1.2345, null)); + assertThat(span.toSpanData().getAttributes().size()).isEqualTo(9); + span.setAttribute("emptyString", (AttributeValue) null); + span.setAttribute("emptyStringAttributeValue", (AttributeValue) null); + span.setAttribute("longAttribute", (AttributeValue) null); + span.setAttribute("boolAttribute", (AttributeValue) null); + span.setAttribute("doubleAttribute", (AttributeValue) null); + span.setAttribute("stringArrayAttribute", (AttributeValue) null); + span.setAttribute("boolArrayAttribute", (AttributeValue) null); + span.setAttribute("longArrayAttribute", (AttributeValue) null); + span.setAttribute("doubleArrayAttribute", (AttributeValue) null); + assertThat(span.toSpanData().getAttributes()).isEmpty(); } @Test diff --git a/sdk/src/test/java/io/opentelemetry/sdk/trace/SpanBuilderSdkTest.java b/sdk/src/test/java/io/opentelemetry/sdk/trace/SpanBuilderSdkTest.java index fc52f9973df..3b3b1430bd1 100644 --- a/sdk/src/test/java/io/opentelemetry/sdk/trace/SpanBuilderSdkTest.java +++ b/sdk/src/test/java/io/opentelemetry/sdk/trace/SpanBuilderSdkTest.java @@ -172,6 +172,20 @@ public void setAttribute() { } } + @Test + public void setAttribute_emptyArrayAttributeValue() throws Exception { + Span.Builder spanBuilder = tracerSdk.spanBuilder(SPAN_NAME); + spanBuilder.setAttribute( + "stringArrayAttribute", AttributeValue.arrayAttributeValue(new String[0])); + spanBuilder.setAttribute( + "boolArrayAttribute", AttributeValue.arrayAttributeValue(new Boolean[0])); + spanBuilder.setAttribute("longArrayAttribute", AttributeValue.arrayAttributeValue(new Long[0])); + spanBuilder.setAttribute( + "doubleArrayAttribute", AttributeValue.arrayAttributeValue(new Double[0])); + RecordEventsReadableSpan span = (RecordEventsReadableSpan) spanBuilder.startSpan(); + assertThat(span.toSpanData().getAttributes().size()).isEqualTo(4); + } + @Test public void setAttribute_nullStringValue() throws Exception { Span.Builder spanBuilder = tracerSdk.spanBuilder(SPAN_NAME); @@ -196,13 +210,23 @@ public void setAttribute_nullAttributeValue() throws Exception { spanBuilder.setAttribute("longAttribute", 0L); spanBuilder.setAttribute("boolAttribute", false); spanBuilder.setAttribute("doubleAttribute", 0.12345f); + spanBuilder.setAttribute("stringArrayAttribute", AttributeValue.arrayAttributeValue("", null)); + spanBuilder.setAttribute("boolArrayAttribute", AttributeValue.arrayAttributeValue(true, null)); + spanBuilder.setAttribute( + "longArrayAttribute", AttributeValue.arrayAttributeValue(12345L, null)); + spanBuilder.setAttribute( + "doubleArrayAttribute", AttributeValue.arrayAttributeValue(1.2345, null)); RecordEventsReadableSpan span = (RecordEventsReadableSpan) spanBuilder.startSpan(); - assertThat(span.toSpanData().getAttributes().size()).isEqualTo(5); + assertThat(span.toSpanData().getAttributes().size()).isEqualTo(9); spanBuilder.setAttribute("emptyString", (AttributeValue) null); spanBuilder.setAttribute("emptyStringAttributeValue", (AttributeValue) null); spanBuilder.setAttribute("longAttribute", (AttributeValue) null); spanBuilder.setAttribute("boolAttribute", (AttributeValue) null); spanBuilder.setAttribute("doubleAttribute", (AttributeValue) null); + spanBuilder.setAttribute("stringArrayAttribute", (AttributeValue) null); + spanBuilder.setAttribute("boolArrayAttribute", (AttributeValue) null); + spanBuilder.setAttribute("longArrayAttribute", (AttributeValue) null); + spanBuilder.setAttribute("doubleArrayAttribute", (AttributeValue) null); assertThat(span.toSpanData().getAttributes()).isEmpty(); } diff --git a/sdk_contrib/testbed/src/test/java/io/opentelemetry/sdk/contrib/trace/testbed/TestUtils.java b/sdk_contrib/testbed/src/test/java/io/opentelemetry/sdk/contrib/trace/testbed/TestUtils.java index 43d2de9be6b..c76f8b1ba76 100644 --- a/sdk_contrib/testbed/src/test/java/io/opentelemetry/sdk/contrib/trace/testbed/TestUtils.java +++ b/sdk_contrib/testbed/src/test/java/io/opentelemetry/sdk/contrib/trace/testbed/TestUtils.java @@ -66,6 +66,14 @@ public boolean check(SpanData span) { return value.equals(attrValue.getDoubleValue()); case LONG: return value.equals(attrValue.getLongValue()); + case STRING_ARRAY: + return value.equals(attrValue.getStringArrayValue()); + case LONG_ARRAY: + return value.equals(attrValue.getLongArrayValue()); + case BOOLEAN_ARRAY: + return value.equals(attrValue.getBooleanArrayValue()); + case DOUBLE_ARRAY: + return value.equals(attrValue.getDoubleArrayValue()); } return false; }