Skip to content

Commit

Permalink
Stabilize ExceptionEventData (#6795)
Browse files Browse the repository at this point in the history
Co-authored-by: jack-berg <[email protected]>
Co-authored-by: Jack Berg <[email protected]>
  • Loading branch information
3 people authored Oct 29, 2024
1 parent 3f05bf6 commit fcae15e
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 186 deletions.
7 changes: 6 additions & 1 deletion docs/apidiffs/current_vs_latest/opentelemetry-sdk-trace.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
Comparing source compatibility of opentelemetry-sdk-trace-1.44.0-SNAPSHOT.jar against opentelemetry-sdk-trace-1.43.0.jar
No changes.
+++ NEW INTERFACE: PUBLIC(+) ABSTRACT(+) io.opentelemetry.sdk.trace.data.ExceptionEventData (not serializable)
+++ CLASS FILE FORMAT VERSION: 52.0 <- n.a.
+++ NEW INTERFACE: io.opentelemetry.sdk.trace.data.EventData
+++ NEW SUPERCLASS: java.lang.Object
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.trace.data.ExceptionEventData create(long, java.lang.Throwable, io.opentelemetry.api.common.Attributes, int)
+++ NEW METHOD: PUBLIC(+) ABSTRACT(+) java.lang.Throwable getException()
40 changes: 37 additions & 3 deletions sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import io.opentelemetry.sdk.internal.InstrumentationScopeUtil;
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.ExceptionEventData;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor;
import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -115,6 +117,13 @@ private enum EndState {
@Nullable
private Thread spanEndingThread;

private static final AttributeKey<String> EXCEPTION_TYPE =
AttributeKey.stringKey("exception.type");
private static final AttributeKey<String> EXCEPTION_MESSAGE =
AttributeKey.stringKey("exception.message");
private static final AttributeKey<String> EXCEPTION_STACKTRACE =
AttributeKey.stringKey("exception.stacktrace");

private SdkSpan(
SpanContext context,
String name,
Expand Down Expand Up @@ -436,7 +445,8 @@ public ReadWriteSpan setStatus(StatusCode statusCode, @Nullable String descripti

@Override
public ReadWriteSpan recordException(Throwable exception) {
recordException(exception, Attributes.empty());
Attributes attributes = this.getAttributes();
recordException(exception, attributes);
return this;
}

Expand All @@ -449,8 +459,32 @@ public ReadWriteSpan recordException(Throwable exception, Attributes additionalA
additionalAttributes = Attributes.empty();
}

AttributesMap attributes =
AttributesMap.create(
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 = stringWriter.toString();

if (exceptionName != null) {
attributes.put(EXCEPTION_TYPE, exceptionName);
}
if (exceptionMessage != null) {
attributes.put(EXCEPTION_MESSAGE, exceptionMessage);
}
if (stackTrace != null) {
attributes.put(EXCEPTION_STACKTRACE, stackTrace);
}

additionalAttributes.forEach(attributes::put);

addTimedEvent(
ExceptionEventData.create(spanLimits, clock.now(), exception, additionalAttributes));
ExceptionEventData.create(
clock.now(), exception, attributes, attributes.getTotalAddedValues()));
return this;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.data;

import io.opentelemetry.api.common.Attributes;
import javax.annotation.concurrent.Immutable;

/** Data representation of an event for a recorded exception. */
@Immutable
public interface ExceptionEventData extends EventData {

/**
* Returns a new immutable {@link ExceptionEventData}.
*
* @param epochNanos epoch timestamp in nanos of the {@link ExceptionEventData}.
* @param exception the {@link Throwable exception} of the {@code Event}.
* @param attributes the additional attributes of the {@link ExceptionEventData}.
* @param totalAttributeCount the total number of attributes for this {@code} Event.
* @return a new immutable {@link ExceptionEventData}
*/
static ExceptionEventData create(
long epochNanos, Throwable exception, Attributes attributes, int totalAttributeCount) {
return ImmutableExceptionEventData.create(
epochNanos, exception, attributes, totalAttributeCount);
}

/**
* Return the {@link Throwable exception} of the {@link ExceptionEventData}.
*
* @return the {@link Throwable exception} of the {@link ExceptionEventData}
*/
Throwable getException();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.sdk.trace.data;

import com.google.auto.value.AutoValue;
import io.opentelemetry.api.common.Attributes;
import javax.annotation.concurrent.Immutable;

/** An effectively immutable implementation of {@link ExceptionEventData}. */
@AutoValue
@Immutable
abstract class ImmutableExceptionEventData implements ExceptionEventData {

private static final String EXCEPTION_EVENT_NAME = "exception";

@Override
public final String getName() {
return EXCEPTION_EVENT_NAME;
}

/**
* Returns a new immutable {@code Event}.
*
* @param epochNanos epoch timestamp in nanos of the {@code Event}.
* @param exception the {@link Throwable exception} of the {@code Event}.
* @param attributes the additional {@link Attributes} of the {@code Event}.
* @param totalAttributeCount the total number of attributes for this {@code} Event.
* @return a new immutable {@code Event<T>}
*/
static ExceptionEventData create(
long epochNanos, Throwable exception, Attributes attributes, int totalAttributeCount) {
return new AutoValue_ImmutableExceptionEventData(
attributes, epochNanos, totalAttributeCount, exception);
}

ImmutableExceptionEventData() {}
}

This file was deleted.

This file was deleted.

This file was deleted.

38 changes: 13 additions & 25 deletions sdk/trace/src/test/java/io/opentelemetry/sdk/trace/SdkSpanTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@
import io.opentelemetry.sdk.resources.Resource;
import io.opentelemetry.sdk.testing.time.TestClock;
import io.opentelemetry.sdk.trace.data.EventData;
import io.opentelemetry.sdk.trace.data.ExceptionEventData;
import io.opentelemetry.sdk.trace.data.LinkData;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.data.StatusData;
import io.opentelemetry.sdk.trace.internal.ExtendedSpanProcessor;
import io.opentelemetry.sdk.trace.internal.data.ExceptionEventData;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Duration;
Expand Down Expand Up @@ -1166,20 +1166,16 @@ void recordException() {
EventData event = events.get(0);
assertThat(event.getName()).isEqualTo("exception");
assertThat(event.getEpochNanos()).isEqualTo(timestamp);
assertThat(event.getAttributes())
.isEqualTo(
Attributes.builder()
.put("exception.type", "java.lang.IllegalStateException")
.put("exception.message", "there was an exception")
.put("exception.stacktrace", stacktrace)
.build());

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"))).isEqualTo(stacktrace);
assertThat(event)
.isInstanceOfSatisfying(
ExceptionEventData.class,
exceptionEvent -> {
assertThat(exceptionEvent.getException()).isSameAs(exception);
assertThat(exceptionEvent.getAdditionalAttributes()).isEqualTo(Attributes.empty());
});
}

Expand Down Expand Up @@ -1237,27 +1233,19 @@ void recordException_additionalAttributes() {
EventData event = events.get(0);
assertThat(event.getName()).isEqualTo("exception");
assertThat(event.getEpochNanos()).isEqualTo(timestamp);
assertThat(event.getAttributes())
.isEqualTo(
Attributes.builder()
.put("key1", "this is an additional attribute")
.put("exception.type", "java.lang.IllegalStateException")
.put("exception.message", "this is a precedence attribute")
.put("exception.stacktrace", stacktrace)
.build());
assertThat(event.getAttributes().get(stringKey("exception.message")))
.isEqualTo("this is a precedence attribute");
assertThat(event.getAttributes().get(stringKey("key1")))
.isEqualTo("this is an additional attribute");
assertThat(event.getAttributes().get(stringKey("exception.type")))
.isEqualTo("java.lang.IllegalStateException");
assertThat(event.getAttributes().get(stringKey("exception.stacktrace"))).isEqualTo(stacktrace);

assertThat(event)
.isInstanceOfSatisfying(
ExceptionEventData.class,
exceptionEvent -> {
assertThat(exceptionEvent.getException()).isSameAs(exception);
assertThat(exceptionEvent.getAdditionalAttributes())
.isEqualTo(
Attributes.of(
stringKey("key1"),
"this is an additional attribute",
stringKey("exception.message"),
"this is a precedence attribute"));
});
}

Expand Down

0 comments on commit fcae15e

Please sign in to comment.