[Breaking Change] Remove attribute value truncation. (#2841)

This commit is contained in:
Anuraag Agrawal 2021-02-18 02:08:39 +09:00 committed by GitHub
parent a100a45780
commit 224845b6b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 5 additions and 260 deletions

View File

@ -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()

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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() {}
}

View File

@ -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() {