Add attribute length limits to SpanLimits. (#3551)
* Add attribute length limits to SpanLimits. * Respond to PR feedback * Respond to PR feedback * Remove test utility function * Rename method to getMaxAttributeValueLength
This commit is contained in:
parent
47fd8814e6
commit
060e50ed5f
|
@ -3,3 +3,11 @@ Comparing source compatibility of against
|
|||
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
|
||||
+++* NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Object getAttribute(io.opentelemetry.api.common.AttributeKey)
|
||||
+++ NEW ANNOTATION: javax.annotation.Nullable
|
||||
***! MODIFIED CLASS: PUBLIC ABSTRACT io.opentelemetry.sdk.trace.SpanLimits (not serializable)
|
||||
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
|
||||
***! MODIFIED CONSTRUCTOR: PROTECTED (<- PUBLIC) SpanLimits()
|
||||
+++ NEW ANNOTATION: java.lang.Deprecated
|
||||
+++ NEW METHOD: PUBLIC(+) int getMaxAttributeValueLength()
|
||||
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.trace.SpanLimitsBuilder (not serializable)
|
||||
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
|
||||
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.trace.SpanLimitsBuilder setMaxAttributeLength(int)
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.trace;
|
||||
|
||||
import io.opentelemetry.api.common.AttributeKey;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.api.common.AttributesBuilder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
final class AttributeUtil {
|
||||
|
||||
private AttributeUtil() {}
|
||||
|
||||
/**
|
||||
* Apply the {@code countLimit} and {@code lengthLimit} to the attributes.
|
||||
*
|
||||
* <p>If all attributes fall within the limits, return as is. Else, return an attributes instance
|
||||
* with the limits applied. {@code countLimit} limits the number of unique attribute keys. {@code
|
||||
* lengthLimit} limits the length of attribute string and string list values.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
static Attributes applyAttributesLimit(
|
||||
final Attributes attributes, final int countLimit, int lengthLimit) {
|
||||
if (attributes.isEmpty() || attributes.size() <= countLimit) {
|
||||
if (lengthLimit == Integer.MAX_VALUE) {
|
||||
return attributes;
|
||||
}
|
||||
boolean allValidLength =
|
||||
allMatch(attributes.asMap().values(), value -> isValidLength(value, lengthLimit));
|
||||
if (allValidLength) {
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
AttributesBuilder result = Attributes.builder();
|
||||
int i = 0;
|
||||
for (Map.Entry<AttributeKey<?>, Object> entry : attributes.asMap().entrySet()) {
|
||||
if (i >= countLimit) {
|
||||
break;
|
||||
}
|
||||
result.put(
|
||||
(AttributeKey) entry.getKey(), applyAttributeLengthLimit(entry.getValue(), lengthLimit));
|
||||
i++;
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
private static boolean isValidLength(Object value, int lengthLimit) {
|
||||
if (value instanceof List) {
|
||||
return allMatch((List<?>) value, entry -> isValidLength(entry, lengthLimit));
|
||||
} else if (value instanceof String) {
|
||||
return ((String) value).length() < lengthLimit;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static <T> boolean allMatch(Iterable<T> iterable, Predicate<T> predicate) {
|
||||
for (T value : iterable) {
|
||||
if (!predicate.test(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the {@code lengthLimit} to the attribute {@code value}. Strings and strings in lists
|
||||
* which exceed the length limit are truncated.
|
||||
*/
|
||||
static Object applyAttributeLengthLimit(Object value, int lengthLimit) {
|
||||
if (lengthLimit == Integer.MAX_VALUE) {
|
||||
return value;
|
||||
}
|
||||
if (value instanceof List) {
|
||||
List<?> values = (List<?>) value;
|
||||
List<Object> response = new ArrayList<>(values.size());
|
||||
for (Object entry : values) {
|
||||
response.add(applyAttributeLengthLimit(entry, lengthLimit));
|
||||
}
|
||||
return response;
|
||||
}
|
||||
if (value instanceof String) {
|
||||
String str = (String) value;
|
||||
return str.length() < lengthLimit ? value : str.substring(0, lengthLimit);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -13,16 +13,21 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** A map with a fixed capacity that drops attributes when the map gets full. */
|
||||
/**
|
||||
* A map with a fixed capacity that drops attributes when the map gets full, and which truncates
|
||||
* string and array string attribute values to the {@link #lengthLimit}.
|
||||
*/
|
||||
final class AttributesMap extends HashMap<AttributeKey<?>, Object> implements Attributes {
|
||||
|
||||
private static final long serialVersionUID = -5072696312123632376L;
|
||||
|
||||
private final long capacity;
|
||||
private final int lengthLimit;
|
||||
private int totalAddedValues = 0;
|
||||
|
||||
AttributesMap(long capacity) {
|
||||
AttributesMap(long capacity, int lengthLimit) {
|
||||
this.capacity = capacity;
|
||||
this.lengthLimit = lengthLimit;
|
||||
}
|
||||
|
||||
<T> void put(AttributeKey<T> key, T value) {
|
||||
|
@ -30,7 +35,7 @@ final class AttributesMap extends HashMap<AttributeKey<?>, Object> implements At
|
|||
if (size() >= capacity && !containsKey(key)) {
|
||||
return;
|
||||
}
|
||||
super.put(key, value);
|
||||
super.put(key, AttributeUtil.applyAttributeLengthLimit(value, lengthLimit));
|
||||
}
|
||||
|
||||
int getTotalAddedValues() {
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.io.StringWriter;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -289,7 +288,9 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
|
|||
return this;
|
||||
}
|
||||
if (attributes == null) {
|
||||
attributes = new AttributesMap(spanLimits.getMaxNumberOfAttributes());
|
||||
attributes =
|
||||
new AttributesMap(
|
||||
spanLimits.getMaxNumberOfAttributes(), spanLimits.getMaxAttributeValueLength());
|
||||
}
|
||||
|
||||
attributes.put(key, value);
|
||||
|
@ -328,7 +329,10 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
|
|||
EventData.create(
|
||||
clock.now(),
|
||||
name,
|
||||
applyAttributesLimit(attributes, spanLimits.getMaxNumberOfAttributesPerEvent()),
|
||||
AttributeUtil.applyAttributesLimit(
|
||||
attributes,
|
||||
spanLimits.getMaxNumberOfAttributesPerEvent(),
|
||||
spanLimits.getMaxAttributeValueLength()),
|
||||
totalAttributeCount));
|
||||
return this;
|
||||
}
|
||||
|
@ -346,29 +350,14 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
|
|||
EventData.create(
|
||||
unit.toNanos(timestamp),
|
||||
name,
|
||||
applyAttributesLimit(attributes, spanLimits.getMaxNumberOfAttributesPerEvent()),
|
||||
AttributeUtil.applyAttributesLimit(
|
||||
attributes,
|
||||
spanLimits.getMaxNumberOfAttributesPerEvent(),
|
||||
spanLimits.getMaxAttributeValueLength()),
|
||||
totalAttributeCount));
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
static Attributes applyAttributesLimit(final Attributes attributes, final int limit) {
|
||||
if (attributes.isEmpty() || attributes.size() <= limit) {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
AttributesBuilder result = Attributes.builder();
|
||||
int i = 0;
|
||||
for (Map.Entry<AttributeKey<?>, Object> entry : attributes.asMap().entrySet()) {
|
||||
if (i >= limit) {
|
||||
break;
|
||||
}
|
||||
result.put((AttributeKey) entry.getKey(), entry.getValue());
|
||||
i++;
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
private void addTimedEvent(EventData timedEvent) {
|
||||
synchronized (lock) {
|
||||
if (hasEnded) {
|
||||
|
|
|
@ -101,8 +101,10 @@ final class SdkSpanBuilder implements SpanBuilder {
|
|||
addLink(
|
||||
LinkData.create(
|
||||
spanContext,
|
||||
RecordEventsReadableSpan.applyAttributesLimit(
|
||||
attributes, spanLimits.getMaxNumberOfAttributesPerLink()),
|
||||
AttributeUtil.applyAttributesLimit(
|
||||
attributes,
|
||||
spanLimits.getMaxNumberOfAttributesPerLink(),
|
||||
spanLimits.getMaxAttributeValueLength()),
|
||||
totalAttributeCount));
|
||||
return this;
|
||||
}
|
||||
|
@ -232,7 +234,9 @@ final class SdkSpanBuilder implements SpanBuilder {
|
|||
private AttributesMap attributes() {
|
||||
AttributesMap attributes = this.attributes;
|
||||
if (attributes == null) {
|
||||
this.attributes = new AttributesMap(spanLimits.getMaxNumberOfAttributes());
|
||||
this.attributes =
|
||||
new AttributesMap(
|
||||
spanLimits.getMaxNumberOfAttributes(), spanLimits.getMaxAttributeValueLength());
|
||||
attributes = this.attributes;
|
||||
}
|
||||
return attributes;
|
||||
|
|
|
@ -17,10 +17,10 @@ import javax.annotation.concurrent.Immutable;
|
|||
* io.opentelemetry.sdk.trace.SdkTracerProviderBuilder#setSpanLimits(java.util.function.Supplier)}
|
||||
* which supplies dynamic configs when queried.
|
||||
*/
|
||||
@AutoValue
|
||||
@Immutable
|
||||
public abstract class SpanLimits {
|
||||
|
||||
static final int DEFAULT_SPAN_MAX_ATTRIBUTE_LENGTH = Integer.MAX_VALUE;
|
||||
|
||||
private static final SpanLimits DEFAULT = new SpanLimitsBuilder().build();
|
||||
|
||||
/** Returns the default {@link SpanLimits}. */
|
||||
|
@ -38,50 +38,70 @@ public abstract class SpanLimits {
|
|||
int maxNumEvents,
|
||||
int maxNumLinks,
|
||||
int maxNumAttributesPerEvent,
|
||||
int maxNumAttributesPerLink) {
|
||||
return new AutoValue_SpanLimits(
|
||||
int maxNumAttributesPerLink,
|
||||
int maxAttributeLength) {
|
||||
return new AutoValue_SpanLimits_SpanLimitsValue(
|
||||
maxNumAttributes,
|
||||
maxNumEvents,
|
||||
maxNumLinks,
|
||||
maxNumAttributesPerEvent,
|
||||
maxNumAttributesPerLink);
|
||||
maxNumAttributesPerLink,
|
||||
maxAttributeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global default max number of attributes per {@link Span}.
|
||||
* Create an instance.
|
||||
*
|
||||
* @return the global default max number of attributes per {@link Span}.
|
||||
* @deprecated Will be made package private in 2.0.0.
|
||||
*/
|
||||
@Deprecated
|
||||
protected SpanLimits() {}
|
||||
|
||||
/**
|
||||
* Returns the max number of attributes per {@link Span}.
|
||||
*
|
||||
* @return the max number of attributes per {@link Span}.
|
||||
*/
|
||||
public abstract int getMaxNumberOfAttributes();
|
||||
|
||||
/**
|
||||
* Returns the global default max number of events per {@link Span}.
|
||||
* Returns the max number of events per {@link Span}.
|
||||
*
|
||||
* @return the global default max number of events per {@code Span}.
|
||||
* @return the max number of events per {@code Span}.
|
||||
*/
|
||||
public abstract int getMaxNumberOfEvents();
|
||||
|
||||
/**
|
||||
* Returns the global default max number of links per {@link Span}.
|
||||
* Returns the max number of links per {@link Span}.
|
||||
*
|
||||
* @return the global default max number of links per {@code Span}.
|
||||
* @return the max number of links per {@code Span}.
|
||||
*/
|
||||
public abstract int getMaxNumberOfLinks();
|
||||
|
||||
/**
|
||||
* Returns the global default max number of attributes per event.
|
||||
* Returns the max number of attributes per event.
|
||||
*
|
||||
* @return the global default max number of attributes per event.
|
||||
* @return the max number of attributes per event.
|
||||
*/
|
||||
public abstract int getMaxNumberOfAttributesPerEvent();
|
||||
|
||||
/**
|
||||
* Returns the global default max number of attributes per link.
|
||||
* Returns the max number of attributes per link.
|
||||
*
|
||||
* @return the global default max number of attributes per link.
|
||||
* @return the max number of attributes per link.
|
||||
*/
|
||||
public abstract int getMaxNumberOfAttributesPerLink();
|
||||
|
||||
/**
|
||||
* Returns the max number of characters for string attribute values. For string array attributes
|
||||
* values, applies to each entry individually.
|
||||
*
|
||||
* @return the max number of characters for attribute strings.
|
||||
*/
|
||||
public int getMaxAttributeValueLength() {
|
||||
return DEFAULT_SPAN_MAX_ATTRIBUTE_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanLimitsBuilder} initialized to the same property values as the current
|
||||
* instance.
|
||||
|
@ -95,6 +115,19 @@ public abstract class SpanLimits {
|
|||
.setMaxNumberOfEvents(getMaxNumberOfEvents())
|
||||
.setMaxNumberOfLinks(getMaxNumberOfLinks())
|
||||
.setMaxNumberOfAttributesPerEvent(getMaxNumberOfAttributesPerEvent())
|
||||
.setMaxNumberOfAttributesPerLink(getMaxNumberOfAttributesPerLink());
|
||||
.setMaxNumberOfAttributesPerLink(getMaxNumberOfAttributesPerLink())
|
||||
.setMaxAttributeLength(getMaxAttributeValueLength());
|
||||
}
|
||||
|
||||
@AutoValue
|
||||
@Immutable
|
||||
abstract static class SpanLimitsValue extends SpanLimits {
|
||||
|
||||
/**
|
||||
* Override {@link SpanLimits#getMaxAttributeValueLength()} to be abstract so autovalue can
|
||||
* implement it.
|
||||
*/
|
||||
@Override
|
||||
public abstract int getMaxAttributeValueLength();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,15 +22,16 @@ public final class SpanLimitsBuilder {
|
|||
private int maxNumLinks = DEFAULT_SPAN_MAX_NUM_LINKS;
|
||||
private int maxNumAttributesPerEvent = DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_EVENT;
|
||||
private int maxNumAttributesPerLink = DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_LINK;
|
||||
private int maxAttributeLength = SpanLimits.DEFAULT_SPAN_MAX_ATTRIBUTE_LENGTH;
|
||||
|
||||
SpanLimitsBuilder() {}
|
||||
|
||||
/**
|
||||
* Sets the global default max number of attributes per {@link Span}.
|
||||
* Sets the max number of attributes per {@link Span}.
|
||||
*
|
||||
* @param maxNumberOfAttributes the global default max number of attributes per {@link Span}. It
|
||||
* must be positive otherwise {@link #build()} will throw an exception.
|
||||
* @param maxNumberOfAttributes the max number of attributes per {@link Span}. Must be positive.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxNumberOfAttributes} is not positive.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxNumberOfAttributes(int maxNumberOfAttributes) {
|
||||
Utils.checkArgument(maxNumberOfAttributes > 0, "maxNumberOfAttributes must be greater than 0");
|
||||
|
@ -39,11 +40,11 @@ public final class SpanLimitsBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the global default max number of events per {@link Span}.
|
||||
* Sets the max number of events per {@link Span}.
|
||||
*
|
||||
* @param maxNumberOfEvents the global default max number of events per {@link Span}. It must be
|
||||
* positive otherwise {@link #build()} will throw an exception.
|
||||
* @param maxNumberOfEvents the max number of events per {@link Span}. Must be positive.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxNumberOfEvents} is not positive.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxNumberOfEvents(int maxNumberOfEvents) {
|
||||
Utils.checkArgument(maxNumberOfEvents > 0, "maxNumberOfEvents must be greater than 0");
|
||||
|
@ -52,11 +53,11 @@ public final class SpanLimitsBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the global default max number of links per {@link Span}.
|
||||
* Sets the max number of links per {@link Span}.
|
||||
*
|
||||
* @param maxNumberOfLinks the global default max number of links per {@link Span}. It must be
|
||||
* positive otherwise {@link #build()} will throw an exception.
|
||||
* @param maxNumberOfLinks the max number of links per {@link Span}. Must be positive.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxNumberOfLinks} is not positive.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxNumberOfLinks(int maxNumberOfLinks) {
|
||||
Utils.checkArgument(maxNumberOfLinks > 0, "maxNumberOfLinks must be greater than 0");
|
||||
|
@ -65,11 +66,11 @@ public final class SpanLimitsBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the global default max number of attributes per event.
|
||||
* Sets the max number of attributes per event.
|
||||
*
|
||||
* @param maxNumberOfAttributesPerEvent the global default max number of attributes per event. It
|
||||
* must be positive otherwise {@link #build()} will throw an exception.
|
||||
* @param maxNumberOfAttributesPerEvent the max number of attributes per event. Must be positive.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxNumberOfAttributesPerEvent} is not positive.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxNumberOfAttributesPerEvent(int maxNumberOfAttributesPerEvent) {
|
||||
Utils.checkArgument(
|
||||
|
@ -79,11 +80,11 @@ public final class SpanLimitsBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the global default max number of attributes per link.
|
||||
* Sets the max number of attributes per link.
|
||||
*
|
||||
* @param maxNumberOfAttributesPerLink the global default max number of attributes per link. It
|
||||
* must be positive otherwise {@link #build()} will throw an exception.
|
||||
* @param maxNumberOfAttributesPerLink the max number of attributes per link. Must be positive.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxNumberOfAttributesPerLink} is not positive.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxNumberOfAttributesPerLink(int maxNumberOfAttributesPerLink) {
|
||||
Utils.checkArgument(
|
||||
|
@ -92,6 +93,20 @@ public final class SpanLimitsBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the max number of characters for string attribute values. For string array attributes
|
||||
* values, applies to each entry individually.
|
||||
*
|
||||
* @param maxAttributeLength the max characters for string attribute values. Must not be negative.
|
||||
* @return this.
|
||||
* @throws IllegalArgumentException if {@code maxAttributeLength} is negative.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxAttributeLength(int maxAttributeLength) {
|
||||
Utils.checkArgument(maxAttributeLength > -1, "maxAttributeLength must be non-negative");
|
||||
this.maxAttributeLength = maxAttributeLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds and returns a {@link SpanLimits} with the values of this builder. */
|
||||
public SpanLimits build() {
|
||||
return SpanLimits.create(
|
||||
|
@ -99,6 +114,7 @@ public final class SpanLimitsBuilder {
|
|||
maxNumEvents,
|
||||
maxNumLinks,
|
||||
maxNumAttributesPerEvent,
|
||||
maxNumAttributesPerLink);
|
||||
maxNumAttributesPerLink,
|
||||
maxAttributeLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ class AttributesMapTest {
|
|||
|
||||
@Test
|
||||
void asMap() {
|
||||
AttributesMap attributesMap = new AttributesMap(2);
|
||||
AttributesMap attributesMap = new AttributesMap(2, Integer.MAX_VALUE);
|
||||
attributesMap.put(longKey("one"), 1L);
|
||||
attributesMap.put(longKey("two"), 2L);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import static io.opentelemetry.api.common.AttributeKey.longArrayKey;
|
|||
import static io.opentelemetry.api.common.AttributeKey.longKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
|
@ -49,6 +50,7 @@ import java.util.concurrent.ExecutorService;
|
|||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -687,6 +689,82 @@ class RecordEventsReadableSpanTest {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributeLength() {
|
||||
int maxLength = 25;
|
||||
RecordEventsReadableSpan span =
|
||||
createTestSpan(SpanLimits.builder().setMaxAttributeLength(maxLength).build());
|
||||
try {
|
||||
String strVal = IntStream.range(0, maxLength).mapToObj(i -> "a").collect(joining());
|
||||
String tooLongStrVal = strVal + strVal;
|
||||
|
||||
Attributes attributes =
|
||||
Attributes.builder()
|
||||
.put("string", tooLongStrVal)
|
||||
.put("boolean", true)
|
||||
.put("long", 1L)
|
||||
.put("double", 1.0)
|
||||
.put(stringArrayKey("stringArray"), Arrays.asList(strVal, tooLongStrVal))
|
||||
.put(booleanArrayKey("booleanArray"), Arrays.asList(true, false))
|
||||
.put(longArrayKey("longArray"), Arrays.asList(1L, 2L))
|
||||
.put(doubleArrayKey("doubleArray"), Arrays.asList(1.0, 2.0))
|
||||
.build();
|
||||
span.setAllAttributes(attributes);
|
||||
|
||||
attributes = span.toSpanData().getAttributes();
|
||||
assertThat(attributes.get(stringKey("string"))).isEqualTo(strVal);
|
||||
assertThat(attributes.get(booleanKey("boolean"))).isEqualTo(true);
|
||||
assertThat(attributes.get(longKey("long"))).isEqualTo(1L);
|
||||
assertThat(attributes.get(doubleKey("double"))).isEqualTo(1.0);
|
||||
assertThat(attributes.get(stringArrayKey("stringArray")))
|
||||
.isEqualTo(Arrays.asList(strVal, strVal));
|
||||
assertThat(attributes.get(booleanArrayKey("booleanArray")))
|
||||
.isEqualTo(Arrays.asList(true, false));
|
||||
assertThat(attributes.get(longArrayKey("longArray"))).isEqualTo(Arrays.asList(1L, 2L));
|
||||
assertThat(attributes.get(doubleArrayKey("doubleArray"))).isEqualTo(Arrays.asList(1.0, 2.0));
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void eventAttributeLength() {
|
||||
int maxLength = 25;
|
||||
RecordEventsReadableSpan span =
|
||||
createTestSpan(SpanLimits.builder().setMaxAttributeLength(maxLength).build());
|
||||
try {
|
||||
String strVal = IntStream.range(0, maxLength).mapToObj(i -> "a").collect(joining());
|
||||
String tooLongStrVal = strVal + strVal;
|
||||
|
||||
Attributes attributes =
|
||||
Attributes.builder()
|
||||
.put("string", tooLongStrVal)
|
||||
.put("boolean", true)
|
||||
.put("long", 1L)
|
||||
.put("double", 1.0)
|
||||
.put(stringArrayKey("stringArray"), Arrays.asList(strVal, tooLongStrVal))
|
||||
.put(booleanArrayKey("booleanArray"), Arrays.asList(true, false))
|
||||
.put(longArrayKey("longArray"), Arrays.asList(1L, 2L))
|
||||
.put(doubleArrayKey("doubleArray"), Arrays.asList(1.0, 2.0))
|
||||
.build();
|
||||
span.setAllAttributes(attributes);
|
||||
|
||||
attributes = span.toSpanData().getAttributes();
|
||||
assertThat(attributes.get(stringKey("string"))).isEqualTo(strVal);
|
||||
assertThat(attributes.get(booleanKey("boolean"))).isEqualTo(true);
|
||||
assertThat(attributes.get(longKey("long"))).isEqualTo(1L);
|
||||
assertThat(attributes.get(doubleKey("double"))).isEqualTo(1.0);
|
||||
assertThat(attributes.get(stringArrayKey("stringArray")))
|
||||
.isEqualTo(Arrays.asList(strVal, strVal));
|
||||
assertThat(attributes.get(booleanArrayKey("booleanArray")))
|
||||
.isEqualTo(Arrays.asList(true, false));
|
||||
assertThat(attributes.get(longArrayKey("longArray"))).isEqualTo(Arrays.asList(1L, 2L));
|
||||
assertThat(attributes.get(doubleArrayKey("doubleArray"))).isEqualTo(Arrays.asList(1.0, 2.0));
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void droppingAttributes() {
|
||||
final int maxNumberOfAttributes = 8;
|
||||
|
@ -915,8 +993,10 @@ class RecordEventsReadableSpanTest {
|
|||
|
||||
private RecordEventsReadableSpan createTestSpanWithAttributes(
|
||||
Map<AttributeKey, Object> attributes) {
|
||||
SpanLimits spanLimits = SpanLimits.getDefault();
|
||||
AttributesMap attributesMap =
|
||||
new AttributesMap(SpanLimits.getDefault().getMaxNumberOfAttributes());
|
||||
new AttributesMap(
|
||||
spanLimits.getMaxNumberOfAttributes(), spanLimits.getMaxAttributeValueLength());
|
||||
attributes.forEach(attributesMap::put);
|
||||
return createTestSpan(
|
||||
SpanKind.INTERNAL,
|
||||
|
@ -1033,7 +1113,7 @@ class RecordEventsReadableSpanTest {
|
|||
TestClock clock = TestClock.create();
|
||||
Resource resource = this.resource;
|
||||
Attributes attributes = TestUtils.generateRandomAttributes();
|
||||
final AttributesMap attributesWithCapacity = new AttributesMap(32);
|
||||
final AttributesMap attributesWithCapacity = new AttributesMap(32, Integer.MAX_VALUE);
|
||||
attributes.forEach((key, value) -> attributesWithCapacity.put((AttributeKey) key, value));
|
||||
Attributes event1Attributes = TestUtils.generateRandomAttributes();
|
||||
Attributes event2Attributes = TestUtils.generateRandomAttributes();
|
||||
|
|
|
@ -14,6 +14,7 @@ import static io.opentelemetry.api.common.AttributeKey.longKey;
|
|||
import static io.opentelemetry.api.common.AttributeKey.stringArrayKey;
|
||||
import static io.opentelemetry.api.common.AttributeKey.stringKey;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||
|
||||
|
@ -39,6 +40,7 @@ import java.time.Instant;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.annotation.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -152,6 +154,49 @@ class SdkSpanBuilderTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void linkAttributeLength() {
|
||||
int maxLength = 25;
|
||||
TracerProvider tracerProvider =
|
||||
SdkTracerProvider.builder()
|
||||
.setSpanLimits(SpanLimits.builder().setMaxAttributeLength(maxLength).build())
|
||||
.build();
|
||||
SpanBuilder spanBuilder = tracerProvider.get("test").spanBuilder(SPAN_NAME);
|
||||
String strVal = IntStream.range(0, maxLength).mapToObj(i -> "a").collect(joining());
|
||||
String tooLongStrVal = strVal + strVal;
|
||||
|
||||
Attributes attributes =
|
||||
Attributes.builder()
|
||||
.put("string", tooLongStrVal)
|
||||
.put("boolean", true)
|
||||
.put("long", 1L)
|
||||
.put("double", 1.0)
|
||||
.put(stringArrayKey("stringArray"), Arrays.asList(strVal, tooLongStrVal))
|
||||
.put(booleanArrayKey("booleanArray"), Arrays.asList(true, false))
|
||||
.put(longArrayKey("longArray"), Arrays.asList(1L, 2L))
|
||||
.put(doubleArrayKey("doubleArray"), Arrays.asList(1.0, 2.0))
|
||||
.build();
|
||||
spanBuilder.addLink(sampledSpanContext, attributes);
|
||||
|
||||
RecordEventsReadableSpan span = (RecordEventsReadableSpan) spanBuilder.startSpan();
|
||||
try {
|
||||
attributes = span.toSpanData().getLinks().get(0).getAttributes();
|
||||
|
||||
assertThat(attributes.get(stringKey("string"))).isEqualTo(strVal);
|
||||
assertThat(attributes.get(booleanKey("boolean"))).isEqualTo(true);
|
||||
assertThat(attributes.get(longKey("long"))).isEqualTo(1L);
|
||||
assertThat(attributes.get(doubleKey("double"))).isEqualTo(1.0);
|
||||
assertThat(attributes.get(stringArrayKey("stringArray")))
|
||||
.isEqualTo(Arrays.asList(strVal, strVal));
|
||||
assertThat(attributes.get(booleanArrayKey("booleanArray")))
|
||||
.isEqualTo(Arrays.asList(true, false));
|
||||
assertThat(attributes.get(longArrayKey("longArray"))).isEqualTo(Arrays.asList(1L, 2L));
|
||||
assertThat(attributes.get(doubleArrayKey("doubleArray"))).isEqualTo(Arrays.asList(1.0, 2.0));
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addLink_NoEffectAfterStartSpan() {
|
||||
SpanBuilder spanBuilder = sdkTracer.spanBuilder(SPAN_NAME);
|
||||
|
|
Loading…
Reference in New Issue