Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Listener exceptions not saved to the observation #3049

Closed
foaw opened this issue Feb 19, 2024 · 1 comment · Fixed by #3080
Closed

Listener exceptions not saved to the observation #3049

foaw opened this issue Feb 19, 2024 · 1 comment · Fixed by #3080

Comments

@foaw
Copy link

foaw commented Feb 19, 2024

In what version(s) of Spring for Apache Kafka are you seeing this issue?

  • org.springframework.kafka:spring-kafka:3.1.1
  • org.apache.kafka:kafka-clients:3.6.1

Describe the bug

When an exception is thrown from a listener, by default the exception is not saved in the current listener observation.

Observation observation = KafkaListenerObservation.LISTENER_OBSERVATION.observation(
this.containerProperties.getObservationConvention(),
DefaultKafkaListenerObservationConvention.INSTANCE,
() -> new KafkaRecordReceiverContext(cRecord, getListenerId(), this::clusterId),
this.observationRegistry);
return observation.observe(() -> {
try {
invokeOnMessage(cRecord);
successTimer(sample, cRecord);
recordInterceptAfter(cRecord, null);
}
catch (RuntimeException e) {
failureTimer(sample, cRecord);
recordInterceptAfter(cRecord, e);
if (this.commonErrorHandler == null) {
throw e;
}
try {
invokeErrorHandler(cRecord, iterator, e);
commitOffsetsIfNeededAfterHandlingError(cRecord);
}
catch (KafkaException ke) {
ke.selfLog(ERROR_HANDLER_THREW_AN_EXCEPTION, this.logger);
return ke;
}
catch (RuntimeException ee) {
this.logger.error(ee, ERROR_HANDLER_THREW_AN_EXCEPTION);
return ee;
}
catch (Error er) { // NOSONAR
this.logger.error(er, "Error handler threw an error");
throw er;
}
}
return null;
});

Observation#observe would do it on its own, but then the provided supplier has to re-throw the exception rather than just return it, which it probably does for ListenerConsumer#invokeInTransaction.

To Reproduce

  1. Make & register a message listener.
  2. Send a message to the listener topic. (For example, java.lang.NullPointerException.)
  3. Throw an exception from the listener.

Expected behavior

The error handler is invoked and all, but on top of that, the (original) exception is embedded into the observation, allowing downstream tracing code to handle it.

Sample

For simplicity's sake, I will only leave the listener code here. In the configuration, there is only a consumer group identifier. Let me know if I should make this into a repository.

@KafkaListener(topics = "error")
public void onErrorMessage(@Payload String payload) throws Throwable {
    Class<?> errorClass = Class.forName(payload);
    throw (Throwable) errorClass.getDeclaredConstructor().newInstance();
}
@tbarabanov
Copy link

tbarabanov commented Feb 25, 2024

Faced with the same issue in spring-kafka:jar:3.0.10. It seems that observation.observe will add error to the context only if the code it invokes will raise an exception. But this won't happen, because exception will be just returned from method call.

By the way, micrometer meters are updated on each listener invocation retry.
I wouldn't mind if observation worked that way too.

@sobychacko sobychacko added this to the 3.2.0-M2 milestone Feb 26, 2024
Wzy19930507 added a commit to Wzy19930507/spring-kafka that referenced this issue Feb 28, 2024
* Embedded the (original) exception into the observation, allowing downstream tracing code to handle it.
* Add unit test for observation Error and RuntimeException.

Resolves spring-projects#3049
artembilan pushed a commit that referenced this issue Feb 29, 2024
Fixes: #3049

Listener exceptions are not saved to the observation.

* Embedded the (original) exception into the observation, allowing downstream tracing code to handle it.
* Add unit test for observation `Error` and `RuntimeException`.
* Unify the `runtimeExceptionTemplate` and `errorTemplate` into a `throwableTemplate`.

**Auto-cherry-pick to `3.1.x` & `3.0.x`**
spring-builds pushed a commit that referenced this issue Feb 29, 2024
Fixes: #3049

Listener exceptions are not saved to the observation.

* Embedded the (original) exception into the observation, allowing downstream tracing code to handle it.
* Add unit test for observation `Error` and `RuntimeException`.
* Unify the `runtimeExceptionTemplate` and `errorTemplate` into a `throwableTemplate`.

(cherry picked from commit 61016db)
spring-builds pushed a commit that referenced this issue Feb 29, 2024
Fixes: #3049

Listener exceptions are not saved to the observation.

* Embedded the (original) exception into the observation, allowing downstream tracing code to handle it.
* Add unit test for observation `Error` and `RuntimeException`.
* Unify the `runtimeExceptionTemplate` and `errorTemplate` into a `throwableTemplate`.

(cherry picked from commit 61016db)
artembilan added a commit that referenced this issue Mar 22, 2024
Fixes: #3151

After fixing #3049 we are missing an `ErrorHandler` part within an observation.
This even cause a retryable topic logic ot be out of an observation scope.

* Restore the previous behavior and add `observation.error(e)` when it is not re-thrown in case of `this.commonErrorHandler` presence

**Auto-cherry-pick to `3.1.x` & `3.0.x`**
spring-builds pushed a commit that referenced this issue Mar 22, 2024
Fixes: #3151

After fixing #3049 we are missing an `ErrorHandler` part within an observation.
This even cause a retryable topic logic ot be out of an observation scope.

* Restore the previous behavior and add `observation.error(e)` when it is not re-thrown in case of `this.commonErrorHandler` presence

(cherry picked from commit c24575c)
spring-builds pushed a commit that referenced this issue Mar 22, 2024
Fixes: #3151

After fixing #3049 we are missing an `ErrorHandler` part within an observation.
This even cause a retryable topic logic ot be out of an observation scope.

* Restore the previous behavior and add `observation.error(e)` when it is not re-thrown in case of `this.commonErrorHandler` presence

(cherry picked from commit c24575c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants