Skip to content

Commit 2d1c14e

Browse files
authored
Add experimental support for log extended attributes (#7123)
1 parent 9cb6365 commit 2d1c14e

File tree

46 files changed

+2852
-125
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2852
-125
lines changed

api/all/src/main/java/io/opentelemetry/api/common/AttributeKey.java

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ public interface AttributeKey<T> {
2626
/** Returns the type of attribute for this key. Useful for building switch statements. */
2727
AttributeType getType();
2828

29+
// TODO (jack-berg): uncomment when extended attributes are promoted from incubator to API
30+
// default ExtendedAttributeKey<T> asExtendedAttributeKey() {
31+
// return InternalAttributeKeyImpl.toExtendedAttributeKey(this);
32+
// }
33+
2934
/** Returns a new AttributeKey for String valued attributes. */
3035
static AttributeKey<String> stringKey(String key) {
3136
return InternalAttributeKeyImpl.create(key, AttributeType.STRING);

api/incubator/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Experimental APIs, including Event API, extended Log Bridge APIs, extended Metri
77
Features:
88

99
* Check if logger is enabled before emitting logs to avoid unnecessary computation
10+
* Add extended attributes to log records to encode complex data structures
1011

1112
See [ExtendedLogsBridgeApiUsageTest](./src/test/java/io/opentelemetry/api/incubator/logs/ExtendedLogsBridgeApiUsageTest.java).
1213

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.common;
7+
8+
import io.opentelemetry.api.common.AttributeKey;
9+
import io.opentelemetry.api.common.Attributes;
10+
import io.opentelemetry.api.common.AttributesBuilder;
11+
import io.opentelemetry.api.internal.ImmutableKeyValuePairs;
12+
import java.util.ArrayList;
13+
import java.util.Comparator;
14+
import javax.annotation.Nullable;
15+
import javax.annotation.concurrent.Immutable;
16+
17+
@Immutable
18+
final class ArrayBackedExtendedAttributes
19+
extends ImmutableKeyValuePairs<ExtendedAttributeKey<?>, Object> implements ExtendedAttributes {
20+
21+
// We only compare the key name, not type, when constructing, to allow deduping keys with the
22+
// same name but different type.
23+
private static final Comparator<ExtendedAttributeKey<?>> KEY_COMPARATOR_FOR_CONSTRUCTION =
24+
Comparator.comparing(ExtendedAttributeKey::getKey);
25+
26+
static final ExtendedAttributes EMPTY = ExtendedAttributes.builder().build();
27+
28+
@Nullable private Attributes attributes;
29+
30+
private ArrayBackedExtendedAttributes(
31+
Object[] data, Comparator<ExtendedAttributeKey<?>> keyComparator) {
32+
super(data, keyComparator);
33+
}
34+
35+
/**
36+
* Only use this constructor if you can guarantee that the data has been de-duped, sorted by key
37+
* and contains no null values or null/empty keys.
38+
*
39+
* @param data the raw data
40+
*/
41+
ArrayBackedExtendedAttributes(Object[] data) {
42+
super(data);
43+
}
44+
45+
@Override
46+
public ExtendedAttributesBuilder toBuilder() {
47+
return new ArrayBackedExtendedAttributesBuilder(new ArrayList<>(data()));
48+
}
49+
50+
@SuppressWarnings("unchecked")
51+
@Override
52+
@Nullable
53+
public <T> T get(ExtendedAttributeKey<T> key) {
54+
return (T) super.get(key);
55+
}
56+
57+
@SuppressWarnings("unchecked")
58+
@Override
59+
public Attributes asAttributes() {
60+
if (attributes == null) {
61+
AttributesBuilder builder = Attributes.builder();
62+
forEach(
63+
(extendedAttributeKey, value) -> {
64+
AttributeKey<Object> attributeKey =
65+
(AttributeKey<Object>) extendedAttributeKey.asAttributeKey();
66+
if (attributeKey != null) {
67+
builder.put(attributeKey, value);
68+
}
69+
});
70+
attributes = builder.build();
71+
}
72+
return attributes;
73+
}
74+
75+
static ExtendedAttributes sortAndFilterToAttributes(Object... data) {
76+
// null out any empty keys or keys with null values
77+
// so they will then be removed by the sortAndFilter method.
78+
for (int i = 0; i < data.length; i += 2) {
79+
ExtendedAttributeKey<?> key = (ExtendedAttributeKey<?>) data[i];
80+
if (key != null && key.getKey().isEmpty()) {
81+
data[i] = null;
82+
}
83+
}
84+
return new ArrayBackedExtendedAttributes(data, KEY_COMPARATOR_FOR_CONSTRUCTION);
85+
}
86+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.common;
7+
8+
import java.util.ArrayList;
9+
import java.util.Arrays;
10+
import java.util.List;
11+
import java.util.function.Predicate;
12+
13+
class ArrayBackedExtendedAttributesBuilder implements ExtendedAttributesBuilder {
14+
private final List<Object> data;
15+
16+
ArrayBackedExtendedAttributesBuilder() {
17+
data = new ArrayList<>();
18+
}
19+
20+
ArrayBackedExtendedAttributesBuilder(List<Object> data) {
21+
this.data = data;
22+
}
23+
24+
@Override
25+
public ExtendedAttributes build() {
26+
// If only one key-value pair AND the entry hasn't been set to null (by #remove(AttributeKey<T>)
27+
// or #removeIf(Predicate<AttributeKey<?>>)), then we can bypass sorting and filtering
28+
if (data.size() == 2 && data.get(0) != null) {
29+
return new ArrayBackedExtendedAttributes(data.toArray());
30+
}
31+
return ArrayBackedExtendedAttributes.sortAndFilterToAttributes(data.toArray());
32+
}
33+
34+
@Override
35+
public <T> ExtendedAttributesBuilder put(ExtendedAttributeKey<T> key, T value) {
36+
if (key == null || key.getKey().isEmpty() || value == null) {
37+
return this;
38+
}
39+
data.add(key);
40+
data.add(value);
41+
return this;
42+
}
43+
44+
@Override
45+
public ExtendedAttributesBuilder removeIf(Predicate<ExtendedAttributeKey<?>> predicate) {
46+
if (predicate == null) {
47+
return this;
48+
}
49+
for (int i = 0; i < data.size() - 1; i += 2) {
50+
Object entry = data.get(i);
51+
if (entry instanceof ExtendedAttributeKey
52+
&& predicate.test((ExtendedAttributeKey<?>) entry)) {
53+
// null items are filtered out in ArrayBackedAttributes
54+
data.set(i, null);
55+
data.set(i + 1, null);
56+
}
57+
}
58+
return this;
59+
}
60+
61+
static List<Double> toList(double... values) {
62+
Double[] boxed = new Double[values.length];
63+
for (int i = 0; i < values.length; i++) {
64+
boxed[i] = values[i];
65+
}
66+
return Arrays.asList(boxed);
67+
}
68+
69+
static List<Long> toList(long... values) {
70+
Long[] boxed = new Long[values.length];
71+
for (int i = 0; i < values.length; i++) {
72+
boxed[i] = values[i];
73+
}
74+
return Arrays.asList(boxed);
75+
}
76+
77+
static List<Boolean> toList(boolean... values) {
78+
Boolean[] boxed = new Boolean[values.length];
79+
for (int i = 0; i < values.length; i++) {
80+
boxed[i] = values[i];
81+
}
82+
return Arrays.asList(boxed);
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.common;
7+
8+
import io.opentelemetry.api.common.AttributeKey;
9+
import io.opentelemetry.api.incubator.internal.InternalExtendedAttributeKeyImpl;
10+
import java.util.List;
11+
import javax.annotation.Nullable;
12+
import javax.annotation.concurrent.Immutable;
13+
14+
/**
15+
* This interface provides a handle for setting the values of {@link ExtendedAttributes}. The type
16+
* of value that can be set with an implementation of this key is denoted by the type parameter.
17+
*
18+
* <p>Implementations MUST be immutable, as these are used as the keys to Maps.
19+
*
20+
* <p>The allowed {@link #getType()}s is a superset of those allowed in {@link AttributeKey}.
21+
*
22+
* <p>Convenience methods are provided for translating to / from {@link AttributeKey}:
23+
*
24+
* <ul>
25+
* <li>{@link #asAttributeKey()} converts from {@link ExtendedAttributeKey} to {@link
26+
* AttributeKey}
27+
* <li>{@link #fromAttributeKey(AttributeKey)} converts from {@link AttributeKey} to {@link
28+
* ExtendedAttributeKey}
29+
* </ul>
30+
*
31+
* @param <T> The type of value that can be set with the key.
32+
*/
33+
@Immutable
34+
public interface ExtendedAttributeKey<T> {
35+
/** Returns the underlying String representation of the key. */
36+
String getKey();
37+
38+
/** Returns the type of attribute for this key. Useful for building switch statements. */
39+
ExtendedAttributeType getType();
40+
41+
/**
42+
* Return the equivalent {@link AttributeKey}, or {@code null} if the {@link #getType()} has no
43+
* equivalent {@link io.opentelemetry.api.common.AttributeType}.
44+
*/
45+
@Nullable
46+
default AttributeKey<T> asAttributeKey() {
47+
return InternalExtendedAttributeKeyImpl.toAttributeKey(this);
48+
}
49+
50+
/** Return an ExtendedAttributeKey equivalent to the {@code attributeKey}. */
51+
// TODO (jack-berg): remove once AttributeKey.asExtendedAttributeKey is available
52+
static <T> ExtendedAttributeKey<T> fromAttributeKey(AttributeKey<T> attributeKey) {
53+
return InternalExtendedAttributeKeyImpl.toExtendedAttributeKey(attributeKey);
54+
}
55+
56+
/** Returns a new ExtendedAttributeKey for String valued attributes. */
57+
static ExtendedAttributeKey<String> stringKey(String key) {
58+
return fromAttributeKey(AttributeKey.stringKey(key));
59+
}
60+
61+
/** Returns a new ExtendedAttributeKey for Boolean valued attributes. */
62+
static ExtendedAttributeKey<Boolean> booleanKey(String key) {
63+
return fromAttributeKey(AttributeKey.booleanKey(key));
64+
}
65+
66+
/** Returns a new ExtendedAttributeKey for Long valued attributes. */
67+
static ExtendedAttributeKey<Long> longKey(String key) {
68+
return fromAttributeKey(AttributeKey.longKey(key));
69+
}
70+
71+
/** Returns a new ExtendedAttributeKey for Double valued attributes. */
72+
static ExtendedAttributeKey<Double> doubleKey(String key) {
73+
return fromAttributeKey(AttributeKey.doubleKey(key));
74+
}
75+
76+
/** Returns a new ExtendedAttributeKey for List&lt;String&gt; valued attributes. */
77+
static ExtendedAttributeKey<List<String>> stringArrayKey(String key) {
78+
return fromAttributeKey(AttributeKey.stringArrayKey(key));
79+
}
80+
81+
/** Returns a new ExtendedAttributeKey for List&lt;Boolean&gt; valued attributes. */
82+
static ExtendedAttributeKey<List<Boolean>> booleanArrayKey(String key) {
83+
return fromAttributeKey(AttributeKey.booleanArrayKey(key));
84+
}
85+
86+
/** Returns a new ExtendedAttributeKey for List&lt;Long&gt; valued attributes. */
87+
static ExtendedAttributeKey<List<Long>> longArrayKey(String key) {
88+
return fromAttributeKey(AttributeKey.longArrayKey(key));
89+
}
90+
91+
/** Returns a new ExtendedAttributeKey for List&lt;Double&gt; valued attributes. */
92+
static ExtendedAttributeKey<List<Double>> doubleArrayKey(String key) {
93+
return fromAttributeKey(AttributeKey.doubleArrayKey(key));
94+
}
95+
96+
/** Returns a new ExtendedAttributeKey for Map valued attributes. */
97+
static ExtendedAttributeKey<ExtendedAttributes> extendedAttributesKey(String key) {
98+
return InternalExtendedAttributeKeyImpl.create(key, ExtendedAttributeType.EXTENDED_ATTRIBUTES);
99+
}
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.api.incubator.common;
7+
8+
/**
9+
* An enum that represents all the possible value types for an {@link ExtendedAttributeKey} and
10+
* hence the types of values that are allowed for {@link ExtendedAttributes}.
11+
*
12+
* <p>This is a superset of {@link io.opentelemetry.api.common.AttributeType},
13+
*/
14+
public enum ExtendedAttributeType {
15+
// Types copied AttributeType
16+
STRING,
17+
BOOLEAN,
18+
LONG,
19+
DOUBLE,
20+
STRING_ARRAY,
21+
BOOLEAN_ARRAY,
22+
LONG_ARRAY,
23+
DOUBLE_ARRAY,
24+
// Extended types unique to ExtendedAttributes
25+
EXTENDED_ATTRIBUTES;
26+
}

0 commit comments

Comments
 (0)