Skip to content

Commit

Permalink
Array values for span attributes (#807)
Browse files Browse the repository at this point in the history
* [API] - Add Arrays for span attributes

* [SDK] - Add Arrays for span attributes

* [Exporters/Shim] - Add Arrays for span attributes

* add tests

* Adjust jaeger exporter to specification. Add tests.

* Fix checkstyle naming issue

* Add further tests.

* Align null value behavior of attributes with spec

* fix javadoc @SInCE

* API must not crash on misusage of AttributeValue

* API - Remove Attribute ArrayValues from Span surface

* Immutable String array values for AttributeValue

* Immutable values for AttributeValue arrays

* ./gradlew goJF

* Implement ArrayAttribute

* Rebase and add tests

* Adapt RecordEventsReadableSpan
  • Loading branch information
thisthat authored Apr 21, 2020
1 parent d87ee34 commit 4bcfdb7
Show file tree
Hide file tree
Showing 12 changed files with 433 additions and 24 deletions.
209 changes: 208 additions & 1 deletion api/src/main/java/io/opentelemetry/common/AttributeValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -39,7 +43,11 @@ public enum Type {
STRING,
BOOLEAN,
LONG,
DOUBLE
DOUBLE,
STRING_ARRAY,
BOOLEAN_ARRAY,
LONG_ARRAY,
DOUBLE_ARRAY
}

/**
Expand Down Expand Up @@ -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() {}

/**
Expand Down Expand Up @@ -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<String> 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<Boolean> 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<Long> 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<Double> 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}.
*
Expand Down Expand Up @@ -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.<String>emptyList());
}
return new AutoValue_AttributeValue_AttributeValueStringArray(
Collections.unmodifiableList(Arrays.asList(stringValues)));
}

@Override
public final Type getType() {
return Type.STRING_ARRAY;
}

@Override
public abstract List<String> getStringArrayValue();
}

@Immutable
@AutoValue
abstract static class AttributeValueBooleanArray extends AttributeValue {

AttributeValueBooleanArray() {}

static AttributeValue create(Boolean... booleanValues) {
if (booleanValues == null) {
return new AutoValue_AttributeValue_AttributeValueBooleanArray(
Collections.<Boolean>emptyList());
}
List<Boolean> 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<Boolean> getBooleanArrayValue();
}

@Immutable
@AutoValue
abstract static class AttributeValueLongArray extends AttributeValue {

AttributeValueLongArray() {}

static AttributeValue create(Long... longValues) {
if (longValues == null) {
return new AutoValue_AttributeValue_AttributeValueLongArray(Collections.<Long>emptyList());
}
List<Long> 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<Long> getLongArrayValue();
}

@Immutable
@AutoValue
abstract static class AttributeValueDoubleArray extends AttributeValue {

AttributeValueDoubleArray() {}

static AttributeValue create(Double... doubleValues) {
if (doubleValues == null) {
return new AutoValue_AttributeValue_AttributeValueDoubleArray(
Collections.<Double>emptyList());
}
List<Double> 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<Double> getDoubleArrayValue();
}
}
58 changes: 58 additions & 0 deletions api/src/test/java/io/opentelemetry/common/AttributeValueTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);
}
}
4 changes: 4 additions & 0 deletions api/src/test/java/io/opentelemetry/trace/DefaultSpanTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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
Expand Down
Loading

0 comments on commit 4bcfdb7

Please sign in to comment.