-
Notifications
You must be signed in to change notification settings - Fork 858
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
Sketch out ExtendedAttributes #6983
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.api.common; | ||
|
||
import io.opentelemetry.api.internal.ImmutableKeyValuePairs; | ||
import java.util.ArrayList; | ||
import java.util.Comparator; | ||
import javax.annotation.Nullable; | ||
import javax.annotation.concurrent.Immutable; | ||
|
||
@Immutable | ||
final class ArrayBackedExtendedAttributes | ||
extends ImmutableKeyValuePairs<ExtendedAttributeKey<?>, Object> implements ExtendedAttributes { | ||
|
||
// We only compare the key name, not type, when constructing, to allow deduping keys with the | ||
// same name but different type. | ||
private static final Comparator<ExtendedAttributeKey<?>> KEY_COMPARATOR_FOR_CONSTRUCTION = | ||
Comparator.comparing(ExtendedAttributeKey::getKey); | ||
|
||
static final ExtendedAttributes EMPTY = ExtendedAttributes.builder().build(); | ||
|
||
@Nullable private Attributes attributes; | ||
|
||
private ArrayBackedExtendedAttributes( | ||
Object[] data, Comparator<ExtendedAttributeKey<?>> keyComparator) { | ||
super(data, keyComparator); | ||
} | ||
|
||
/** | ||
* Only use this constructor if you can guarantee that the data has been de-duped, sorted by key | ||
* and contains no null values or null/empty keys. | ||
* | ||
* @param data the raw data | ||
*/ | ||
ArrayBackedExtendedAttributes(Object[] data) { | ||
super(data); | ||
} | ||
|
||
@Override | ||
public ExtendedAttributesBuilder toBuilder() { | ||
return new ArrayBackedExtendedAttributesBuilder(new ArrayList<>(data())); | ||
Check warning on line 44 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributes.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributes.java#L44
|
||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
@Nullable | ||
public <T> T get(ExtendedAttributeKey<T> key) { | ||
return (T) super.get(key); | ||
} | ||
|
||
@SuppressWarnings("unchecked") | ||
@Override | ||
public Attributes asAttributes() { | ||
if (attributes == null) { | ||
AttributesBuilder builder = Attributes.builder(); | ||
forEach( | ||
(extendedAttributeKey, value) -> { | ||
AttributeKey<Object> attributeKey = | ||
(AttributeKey<Object>) extendedAttributeKey.asAttributeKey(); | ||
if (attributeKey != null) { | ||
builder.put(attributeKey, value); | ||
} | ||
}); | ||
attributes = builder.build(); | ||
} | ||
return attributes; | ||
} | ||
|
||
static ExtendedAttributes sortAndFilterToAttributes(Object... data) { | ||
// null out any empty keys or keys with null values | ||
// so they will then be removed by the sortAndFilter method. | ||
for (int i = 0; i < data.length; i += 2) { | ||
ExtendedAttributeKey<?> key = (ExtendedAttributeKey<?>) data[i]; | ||
if (key != null && key.getKey().isEmpty()) { | ||
data[i] = null; | ||
Check warning on line 78 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributes.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributes.java#L78
|
||
} | ||
} | ||
return new ArrayBackedExtendedAttributes(data, KEY_COMPARATOR_FOR_CONSTRUCTION); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.api.common; | ||
|
||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.function.Predicate; | ||
|
||
class ArrayBackedExtendedAttributesBuilder implements ExtendedAttributesBuilder { | ||
private final List<Object> data; | ||
|
||
ArrayBackedExtendedAttributesBuilder() { | ||
data = new ArrayList<>(); | ||
} | ||
|
||
ArrayBackedExtendedAttributesBuilder(List<Object> data) { | ||
this.data = data; | ||
} | ||
Check warning on line 21 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L19-L21
|
||
|
||
@Override | ||
public ExtendedAttributes build() { | ||
// If only one key-value pair AND the entry hasn't been set to null (by #remove(AttributeKey<T>) | ||
// or #removeIf(Predicate<AttributeKey<?>>)), then we can bypass sorting and filtering | ||
if (data.size() == 2 && data.get(0) != null) { | ||
return new ArrayBackedExtendedAttributes(data.toArray()); | ||
} | ||
return ArrayBackedExtendedAttributes.sortAndFilterToAttributes(data.toArray()); | ||
} | ||
|
||
@Override | ||
public <T> ExtendedAttributesBuilder put(ExtendedAttributeKey<T> key, T value) { | ||
if (key == null || key.getKey().isEmpty() || value == null) { | ||
return this; | ||
Check warning on line 36 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L36
|
||
} | ||
data.add(key); | ||
data.add(value); | ||
return this; | ||
} | ||
|
||
@Override | ||
public ExtendedAttributesBuilder removeIf(Predicate<ExtendedAttributeKey<?>> predicate) { | ||
if (predicate == null) { | ||
return this; | ||
Check warning on line 46 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L46
|
||
} | ||
for (int i = 0; i < data.size() - 1; i += 2) { | ||
Object entry = data.get(i); | ||
Check warning on line 49 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L49
|
||
if (entry instanceof ExtendedAttributeKey | ||
&& predicate.test((ExtendedAttributeKey<?>) entry)) { | ||
// null items are filtered out in ArrayBackedAttributes | ||
data.set(i, null); | ||
data.set(i + 1, null); | ||
Check warning on line 54 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L53-L54
|
||
} | ||
} | ||
return this; | ||
Check warning on line 57 in api/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java Codecov / codecov/patchapi/all/src/main/java/io/opentelemetry/api/common/ArrayBackedExtendedAttributesBuilder.java#L57
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.api.common; | ||
|
||
import io.opentelemetry.api.internal.InternalExtendedAttributeKeyImpl; | ||
import java.util.List; | ||
import javax.annotation.Nullable; | ||
import javax.annotation.concurrent.Immutable; | ||
|
||
/** TODO. */ | ||
@Immutable | ||
public interface ExtendedAttributeKey<T> { | ||
/** Returns the underlying String representation of the key. */ | ||
String getKey(); | ||
|
||
/** Returns the type of attribute for this key. Useful for building switch statements. */ | ||
ExtendedAttributeType getType(); | ||
|
||
@Nullable | ||
default AttributeKey<T> asAttributeKey() { | ||
return InternalExtendedAttributeKeyImpl.toAttributeKey(this); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for String valued attributes. */ | ||
static ExtendedAttributeKey<String> stringKey(String key) { | ||
return AttributeKey.stringKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for Boolean valued attributes. */ | ||
static ExtendedAttributeKey<Boolean> booleanKey(String key) { | ||
return AttributeKey.booleanKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for Long valued attributes. */ | ||
static ExtendedAttributeKey<Long> longKey(String key) { | ||
return AttributeKey.longKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for Double valued attributes. */ | ||
static ExtendedAttributeKey<Double> doubleKey(String key) { | ||
return AttributeKey.doubleKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for List<String> valued attributes. */ | ||
static ExtendedAttributeKey<List<String>> stringArrayKey(String key) { | ||
return AttributeKey.stringArrayKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for List<Boolean> valued attributes. */ | ||
static ExtendedAttributeKey<List<Boolean>> booleanArrayKey(String key) { | ||
return AttributeKey.booleanArrayKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for List<Long> valued attributes. */ | ||
static ExtendedAttributeKey<List<Long>> longArrayKey(String key) { | ||
return AttributeKey.longArrayKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for List<Double> valued attributes. */ | ||
static ExtendedAttributeKey<List<Double>> doubleArrayKey(String key) { | ||
return AttributeKey.doubleArrayKey(key).asExtendedAttributeKey(); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for Map valued attributes. */ | ||
static ExtendedAttributeKey<ExtendedAttributes> mapKey(String key) { | ||
return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.MAP); | ||
} | ||
|
||
/** Returns a new ExtendedAttributeKey for Map array valued attributes. */ | ||
static ExtendedAttributeKey<List<ExtendedAttributes>> mapArrayKey(String key) { | ||
return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.MAP_ARRAY); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.api.common; | ||
|
||
/** TODO. */ | ||
public enum ExtendedAttributeType { | ||
STRING, | ||
BOOLEAN, | ||
LONG, | ||
DOUBLE, | ||
STRING_ARRAY, | ||
BOOLEAN_ARRAY, | ||
LONG_ARRAY, | ||
DOUBLE_ARRAY, | ||
MAP, | ||
MAP_ARRAY; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* Copyright The OpenTelemetry Authors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package io.opentelemetry.api.common; | ||
|
||
import java.util.Map; | ||
import java.util.function.BiConsumer; | ||
import javax.annotation.Nullable; | ||
import javax.annotation.concurrent.Immutable; | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Immutable | ||
public interface ExtendedAttributes { | ||
|
||
/** Returns the value for the given {@link AttributeKey}, or {@code null} if not found. */ | ||
@Nullable | ||
default <T> T get(AttributeKey<T> key) { | ||
if (key == null) { | ||
return null; | ||
} | ||
return get(key.asExtendedAttributeKey()); | ||
} | ||
|
||
/** Returns the value for the given {@link ExtendedAttributeKey}, or {@code null} if not found. */ | ||
@Nullable | ||
<T> T get(ExtendedAttributeKey<T> key); | ||
|
||
/** Iterates over all the key-value pairs of attributes contained by this instance. */ | ||
void forEach(BiConsumer<? super ExtendedAttributeKey<?>, ? super Object> consumer); | ||
|
||
/** The number of attributes contained in this. */ | ||
int size(); | ||
|
||
/** Whether there are any attributes contained in this. */ | ||
boolean isEmpty(); | ||
|
||
/** Returns a read-only view of this {@link ExtendedAttributes} as a {@link Map}. */ | ||
Map<ExtendedAttributeKey<?>, Object> asMap(); | ||
|
||
/** | ||
* Return a view of this extended attributes with entries limited to those representable as | ||
* standard attributes. | ||
*/ | ||
Attributes asAttributes(); | ||
|
||
/** Returns a {@link ExtendedAttributes} instance with no attributes. */ | ||
static ExtendedAttributes empty() { | ||
return ArrayBackedExtendedAttributes.EMPTY; | ||
} | ||
|
||
/** | ||
* Returns a new {@link ExtendedAttributesBuilder} instance for creating arbitrary {@link | ||
* ExtendedAttributes}. | ||
*/ | ||
static ExtendedAttributesBuilder builder() { | ||
return new ArrayBackedExtendedAttributesBuilder(); | ||
} | ||
|
||
/** | ||
* Returns a new {@link ExtendedAttributesBuilder} instance populated with the data of this {@link | ||
* ExtendedAttributes}. | ||
*/ | ||
ExtendedAttributesBuilder toBuilder(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about renaming to
ComplexAttributes
?It does not suggest that there is some inheritance or that it e.g. supports more primitive types.
I think that "complex" is a better term for a type which supports nesting. I see that the "complex" term is even used in https://refactoring.guru/design-patterns/composite.
At last the proposed name is shorter 😉