diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt index 48f428554cc..6b3185fa05d 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt @@ -1,2 +1,7 @@ Comparing source compatibility of opentelemetry-sdk-trace-1.48.0-SNAPSHOT.jar against opentelemetry-sdk-trace-1.47.0.jar -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC ABSTRACT io.opentelemetry.sdk.trace.SpanLimits (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + +++ NEW METHOD: PUBLIC(+) boolean isExcludeExceptionStackTrace() +*** 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 setExcludeExceptionStackTrace(boolean) diff --git a/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java b/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java index b6ee0aff2d4..bbee032e7b4 100644 --- a/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java +++ b/sdk/all/src/test/java/io/opentelemetry/sdk/OpenTelemetrySdkTest.java @@ -413,7 +413,7 @@ void stringRepresentation() { + "clock=SystemClock{}, " + "idGenerator=RandomIdGenerator{}, " + "resource=Resource{schemaUrl=null, attributes={service.name=\"otel-test\"}}, " - + "spanLimitsSupplier=SpanLimitsValue{maxNumberOfAttributes=128, maxNumberOfEvents=128, maxNumberOfLinks=128, maxNumberOfAttributesPerEvent=128, maxNumberOfAttributesPerLink=128, maxAttributeValueLength=2147483647}, " + + "spanLimitsSupplier=SpanLimitsValue{maxNumberOfAttributes=128, maxNumberOfEvents=128, maxNumberOfLinks=128, maxNumberOfAttributesPerEvent=128, maxNumberOfAttributesPerLink=128, maxAttributeValueLength=2147483647, excludeExceptionStackTrace=false}, " + "sampler=ParentBased{root:AlwaysOnSampler,remoteParentSampled:AlwaysOnSampler,remoteParentNotSampled:AlwaysOffSampler,localParentSampled:AlwaysOnSampler,localParentNotSampled:AlwaysOffSampler}, " + "spanProcessor=SimpleSpanProcessor{spanExporter=MultiSpanExporter{spanExporters=[MockSpanExporter{}, MockSpanExporter{}]}, exportUnsampledSpans=false}" + "}, " diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java index f3821c55540..27962a0500e 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java @@ -479,11 +479,14 @@ public ReadWriteSpan recordException(Throwable exception, Attributes additionalA spanLimits.getMaxNumberOfAttributes(), spanLimits.getMaxAttributeValueLength()); String exceptionName = exception.getClass().getCanonicalName(); String exceptionMessage = exception.getMessage(); - StringWriter stringWriter = new StringWriter(); - try (PrintWriter printWriter = new PrintWriter(stringWriter)) { - exception.printStackTrace(printWriter); + String stackTrace = null; + if (!spanLimits.isExcludeExceptionStackTrace()) { + StringWriter stringWriter = new StringWriter(); + try (PrintWriter printWriter = new PrintWriter(stringWriter)) { + exception.printStackTrace(printWriter); + } + stackTrace = stringWriter.toString(); } - String stackTrace = stringWriter.toString(); if (exceptionName != null) { attributes.put(EXCEPTION_TYPE, exceptionName); diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimits.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimits.java index adc98fd7f4d..a1b759570a3 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimits.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimits.java @@ -39,14 +39,16 @@ static SpanLimits create( int maxNumLinks, int maxNumAttributesPerEvent, int maxNumAttributesPerLink, - int maxAttributeLength) { + int maxAttributeLength, + boolean excludeExceptionStackTrace) { return new AutoValue_SpanLimits_SpanLimitsValue( maxNumAttributes, maxNumEvents, maxNumLinks, maxNumAttributesPerEvent, maxNumAttributesPerLink, - maxAttributeLength); + maxAttributeLength, + excludeExceptionStackTrace); } /** @@ -102,6 +104,15 @@ public int getMaxAttributeValueLength() { return DEFAULT_SPAN_MAX_ATTRIBUTE_LENGTH; } + /** + * Returns whether exception stack trace should be excluded from exception event attributes. + * + * @return whether exception stack trace should be excluded from exception event attributes. + */ + public boolean isExcludeExceptionStackTrace() { + return false; + } + /** * Returns a {@link SpanLimitsBuilder} initialized to the same property values as the current * instance. @@ -116,7 +127,8 @@ public SpanLimitsBuilder toBuilder() { .setMaxNumberOfLinks(getMaxNumberOfLinks()) .setMaxNumberOfAttributesPerEvent(getMaxNumberOfAttributesPerEvent()) .setMaxNumberOfAttributesPerLink(getMaxNumberOfAttributesPerLink()) - .setMaxAttributeValueLength(getMaxAttributeValueLength()); + .setMaxAttributeValueLength(getMaxAttributeValueLength()) + .setExcludeExceptionStackTrace(isExcludeExceptionStackTrace()); } @AutoValue @@ -129,5 +141,12 @@ abstract static class SpanLimitsValue extends SpanLimits { */ @Override public abstract int getMaxAttributeValueLength(); + + /** + * Override {@link SpanLimits#isExcludeExceptionStackTrace()} to be abstract so autovalue can + * implement it. + */ + @Override + public abstract boolean isExcludeExceptionStackTrace(); } } diff --git a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimitsBuilder.java b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimitsBuilder.java index 353bc19b044..d0b912641e7 100644 --- a/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimitsBuilder.java +++ b/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SpanLimitsBuilder.java @@ -23,6 +23,7 @@ public final class SpanLimitsBuilder { private int maxNumAttributesPerEvent = DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_EVENT; private int maxNumAttributesPerLink = DEFAULT_SPAN_MAX_NUM_ATTRIBUTES_PER_LINK; private int maxAttributeValueLength = SpanLimits.DEFAULT_SPAN_MAX_ATTRIBUTE_LENGTH; + private boolean excludeExceptionStackTrace = false; SpanLimitsBuilder() {} @@ -109,6 +110,18 @@ public SpanLimitsBuilder setMaxAttributeValueLength(int maxAttributeValueLength) return this; } + /** + * Sets whether exception stacktraces should be excluded from exception event attributes. + * + * @param excludeExceptionStackTrace whether exception stacktraces should be excluded from + * exception event attributes. + * @return this. + */ + public SpanLimitsBuilder setExcludeExceptionStackTrace(boolean excludeExceptionStackTrace) { + this.excludeExceptionStackTrace = excludeExceptionStackTrace; + return this; + } + /** Builds and returns a {@link SpanLimits} with the values of this builder. */ public SpanLimits build() { return SpanLimits.create( @@ -117,6 +130,7 @@ public SpanLimits build() { maxNumLinks, maxNumAttributesPerEvent, maxNumAttributesPerLink, - maxAttributeValueLength); + maxAttributeValueLength, + excludeExceptionStackTrace); } } diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java index 180fd377b0c..12edd0fe391 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java @@ -1277,6 +1277,38 @@ void recordException_additionalAttributes() { }); } + @Test + void recordException_excludeStackTrace() { + IllegalStateException exception = new IllegalStateException("there was an exception"); + SdkSpan span = createTestSpan(SpanLimits.builder().setExcludeExceptionStackTrace(true).build()); + + testClock.advance(Duration.ofNanos(1000)); + long timestamp = testClock.now(); + + // make sure that span attributes don't leak down to the exception event + span.setAttribute("spankey", "val"); + + span.recordException(exception); + + List events = span.toSpanData().getEvents(); + assertThat(events).hasSize(1); + EventData event = events.get(0); + assertThat(event.getName()).isEqualTo("exception"); + assertThat(event.getEpochNanos()).isEqualTo(timestamp); + assertThat(event.getAttributes().get(stringKey("exception.message"))) + .isEqualTo("there was an exception"); + assertThat(event.getAttributes().get(stringKey("exception.type"))) + .isEqualTo(exception.getClass().getName()); + assertThat(event.getAttributes().get(stringKey("exception.stacktrace"))).isNull(); + assertThat(event.getAttributes().size()).isEqualTo(2); + assertThat(event) + .isInstanceOfSatisfying( + ExceptionEventData.class, + exceptionEvent -> { + assertThat(exceptionEvent.getException()).isSameAs(exception); + }); + } + @Test void badArgsIgnored() { SdkSpan span = createTestRootSpan(); diff --git a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/config/SpanLimitsTest.java b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/config/SpanLimitsTest.java index 73d9ac2e842..f5b888fab50 100644 --- a/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/config/SpanLimitsTest.java +++ b/sdk/trace/src/test/java/io/opentelemetry/sdk/trace/config/SpanLimitsTest.java @@ -21,6 +21,7 @@ void defaultSpanLimits() { assertThat(SpanLimits.getDefault().getMaxNumberOfLinks()).isEqualTo(128); assertThat(SpanLimits.getDefault().getMaxNumberOfAttributesPerEvent()).isEqualTo(128); assertThat(SpanLimits.getDefault().getMaxNumberOfAttributesPerLink()).isEqualTo(128); + assertThat(SpanLimits.getDefault().isExcludeExceptionStackTrace()).isEqualTo(false); } @Test @@ -32,12 +33,14 @@ void updateSpanLimits_All() { .setMaxNumberOfLinks(11) .setMaxNumberOfAttributesPerEvent(1) .setMaxNumberOfAttributesPerLink(2) + .setExcludeExceptionStackTrace(true) .build(); assertThat(spanLimits.getMaxNumberOfAttributes()).isEqualTo(8); assertThat(spanLimits.getMaxNumberOfEvents()).isEqualTo(10); assertThat(spanLimits.getMaxNumberOfLinks()).isEqualTo(11); assertThat(spanLimits.getMaxNumberOfAttributesPerEvent()).isEqualTo(1); assertThat(spanLimits.getMaxNumberOfAttributesPerLink()).isEqualTo(2); + assertThat(spanLimits.isExcludeExceptionStackTrace()).isEqualTo(true); // Preserves values SpanLimits spanLimitsDupe = spanLimits.toBuilder().build();