Repository: open-telemetry/opentelemetry-java
File: sdk/common/src/main/java/io/opentelemetry/sdk/internal/ExceptionAttributeResolver.java (Java)

Code before:
import javax.annotation.Nullable;

/**
 * Implementations resolve {@code exception.*} attributes attached to span events, logs, etc.
 *
 * <p>This class is internal and experimental. Its APIs are unstable and can change at any time. Its
 * APIs (or a version of them) may be promoted to the public stable API in the future, but no
 * guarantees are made.
 */
public interface ExceptionAttributeResolver {

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

  /**
   * Resolve the {@link #EXCEPTION_TYPE} attribute from the {@code throwable}, or {@code null} if no
   * value should be set.
   *
   * @param throwable the throwable
   * @param maxAttributeLength the max attribute length that will be retained by the SDK. Responses
   *     are not required to conform to this limit, but implementations may incorporate this limit
   *     to avoid unnecessary compute.
   */
  @Nullable
  String getExceptionType(Throwable throwable, int maxAttributeLength);

  /**
   * Resolve the {@link #EXCEPTION_MESSAGE} attribute from the {@code throwable}, or {@code null} if
   * no value should be set.
   *
   * @param throwable the throwable
   * @param maxAttributeLength the max attribute length that will be retained by the SDK. Responses
   *     are not required to conform to this limit, but implementations may incorporate this limit
   *     to avoid unnecessary compute.
   */
  @Nullable
  String getExceptionMessage(Throwable throwable, int maxAttributeLength);

  /**
   * Resolve the {@link #EXCEPTION_STACKTRACE} attribute from the {@code throwable}, or {@code null}
   * if no value should be set.
   *
   * @param throwable the throwable
   * @param maxAttributeLength the max attribute length that will be retained by the SDK. Responses
   *     are not required to conform to this limit, but implementations may incorporate this limit
   *     to avoid unnecessary compute.
   */
  @Nullable
  String getExceptionStacktrace(Throwable throwable, int maxAttributeLength);
}

Review comment (refactor):
Realized that for alternative more perform implementations of `exception.stacktrace` to be possible, they need to know the attribute length limit so they can exit early.

The limit is much less relevant for `exception.type` and `exception.message`, but seemed more consistent to include it everywhere even if its likely not needed.

I also considered a solution where this is an abstract class instead of an interface, and has accepts max attribute length as a constructor parameter which is accessible by implementations. But in practice, max attribute length comes from SpanLimits, which can be re-configured at runtime by setting `Supplier<SpanLimit>`. And so an abstract class design would likely mean re-initializing ExceptionAttributeResolver for each span to ensure we get the up to date limits, which is wasteful. 

Better to include it as parameter in the API, despite it making the API appear a little cluttered.

Code after:
import javax.annotation.Nullable;

/**
 * Implementations resolve {@code exception.*} attributes attached to span events, logs, etc.
 *
 * <p>This class is internal and experimental. Its APIs are unstable and can change at any time. Its
 * APIs (or a version of them) may be promoted to the public stable API in the future, but no
 * guarantees are made.
 */
public interface ExceptionAttributeResolver {

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

  void setExceptionAttributes(
      AttributeSetter attributeSetter, Throwable throwable, int maxAttributeLength);

  /**
   * This class is internal and experimental. Its APIs are unstable and can change at any time. Its
   * APIs (or a version of them) may be promoted to the public stable API in the future, but no
   * guarantees are made.
   */
  // TODO(jack-berg): Consider promoting to opentelemetry and extending with Span, LogRecordBuilder,
  // AttributeBuilder, AttributesMap etc.
  interface AttributeSetter {
    <T> void setAttribute(AttributeKey<T> key, @Nullable T value);
  }
}