Repository: open-telemetry/opentelemetry-java
File: sdk/trace/src/main/java/io/opentelemetry/sdk/trace/SdkSpan.java (Java)

Code before:
        stackTrace =
            stackTrace.substring(
                0, Math.min(stackTrace.length(), this.spanLimits.getMaxAttributeValueLength()));
      }
    }

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

    attributesBuilder.putAll(additionalAttributes);

    AttributeUtil.applyAttributesLimit(
        attributesBuilder.build(),
        spanLimits.getMaxNumberOfAttributesPerEvent(),
        spanLimits.getMaxAttributeValueLength());

    Attributes attributes = attributesBuilder.build();

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

  @Override
  public ReadWriteSpan updateName(String name) {
    if (name == null) {
      return this;
    }
    synchronized (lock) {
      if (!isModifiableByCurrentThread()) {
        logger.log(Level.FINE, "Calling updateName() on an ended Span.");
        return this;
      }
      this.name = name;
    }
    return this;
  }

  @Override
  public Span addLink(SpanContext spanContext, Attributes attributes) {
    if (spanContext == null || !spanContext.isValid()) {
      return this;
    }
    if (attributes == null) {
      attributes = Attributes.empty();

Review comment (suggestion):
We have a class called `AttributesMap` which applies span limits as entries are added:
```suggestion
    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(clock.now(), exception, attributes));
```


Code after:
    return this;
  }

  @Override
  public ReadWriteSpan updateName(String name) {
    if (name == null) {
      return this;
    }
    synchronized (lock) {
      if (!isModifiableByCurrentThread()) {
        logger.log(Level.FINE, "Calling updateName() on an ended Span.");
        return this;
      }
      this.name = name;
    }
    return this;
  }

  @Override
  public Span addLink(SpanContext spanContext, Attributes attributes) {
    if (spanContext == null || !spanContext.isValid()) {
      return this;
    }
    if (attributes == null) {
      attributes = Attributes.empty();
    }
    LinkData link =
        LinkData.create(
            spanContext,
            AttributeUtil.applyAttributesLimit(
                attributes,
                spanLimits.getMaxNumberOfAttributesPerLink(),
                spanLimits.getMaxAttributeValueLength()));
    synchronized (lock) {
      if (!isModifiableByCurrentThread()) {
        logger.log(Level.FINE, "Calling addLink() on an ended Span.");
        return this;
      }
      if (links == null) {
        links = new ArrayList<>();
      }
      if (links.size() < spanLimits.getMaxNumberOfLinks()) {
        links.add(link);
      }
      totalRecordedLinks++;
    }
    return this;
  }

  @Override
  public void end() {