Skip to content

Commit 3d3bff5

Browse files
authored
Fix bug preventing accurate reporting of dropped attribute count (#7142)
1 parent 31f484f commit 3d3bff5

File tree

3 files changed

+36
-5
lines changed

3 files changed

+36
-5
lines changed

sdk/common/src/main/java/io/opentelemetry/sdk/internal/AttributesMap.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@
1818
* A map with a fixed capacity that drops attributes when the map gets full, and which truncates
1919
* string and array string attribute values to the {@link #lengthLimit}.
2020
*
21+
* <p>WARNING: In order to reduce memory allocation, this class extends {@link HashMap} when it
22+
* would be more appropriate to delegate. The problem with extending is that we don't enforce that
23+
* all {@link HashMap} methods for reading / writing data conform to the configured attribute
24+
* limits. Therefore, it's easy to accidentally call something like {@link Map#putAll(Map)} or
25+
* {@link Map#put(Object, Object)} and bypass the restrictions (see <a
26+
* href="https://github.com/open-telemetry/opentelemetry-java/issues/7135">#7135</a>). Callers MUST
27+
* take care to only call methods from {@link AttributesMap}, and not {@link HashMap}.
28+
*
2129
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
2230
* at any time.
2331
*/
@@ -44,13 +52,18 @@ public static AttributesMap create(long capacity, int lengthLimit) {
4452
return new AttributesMap(capacity, lengthLimit);
4553
}
4654

47-
/** Add the attribute key value pair, applying capacity and length limits. */
48-
public <T> void put(AttributeKey<T> key, T value) {
55+
/**
56+
* Add the attribute key value pair, applying capacity and length limits. Callers MUST ensure the
57+
* {@code value} type matches the type required by {@code key}.
58+
*/
59+
@Override
60+
@Nullable
61+
public Object put(AttributeKey<?> key, Object value) {
4962
totalAddedValues++;
5063
if (size() >= capacity && !containsKey(key)) {
51-
return;
64+
return null;
5265
}
53-
super.put(key, AttributeUtil.applyAttributeLengthLimit(value, lengthLimit));
66+
return super.put(key, AttributeUtil.applyAttributeLengthLimit(value, lengthLimit));
5467
}
5568

5669
/** Get the total number of attributes added, including those dropped for capcity limits. */

sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ public ReadWriteSpan recordException(Throwable exception) {
466466
}
467467

468468
@Override
469+
@SuppressWarnings("unchecked")
469470
public ReadWriteSpan recordException(Throwable exception, Attributes additionalAttributes) {
470471
if (exception == null) {
471472
return this;

sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1277,6 +1277,21 @@ void recordException_additionalAttributes() {
12771277
});
12781278
}
12791279

1280+
@Test
1281+
void recordException_SpanLimits() {
1282+
SdkSpan span = createTestSpan(SpanLimits.builder().setMaxNumberOfAttributes(2).build());
1283+
span.recordException(
1284+
new IllegalStateException("error"),
1285+
Attributes.builder().put("key1", "value").put("key2", "value").build());
1286+
1287+
List<EventData> events = span.toSpanData().getEvents();
1288+
assertThat(events.size()).isEqualTo(1);
1289+
EventData event = events.get(0);
1290+
assertThat(event.getAttributes().size()).isEqualTo(2);
1291+
assertThat(event.getTotalAttributeCount()).isEqualTo(5);
1292+
assertThat(event.getTotalAttributeCount() - event.getAttributes().size()).isPositive();
1293+
}
1294+
12801295
@Test
12811296
void badArgsIgnored() {
12821297
SdkSpan span = createTestRootSpan();
@@ -1519,7 +1534,9 @@ void testAsSpanData() {
15191534
Resource resource = this.resource;
15201535
Attributes attributes = TestUtils.generateRandomAttributes();
15211536
AttributesMap attributesWithCapacity = AttributesMap.create(32, Integer.MAX_VALUE);
1522-
attributes.forEach(attributesWithCapacity::put);
1537+
attributes.forEach(
1538+
(attributeKey, object) ->
1539+
attributesWithCapacity.put((AttributeKey<Object>) attributeKey, object));
15231540
Attributes event1Attributes = TestUtils.generateRandomAttributes();
15241541
Attributes event2Attributes = TestUtils.generateRandomAttributes();
15251542
SpanContext context =

0 commit comments

Comments
 (0)