DefaultErrorHandler doesn't log not retryable exceptions - spring-kafka

Not retryable exceptions are not logged in DefaultErrorHandler when used with DeadLetterPublishingRecoverer.
#Bean
public CommonErrorHandler consumerErrorHandler(KafkaTemplate<String, KafkaMessage> kafkaTemplate) {
var errorHandler = new DefaultErrorHandler(new DeadLetterPublishingRecoverer(kafkaTemplate), kafkaConsumerRetryProperties.getBackoffPolicy());
errorHandler.addNotRetryableExceptions(NullPointerException.class);
return errorHandler;
}
In this case NullPointerException is not logged whatsoever when thrown in method annotated with #KafkaListener

Feel free to open an issue on GitHub. In the meantime, you could subclass the DLPR and log the exception in accept() before calling super.accept().

Related

Spring Boot ErrorPageFilter block the custom exception handler with #ExceptionHandler

My web app constructed with SpringBoot 2.0.0.M3 and java8, deploy on outer tomcat/8.0.24 war.
My Exception handler:
#ControllerAdvice(annotations = RestController.class)
public class GlobalExceptionHandler extends
ResponseEntityExceptionHandler {
#ExceptionHandler(MyCustomException.class)
public ResponseEntity<String> handlerMyException(
MyCustomException rae) {
String msg = "MyCustomException";
return new ResponseEntity<>(msg ,
HttpStatus.OK);
}
}
I trow a MyCustomException in my Controller but it wasn't handled by handlerMyException() method:
ERROR 1 --- [ajp-nio-8009-exec-372] o.s.b.w.servlet.support.ErrorPageFilter : Forwarding to error page from request [/api/test] due to exception
Then I disable the ErrorPageFilter by:
setRegisterErrorPageFilter(false);
this time no error log occurred, but handlerMyException() still not triggered. Is anyone know this? TIA!

Flink Retrofit not Serializable Exception

I have a Flink Job reading events from a Kafka queue then calling another service if certain conditions are met.
I wanted to use Retrofit2 to call the REST endpoint of that service but I get a is not Serializable Exception. I have several Flat Maps connected to each other (in series) then calling the service happens in the last FlatMap. The exception I get:
Exception in thread "main"
org.apache.flink.api.common.InvalidProgramException: The
implementation of the RichFlatMapFunction is not serializable. The
object probably contains or references non serializable fields.
...
Caused by: java.io.NotSerializableException: retrofit2.Retrofit$1
...
The way I am initializing retrofit:
RetrofitClient.getClient(BASE_URL).create(NotificationService.class);
And the NotificationService interface
public interface NotificationService {
#PUT("/test")
Call<String> putNotification(#Body Notification notification);
}
The RetrofitClient class
public class RetrofitClient {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
if (retrofit == null) {
retrofit = new Retrofit.Builder().baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
Put your Notification class code for more details, but looks like this answer helps
java.io.NotSerializableException with "$1" after class

Can a generic #ExceptionHandler and DefaultHandlerExceptionResolver play nice?

I'd like to implement an #ExceptionHandler that prevents all uncaught exceptions from getting to the client. Something like this...
#ControllerAdvice
public class ExceptionHandlingControllerAdvice {
private static final Logger logger = getLogger(ExceptionHandlingControllerAdvice.class);
#ExceptionHandler(Exception.class)
#ResponseStatus(value = INTERNAL_SERVER_ERROR)
public void handleAnyUncaughtException(Exception e) {
logger.error("This uncaught exception is being blocked from reaching the client.", e);
}
}
But this is getting in the way of the exception handling performed out of the box by DefaultHandlerExceptionResolver, e.g. to throw 4xx errors on failed #RequestBody validations checked with #Valid. It seems like #ExceptionHandler is taking precedence and returning 500 before the DHER can try to return a 4xx.
Is there a way to block uncaught exceptions from getting to the client, but still let the DefaultHandlerExceptionResolver do its job?
I found a solution. I was writing an #ExceptionHandler that explicitly handles all the standard Spring MVC exceptions, checked the manual for the list, and ran across the ResponseEntityExceptionHandler base class.
Extending that base class in the #ControllerAdvice adds an #ExceptionHandler for the standard exceptions with the crucial difference that you don't have to maintain the list should those exceptions change. The #ControllerAdvice now looks like this.
#ControllerAdvice
public class ExceptionHandlingControllerAdvice extends ResponseEntityExceptionHandler {
private static final Logger logger = getLogger(ExceptionHandlingControllerAdvice.class);
#ExceptionHandler(Exception.class)
#ResponseStatus(value = INTERNAL_SERVER_ERROR)
public void handleAnyUncaughtException(Exception e) {
logger.error("This uncaught exception is being blocked from reaching the client.", e);
}
}

SignalR, Owin and exception handling

I've developed a sample SignalR application based on ASP.NET 4.5 & Owin, and I've hosted that app on IIS 7.5.
Everything is working fine, but how can I handle exceptions in Owin?
Consider the following code:
[HubName("SampleHub")]
public class SampleHub : Hub
{
public SampleHub()
{
throw new InvalidOperationException("?!");
}
}
This exception won't call Application_Error (and this is my problem).
Where can I get all exceptions from Owin for logging and debugging purposes similarly to Application_Error?
I'm not interested in something like this:
app.UseErrorPage(new ErrorPageOptions()
{
ShowCookies = true,
ShowEnvironment = true,
ShowExceptionDetails = true,
ShowHeaders = true,
ShowQuery = true,
ShowSourceCode = true
});
This is totally useless for advanced scenarios, something like ASP.NET Web API and ASP.NET MVC.
Action filters with OnException method for override purposes is much better.
If you want exception handling specifically for SignalR Hubs, OWIN middleware is not the way to go.
To illustrate just one reason why, suppose that SignalR is using its WebSocket transport when an exception is thrown from inside a Hub method. In this case, SignalR will not close the WebSocket connection. Instead SignalR will write a JSON encoded message directly to the socket to indicate to the client that an exception was thrown. There is no easy way using OWIN middleware to trigger any sort of event when this happens outside of possibly wrapping the entire OWIN WebSocket Extension which I would strongly advise against.
Fortunately SignalR provides its own Hub Pipeline which is perfectly suited for your scenario.
using System;
using System.Diagnostics;
using Microsoft.AspNet.SignalR.Hubs;
public class MyErrorModule : HubPipelineModule
{
protected override void OnIncomingError(ExceptionContext exceptionContext, IHubIncomingInvokerContext invokerContext)
{
MethodDescriptor method = invokerContext.MethodDescriptor;
Debug.WriteLine("{0}.{1}({2}) threw the following uncaught exception: {3}",
method.Hub.Name,
method.Name,
String.Join(", ", invokerContext.Args),
exceptionContext.Error);
}
}
You can use the ExceptionContext for more than just logging. For example you can set ExceptionContext.Error to a different exception which will change the exception the client receives.
You can even suppress the exception by setting ExceptionContext.Error to null or by setting ExceptonContext.Result. If you do this, It will appear to the client that the Hub method returned the value you found in ExceptonContext.Result instead of throwing.
A while back a wrote another SO answer about how you can call a single client callback for every exception thrown by a Hub method: SignalR exception logging?
There is also MSDN documentation for HubPipelineModules: http://msdn.microsoft.com/en-us/library/microsoft.aspnet.signalr.hubs.hubpipelinemodule(v=vs.118).aspx
The answer by #halter73 is great for errors thrown inside hubs, but it doesn't catch errors thrown during their creation.
I was getting the exception:
System.InvalidOperationException: 'foobarhub' Hub could not be resolved.
The server was returning an HTML page for this exception, but I needed it in JSON format for better integration with my Angular app, so based on this answer I implemented an OwinMiddleware to catch exceptions and change the output format. You could use this for logging errors instead.
public class GlobalExceptionMiddleware : OwinMiddleware
{
public GlobalExceptionMiddleware(OwinMiddleware next)
: base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
try
{
await Next.Invoke(context);
}
catch (Exception ex)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = 500;
await context.Response.WriteAsync(JsonConvert.SerializeObject(ex));
}
}
}
Add the registration in OwinStartup.cs, just remember to place it before the MapSignalR method call:
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.Use<GlobalExceptionMiddleware>(); // must come before MapSignalR()
app.MapSignalR();
}
}

Returning an error and message from a Spring controller or service

I'm migrating some servlets over to the Spring framework, using Spring MVC. Currently in each servlet we authenticate the user and if the authentication fails we do this:
if (authfailed)
{
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"You are not authorized.");
return;
}
On the front end is a YUI-based application, and when an error status is returned the "failure" callback displays a dialog with the error message given above.
I know in my controller I can get the response object and call sendError, but is that the best way to handle this? sendError also throws an IOException so I'd have to catch that - a bit of annoying code to insert in every method of every controller.
I have the same problem handling exceptions - the servlets have try-catch blocks that call sendError in the catch method. I know I can mark my exception handlers with
#ExceptionHandler
#ResponseStatus(value = HttpStatus.NOT_FOUND)
but doesn't the exception handling class need to be in each controller class?
Finally, if the exception happens in a service called from a controller, does the exception bubble up to the controller or should I handle the exception in the service (thus pushing these exception handling issues into the service layer)?
This seems more difficult than it should be, but as with many things in Spring it's likely I don't understand what's going on. All I want to do is to send an error status and message back in the response!
Thanks,
Paul
It looks like you have the most of the answers in your question itself :)
To reiterate,
Have the controller like this
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request) throws NotFoundException {
String id = request.getParameter("id");
if (id == null)
throw new NotFoundException("Id not found in the request");
return "success";
}
Declare the exception class in NotFoundException.java,
#ResponseStatus(value=HttpStatus.NOT_FOUND, reason="Id Not Found")
public class NotFoundException extends Exception {
public NotFoundException(String msg) {
super(msg);
}
}
This exception class need not be every controller class. Declare it as public class and import it in every required controller.
This is one way of doing it. If you like the non-spring style, declare HttpServletResponse in every controller arguments and do
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, HttpServletResponse response) {
...
try {
response.sendError(..)
catch(..) {}
}
Or you can use views to show error message,
#RequestMapping("/test")
public String verifyAuth(HttpServletRequest request, Map<String, Object> map){
String id = request.getParameter("id");
if (id == null) {
map.put("status", HttpStatus.NOTFOUND);
map.put("reason", "Id Not Found");
return "error"
}
return "success";
}
Make sure your viewResolver is configured correctly and in the error.jsp to get the error string, you could say.
<body>
${status} ${reason}
</body>
Define error.jsp with nice css for all kind of errors you would expect.
These are not the only ways. With spring you have freedom to do anything. I have seen few ppl rendering json object for error message.
To answer your another question of if the error happens in the service called by the controller is depend on your scenario. For example you are trying to read the user store, if the user store not available error happens, I would handle there itself to read from another replica user store if one available and If I found user does not exist I would leave the exception to the controller to throw.

Resources