I'm writing a stand alone application, that has to start up and be left running unattended for long periods of time. Rather than have exceptions bring it to a halt, it needs to log the exception with enough information for the support people to have an idea what happened, and carry on.
As a result each exception is wrapped in a runtime exception, then thrown to be logged by a different part of the application. I'm using aop:config tags to create an aspect to log the runtime exceptions thrown by the rest of the application. The exception would then carry on up the call stack to an UncaughtExceptionHandler to end the exception silently.
However, the same exception is being caught repeatedly, and logged (each exception is written by a separate thread, and goes to a separate log file). In the debugger, both exceptions have the same ID.
My applicationContext is basic for this :
<aop:config>
<aop:aspect ref="exceptionLoggingAspect">
<aop:after-throwing method="logException"
pointcut="execution(* *.*(..))" throwing="exception" />
</aop:aspect>
</aop:config>
The UncaughtExceptionHandler is equally basic, at least till I get it working :
private void setUncaughtExceptionHandler()
{
final Handler handler = new Handler();
Thread.setDefaultUncaughtExceptionHandler(handler);
}
class Handler implements Thread.UncaughtExceptionHandler
{
#Override
public void uncaughtException(Thread t, Throwable e)
{
System.out.println("Throwable: " + e.getMessage());
System.out.println(t.toString());
}
}
I have experimented by restricting the pointcut to a single package, and throwing an exception from that package (not the package the exception logging is in), but it is still logged twice.
Is there something fundamentally wrong with this idea ? Advice appreciated.
Related
My app is a Spring Boot web application. I'm having a unique problem catching my exception with my ExceptionHandler - I think it is because the exception is being thrown and rethrown multiple times in my app flow.
Here is a high level description of the problem:
I throw ExceptionType1 in my service.
My ExceptionType1 exception is caught by my ErrorController class's error() method
#Override
#RequestMapping
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
boolean isErr = (boolean) request.getAttribute("filter.error");
if (isErr) {
//the error was thrown by cta filter, throw ExceptionType2
throw new ExceptionType2(errorMsg, errorCode);
} else {
//handle other errors
I catch the error, convert the ExceptionType1 exception to ExceptionType2 exception and rethrow it as ExceptionType2
The ExceptionType2 exception thrown above is caught by my ExceptionHandler class
#Component
#ControllerAdvice
public class MyExceptionHandler {
#ExceptionHandler({ExceptionType2.class})
public final String handleExceptionType2(ExceptionType2 e) throws ExceptionType3 {
throw new ExceptionType3(errorMsg, errorCode);
}
The ExceptionHandler above has an #ExceptionHandler method that catches the ExceptionType2 error thrown in the previous step, converts this exception to ExceptionType3 and rethrows it.
5. Here's my problem. There is yet another ExceptionHandler class that is supposed to catch ExceptionType3 errors - but it is not working. I put a breakpoint in my #ExceptionHandler method for ExceptionType3 and it is never hit
TLDR -- I basically catch an exception in my code - then it is
converted to another exception type and
rethrown as the new exception type 3 times in my code.
It works the first 2 times but the last time I try to convert the exception and rethrow it as ExceptionType3 - it is not caught by my ExceptionHandler class for ExceptionType3.
My theory right now is - I have converted exception type and rethrown the exception too many times. Is there some limitation on this in Spring? The reason I think this is - if I create and throw ExceptionType3 at any point in the above steps before step 5 - it is able to be caught by the appropriate ExceptionHandler class.
Any advice on this would be appreciated.
I believe that Spring does not allow handling of exceptions re-thrown from other exception handlers. Exception handler is supposed to be a final point where exception should be converted to HTTP response or just logged.
One of the way (maybe a little dirty) to solve your issue is to call handler for ExceptionType3 manually.
I have a somewhat linear job set up in Spring Batch that consists of several steps. If, at any point, a single step fails, the job should fail.
The steps consist of a number of tasklets followed by a chunk-based step. I.e.:
Step 1
Tasklet 1
Step 2
Tasklet 2
Step 3
Reader
Processor
Writer
If something goes wrong, the obvious thing to do is throw an Exception. Spring Batch will handle this and log everything. This behaviour, particularly printing the stack trace, is undesirable, and it would be better if the Job could be ended gracefully with the Status set to FAILED.
The Tasklets currently set the ExitStatus directly on the StepContribution. They are also built using a flow (which wasn't ideal, but the steps continue unhindered otherwise). The issues can then be handled directly in the Tasklet.
However, we have no access to the StepContribution in the chunk-based approach. We only have the StepExecution. Using setExitStatus does nothing here.
We are using the builders (JobBuilerFactory and StepBuilderFactory), not the XML setups.
The potential solutions:
Tell or configure Batch how to handle exceptions (not to print a stack trace).
Catch the exception in a listener. Unfortunately, the exception has already been caught by Spring Batch by the time it gets to the #AfterStep.
Tell the step/job that we do not want to continue (e.g. setting a value in the execution context or an alternative for the StepContribution.
As far as I know, the only way to stop the job is to throw an exception. There was no other graceful way of telling Spring Batch "This job is done, it failed, go directly to Failed, do not pass GO, etc."
Although not a direct solution to the original problem, one can use the .exceptionHandler() of a StepBuilder to gain more control over the exceptions you throw, e.g. logging them.
public class LogAndRethrowExceptionHandler implements ExceptionHandler {
private static final Logger LOGGER = Logger.getLogger(...);
#Override
public void handleException(RepeatContext repeatContext, Throwable throwable) throws Throwable {
LOGGER.error(throwable.getMessage());
throw throwable;
}
}
This way you may, in theory, hide the stack traces produced by Spring Batch but still show the error messages.
I think you can explore below two options.
Option 1 : You Can use noSkip Exception.
This Explicitly prevent certain exceptions (and subclasses) from being skipped
Throw some specific Exception for which you want to fail the job.
This is how you can configure hat
stepBuilderFactory.get("myStep")
.<POJO, POJO> chunk(1000)
.reader(reader)
.processor(processor)
.writer(writer)
.faultTolerant()
.noSkip(YourCustomException.class)
.skip(Exception.class)
.skipLimit(100)
****Option 2** :** You can use set the exit status to FAILED for error flow in after step is completed
public class MyStepExecutionListener implements StepExecutionListener {
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
if(allIsGood()) //
{
return ExitStatus.COMPLETED;
}
else if (someExceptionOrErrorCase()){
return ExitStatus.FAILED;
}
}
}
Hope this helps
In my case I ended up adding conditions and throwing JobInterruptedException in both Reader and Processor
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobInterruptedException;
public class CustomReader implements ItemReader<String> {
#Override
public String read() throws Exception {
// ...
// if ("condition to stop job") {
throw new JobInterruptedException("Aborting Job", BatchStatus.ABANDONED);
// }
}
}
We have a typical Spring Boot Java application with Services, Rest Controllers and Repositories.
We use custom runtime exceptions in our services and controllers by re-throwing them from catch blocks and then handle them in a spring global exception handler (via #ControllerAdvice).
Usually, we use throw new SomeCustomException("Message"); construction, but it looks not so good to me as it's hard to see what exceptions are thrown throughout the code.
Thinking of how I could improve readability of the code, I came up with the idea of creating static final instances and then use them like throw new SOME_CUSTOM_EXCEPTION;
In this case, it is clear what exceptions class can throw and it is easy to check whether they are handled in the global exception handler.
I see some drawbacks with those constant exception instances though. First, what if need to pass an external exception into the custom exception, or there are multiple throws of the same class with different messages?
Another idea is to extract exception messages as constants. But again,sometimes we pass no messages.
Are there best practices of indicating what exceptions a class can throw or I am over-thinking and it is just fine to throw new?
If you wanted to improve readability, perhaps additional custom exceptions with more detailed names would be enough. Additionally you could have a default message constructor, and store other common message strings inside the exception class as static constants:
public class CustomException {
public static String ERROR_MESSAGE = "some error message";
public CustomException() {
super("Default message")
}
public CustomException(String message) {
super(message)
}
}
throw new CustomException(CustomException.ERROR_MESSAGE);
I wrote an #ExceptionHandler to send the exception in JSON for REST requests. However, due to the way Spring Security works, AccessDeniedExceptions must not be handled.
If I simply rethrow an AccessDeniedException in the handler, I get an ERROR level logging saying:
Failed to invoke #ExceptionHandler method: SomeMethod() throws java.lang.Exception
org.springframework.security.access.AccessDeniedException: Access is denied
...Stack...
I cannot safely disable ERROR level logging for the class logging it (ExceptionHandlerExceptionResolver), but having these stacktrace is quite confusing for operations people.
Is there anyway to make #ExceptionHandler not handle this specific exception?
I think you could just use global exception handler instead, so you don't manually handle this AccessDeniedExceptions,
this global exception will be thrown for every kinds of exceptions (except for the exception handlers that you handle manually):
#ControllerAdvice
public class GlobalHandler {
#ExceptionHandler(Exception.class)
public ModelAndView handleException() {
return new ModelAndView("errorGlobal");
}
}
I have heard that it is possible to log (or do something else) Exceptions with Spring in my web-App, so I don't have to manually insert in every "catch(){}" block the Log-function.
Does anyone have experience with Spring-overall-logging? I just want to get informed when an error appears
ExceptionHandler is the central point for handling unexpected Exceptions that are thrown during the Faces lifecycle. The ExceptionHandler must not be notified of any Exceptions that occur during application startup or shutdown.
See the specification prose document for the requirements for the default implementation. Exceptions may be passed to the ExceptionHandler in one of two ways:
1.)By ensuring that Exceptions are not caught, or are caught and re-thrown.
This approach allows the ExceptionHandler facility specified in section JSF.6.2 to operate on the Exception.
2.)By using the system event facility to publish an ExceptionQueuedEvent that wraps the Exception.
This approach requires manually publishing the ExceptionQueuedEvent, but allows more information about the Exception to be stored in the event. The following code is an example of how to do this.
Global Exception Handler – Exception Handling is a cross-cutting concern, it should be done for all the pointcuts in our application. We have already looked into Spring AOP and that’s why Spring provides #ControllerAdvice annotation that we can use with any class to define our global exception handler.
The handler methods in Global Controller Advice is same as Controller based exception handler methods and used when controller class is not able to handle the exception.
Sample Code
#ExceptionHandler(Exception.class)
public ModelAndView getExceptionPage(Exception e, HttpServletRequest request) {
request.setAttribute("errorMessageObject", e.toString());
return model;
}
** Here we can catch the base exception class Exception.class or any other exception class. Also we can throw and catch our own custom defines exception class.