Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Array values for span attributes #807

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -189,8 +190,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