[Breaking Change] Remove attribute value truncation. (#2841)
This commit is contained in:
parent
a100a45780
commit
224845b6b1
|
|
@ -129,7 +129,7 @@ class OpenTelemetrySdkTest {
|
|||
// Demonstrates how clear or confusing is SDK configuration
|
||||
@Test
|
||||
void fullOpenTelemetrySdkConfigurationDemo() {
|
||||
SpanLimits newConfig = SpanLimits.builder().setMaxLengthOfAttributeValues(128).build();
|
||||
SpanLimits newConfig = SpanLimits.builder().setMaxNumberOfAttributes(512).build();
|
||||
|
||||
OpenTelemetrySdkBuilder sdkBuilder =
|
||||
OpenTelemetrySdk.builder()
|
||||
|
|
|
|||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.trace;
|
||||
|
||||
import io.opentelemetry.api.trace.SpanKind;
|
||||
import io.opentelemetry.api.trace.Tracer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Threads;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
@State(Scope.Benchmark)
|
||||
public class SpanAttributeTruncateBenchmark {
|
||||
|
||||
private SdkSpanBuilder sdkSpanBuilder;
|
||||
|
||||
public final String shortValue = "short";
|
||||
public final String longValue = "very_long_attribute_and_then_some_more";
|
||||
public String veryLongValue;
|
||||
|
||||
@Param({"10", "1000000"})
|
||||
public int maxLength;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public final void setup() {
|
||||
Tracer tracer =
|
||||
SdkTracerProvider.builder()
|
||||
.setSpanLimits(SpanLimits.builder().setMaxLengthOfAttributeValues(maxLength).build())
|
||||
.build()
|
||||
.get("benchmarkTracer");
|
||||
sdkSpanBuilder =
|
||||
(SdkSpanBuilder)
|
||||
tracer
|
||||
.spanBuilder("benchmarkSpan")
|
||||
.setSpanKind(SpanKind.CLIENT)
|
||||
.setAttribute("key", "value");
|
||||
|
||||
String seed = "0123456789";
|
||||
StringBuilder longString = new StringBuilder();
|
||||
while (longString.length() < 10_000_000) {
|
||||
longString.append(seed);
|
||||
}
|
||||
veryLongValue = longString.toString();
|
||||
}
|
||||
|
||||
/** attributes that don't require any truncation. */
|
||||
@Benchmark
|
||||
@Threads(value = 1)
|
||||
@Fork(1)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 10, time = 1)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public RecordEventsReadableSpan shortAttributes() {
|
||||
RecordEventsReadableSpan span = (RecordEventsReadableSpan) sdkSpanBuilder.startSpan();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
span.setAttribute(String.valueOf(i), shortValue);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/** even if we truncate, result is short. */
|
||||
@Benchmark
|
||||
@Threads(value = 1)
|
||||
@Fork(1)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 10, time = 1)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public RecordEventsReadableSpan longAttributes() {
|
||||
RecordEventsReadableSpan span = (RecordEventsReadableSpan) sdkSpanBuilder.startSpan();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
span.setAttribute(String.valueOf(i), longValue);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/** have to copy very long strings. */
|
||||
@Benchmark
|
||||
@Threads(value = 1)
|
||||
@Fork(1)
|
||||
@Warmup(iterations = 5, time = 1)
|
||||
@Measurement(iterations = 10, time = 1)
|
||||
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||
public RecordEventsReadableSpan veryLongAttributes() {
|
||||
RecordEventsReadableSpan span = (RecordEventsReadableSpan) sdkSpanBuilder.startSpan();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
span.setAttribute(String.valueOf(i), veryLongValue);
|
||||
}
|
||||
return span;
|
||||
}
|
||||
}
|
||||
|
|
@ -263,10 +263,6 @@ final class RecordEventsReadableSpan implements ReadWriteSpan {
|
|||
attributes = new AttributesMap(spanLimits.getMaxNumberOfAttributes());
|
||||
}
|
||||
|
||||
if (spanLimits.shouldTruncateStringAttributeValues()) {
|
||||
value = StringUtils.truncateToSize(key, value, spanLimits.getMaxLengthOfAttributeValues());
|
||||
}
|
||||
|
||||
attributes.put(key, value);
|
||||
}
|
||||
return this;
|
||||
|
|
|
|||
|
|
@ -144,10 +144,6 @@ final class SdkSpanBuilder implements SpanBuilder {
|
|||
attributes = new AttributesMap(spanLimits.getMaxNumberOfAttributes());
|
||||
}
|
||||
|
||||
if (spanLimits.shouldTruncateStringAttributeValues()) {
|
||||
value = StringUtils.truncateToSize(key, value, spanLimits.getMaxLengthOfAttributeValues());
|
||||
}
|
||||
|
||||
attributes.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,13 +21,6 @@ import javax.annotation.concurrent.Immutable;
|
|||
@Immutable
|
||||
public abstract class SpanLimits {
|
||||
|
||||
/**
|
||||
* Value for attribute length which indicates attributes should not be truncated.
|
||||
*
|
||||
* @see SpanLimitsBuilder#setMaxLengthOfAttributeValues(int)
|
||||
*/
|
||||
public static final int UNLIMITED_ATTRIBUTE_LENGTH = -1;
|
||||
|
||||
// These values are the default values for all the global parameters.
|
||||
// TODO: decide which default sampler to use
|
||||
|
||||
|
|
@ -48,15 +41,13 @@ public abstract class SpanLimits {
|
|||
int maxNumEvents,
|
||||
int maxNumLinks,
|
||||
int maxNumAttributesPerEvent,
|
||||
int maxNumAttributesPerLink,
|
||||
int maxAttributeLength) {
|
||||
int maxNumAttributesPerLink) {
|
||||
return new AutoValue_SpanLimits(
|
||||
maxNumAttributes,
|
||||
maxNumEvents,
|
||||
maxNumLinks,
|
||||
maxNumAttributesPerEvent,
|
||||
maxNumAttributesPerLink,
|
||||
maxAttributeLength);
|
||||
maxNumAttributesPerLink);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -94,18 +85,6 @@ public abstract class SpanLimits {
|
|||
*/
|
||||
public abstract int getMaxNumberOfAttributesPerLink();
|
||||
|
||||
/**
|
||||
* Returns the global default max length of string attribute value in characters.
|
||||
*
|
||||
* @return the global default max length of string attribute value in characters.
|
||||
* @see #shouldTruncateStringAttributeValues()
|
||||
*/
|
||||
public abstract int getMaxLengthOfAttributeValues();
|
||||
|
||||
public boolean shouldTruncateStringAttributeValues() {
|
||||
return getMaxLengthOfAttributeValues() != UNLIMITED_ATTRIBUTE_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link SpanLimitsBuilder} initialized to the same property values as the current
|
||||
* instance.
|
||||
|
|
@ -119,7 +98,6 @@ public abstract class SpanLimits {
|
|||
.setMaxNumberOfEvents(getMaxNumberOfEvents())
|
||||
.setMaxNumberOfLinks(getMaxNumberOfLinks())
|
||||
.setMaxNumberOfAttributesPerEvent(getMaxNumberOfAttributesPerEvent())
|
||||
.setMaxNumberOfAttributesPerLink(getMaxNumberOfAttributesPerLink())
|
||||
.setMaxLengthOfAttributeValues(getMaxLengthOfAttributeValues());
|
||||
.setMaxNumberOfAttributesPerLink(getMaxNumberOfAttributesPerLink());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,14 +15,12 @@ public final class SpanLimitsBuilder {
|
|||
private static final int DEFAULT_SPAN_MAX_NUM_LINKS = 128;
|
||||
private static final int DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_EVENT = 128;
|
||||
private static final int DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_LINK = 128;
|
||||
private static final int DEFAULT_MAX_ATTRIBUTE_LENGTH = SpanLimits.UNLIMITED_ATTRIBUTE_LENGTH;
|
||||
|
||||
private int maxNumAttributes = DEFAULT_SPAN_MAX_NUM_ATTRIBUTES;
|
||||
private int maxNumEvents = DEFAULT_SPAN_MAX_NUM_EVENTS;
|
||||
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 = DEFAULT_MAX_ATTRIBUTE_LENGTH;
|
||||
|
||||
SpanLimitsBuilder() {}
|
||||
|
||||
|
|
@ -93,23 +91,6 @@ public final class SpanLimitsBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the global default max length of string attribute value in characters.
|
||||
*
|
||||
* @param maxLengthOfAttributeValues the global default max length of string attribute value in
|
||||
* characters. It must be non-negative (or {@link SpanLimits#UNLIMITED_ATTRIBUTE_LENGTH})
|
||||
* otherwise {@link #build()} will throw an exception.
|
||||
* @return this.
|
||||
*/
|
||||
public SpanLimitsBuilder setMaxLengthOfAttributeValues(int maxLengthOfAttributeValues) {
|
||||
Utils.checkArgument(
|
||||
maxLengthOfAttributeValues == -1 || maxLengthOfAttributeValues > 0,
|
||||
"maxLengthOfAttributeValues must be -1 to "
|
||||
+ "disable length restriction, or positive to enable length restriction");
|
||||
this.maxAttributeLength = maxLengthOfAttributeValues;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds and returns a {@link SpanLimits} with the values of this builder. */
|
||||
public SpanLimits build() {
|
||||
return SpanLimits.create(
|
||||
|
|
@ -117,7 +98,6 @@ public final class SpanLimitsBuilder {
|
|||
maxNumEvents,
|
||||
maxNumLinks,
|
||||
maxNumAttributesPerEvent,
|
||||
maxNumAttributesPerLink,
|
||||
maxAttributeLength);
|
||||
maxNumAttributesPerLink);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* 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.AttributeType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
final class StringUtils {
|
||||
/**
|
||||
* If given attribute is of type STRING and has more characters than given {@code limit} then
|
||||
* return new value with string truncated to {@code limit} characters.
|
||||
*
|
||||
* <p>If given attribute is of type STRING_ARRAY and non-empty then return new value with every
|
||||
* element truncated to {@code limit} characters.
|
||||
*
|
||||
* <p>Otherwise return given {@code value}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static <T> T truncateToSize(AttributeKey<T> key, T value, int limit) {
|
||||
if (value == null
|
||||
|| ((key.getType() != AttributeType.STRING)
|
||||
&& (key.getType() != AttributeType.STRING_ARRAY))) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (key.getType() == AttributeType.STRING_ARRAY) {
|
||||
List<String> strings = (List<String>) value;
|
||||
if (strings.isEmpty()) {
|
||||
return value;
|
||||
}
|
||||
|
||||
List<String> newStrings = new ArrayList<>(strings.size());
|
||||
for (String string : strings) {
|
||||
newStrings.add(truncateToSize(string, limit));
|
||||
}
|
||||
|
||||
return (T) newStrings;
|
||||
}
|
||||
|
||||
return (T) truncateToSize((String) value, limit);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String truncateToSize(@Nullable String s, int limit) {
|
||||
if (s == null || s.length() <= limit) {
|
||||
return s;
|
||||
}
|
||||
return s.substring(0, limit);
|
||||
}
|
||||
|
||||
private StringUtils() {}
|
||||
}
|
||||
|
|
@ -373,52 +373,6 @@ class SdkSpanBuilderTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void tooLargeAttributeValuesAreTruncated() {
|
||||
SpanLimits spanLimits = SpanLimits.builder().setMaxLengthOfAttributeValues(10).build();
|
||||
TracerProvider tracerProvider = SdkTracerProvider.builder().setSpanLimits(spanLimits).build();
|
||||
// Verify methods do not crash.
|
||||
SpanBuilder spanBuilder = tracerProvider.get("test").spanBuilder(SPAN_NAME);
|
||||
spanBuilder.setAttribute("builderStringNull", null);
|
||||
spanBuilder.setAttribute("builderStringSmall", "small");
|
||||
spanBuilder.setAttribute("builderStringLarge", "very large string that we have to cut");
|
||||
spanBuilder.setAttribute("builderLong", 42L);
|
||||
spanBuilder.setAttribute(
|
||||
stringKey("builderStringLargeValue"), "very large string that we have to cut");
|
||||
spanBuilder.setAttribute(
|
||||
stringArrayKey("builderStringArray"),
|
||||
Arrays.asList("small", null, "very large string that we have to cut"));
|
||||
|
||||
RecordEventsReadableSpan span = (RecordEventsReadableSpan) spanBuilder.startSpan();
|
||||
span.setAttribute("spanStringSmall", "small");
|
||||
span.setAttribute("spanStringLarge", "very large string that we have to cut");
|
||||
span.setAttribute("spanLong", 42L);
|
||||
span.setAttribute(stringKey("spanStringLarge"), "very large string that we have to cut");
|
||||
span.setAttribute(
|
||||
stringArrayKey("spanStringArray"),
|
||||
Arrays.asList("small", null, "very large string that we have to cut"));
|
||||
|
||||
try {
|
||||
Attributes attrs = span.toSpanData().getAttributes();
|
||||
assertThat(attrs.get(stringKey("builderStringNull"))).isEqualTo(null);
|
||||
assertThat(attrs.get(stringKey("builderStringSmall"))).isEqualTo("small");
|
||||
assertThat(attrs.get(stringKey("builderStringLarge"))).isEqualTo("very large");
|
||||
assertThat(attrs.get(longKey("builderLong"))).isEqualTo(42L);
|
||||
assertThat(attrs.get(stringKey("builderStringLargeValue"))).isEqualTo("very large");
|
||||
assertThat(attrs.get(stringArrayKey("builderStringArray")))
|
||||
.isEqualTo(Arrays.asList("small", null, "very large"));
|
||||
|
||||
assertThat(attrs.get(stringKey("spanStringSmall"))).isEqualTo("small");
|
||||
assertThat(attrs.get(stringKey("spanStringLarge"))).isEqualTo("very large");
|
||||
assertThat(attrs.get(longKey("spanLong"))).isEqualTo(42L);
|
||||
assertThat(attrs.get(stringKey("spanStringLarge"))).isEqualTo("very large");
|
||||
assertThat(attrs.get(stringArrayKey("spanStringArray")))
|
||||
.isEqualTo(Arrays.asList("small", null, "very large"));
|
||||
} finally {
|
||||
span.end();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void addAttributes_OnlyViaSampler() {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue