20

I wrote a servlet to handle the exceptions occurring in my web app and mapped them in web.xml

    <error-page>
      <exception-type>java.lang.Exception</exception-type>
      <location>/exceptionHandler</location>
    </error-page>

Here is what I have done in the Exception Handling servlet service method:

@Override
    protected void service(HttpServletRequest req, HttpServletResponse arg1)
            throws ServletException, IOException {
         Object attribute = req.getAttribute("javax.servlet.error.exception");
         if(attribute instanceof  SocketException){
            // don't do anything 
         }else{
          super.service(req, arg1);
         }
    }.

Problem:

The above approach is not working and the stack trace is printing to the console. This occurs when the user requests something and then closes their browser.

Question:

How do I stop printing the stacktrace to the JBoss console whenever a SocketException occurs?

Reason for doing this:

I want to avoid seeing all of the log's SocketExceptions at the end of th day because I can't do anything with that information.

michaelsnowden
  • 6,031
  • 2
  • 38
  • 83
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • 1
    If you know why the exception is occurring, then shouldn't you be handling that exception according to your requirements *when* it occurs? A filter like you suggest would filter all occurrences of the exception, even when they occur for reasons other than those you expect. – Taylor Hx Oct 30 '13 at 06:33
  • 1
    @Daemon There is no way to handle that. I given the reason :). All I want to do is just escape that stacktrace in server logs. – Suresh Atta Oct 30 '13 at 06:37
  • Ahh, I see. The exception is being held as an attribute of the `ServletRequest`, and isn't caught until request is processed. – Taylor Hx Oct 30 '13 at 06:48
  • I am not sure why you had to override the `service()`. I think this could have been done in `doGet` and `doPost` methods. Also how do your `doGet` and `doPost` methods look like. One more thing, why aren't you calling these two methods inside your service method? – me_digvijay Oct 30 '13 at 15:39
  • Are you sure that using 'java.lang.Exception' for specifying exception-type works? Try using java.lang.Throwable, which should be used to specifying generic error handler. java.lang.Throwable As you want to handle SocketException, you might want to use something like this: java.net.SocketException – Sudarshan_SMD Nov 01 '13 at 10:40
  • Could you attach the stack trace to your question? thanks. – ericson Nov 04 '13 at 15:16
  • @sᴜʀᴇsʜᴀᴛᴛᴀ As you are talking about jboss, what about add an appender to your `jboss-log4j.xml`? At $JBOSS_HOME/server/{profile}/default/conf – Jorge Campos Nov 04 '13 at 18:17
  • Adding to previous comment by @JorgeCampos in log4j.xml check the package (Logger class) that logs the error and increase its Level Threshold to FATAL. This might work. Another option I would explore is to override the default HTTP connector of Tomcat and suppress/log `SocketException` at debug Level. – Bimalesh Jha Mar 06 '14 at 15:56
  • Please share the stack trace logged for `ScoketException` so that I can try to figure it out. – Braj Mar 11 '14 at 06:57
  • Have you tries Jboss custom logging handler? Have a look at my answer and let me know if am I wrong as per your requirement. – Braj Mar 11 '14 at 17:06

7 Answers7

7

Here is what I done so war as work around.

Added one filter and hijack all the request and response.Catch the exception and check the type.

/**
 * Hijacks all the http request and response here.
 * Catch the SocketException and do not print 
 * If other exceptions print to console
 * date : 9-18-2013
 * 
 * @author Suresh Atta
 *
 */
public class ExceptionHandler implements Filter {

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {
        try{
        arg2.doFilter(arg0, arg1);
        }catch(SocketException e ){
           // Please don't print this to log.    
        }
    }


}

And in web.xml ,filter mapping

<filter>
        <filter-name>ExceptionHandler</filter-name>
        <filter-class>com.nextenders.server.ExceptionHandler</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ExceptionHandler</filter-name>
        <dispatcher>  REQUEST   </dispatcher>
        <url-pattern> /*</url-pattern>
    </filter-mapping>  

I'm not marking this as answer,since I'm not sure this is a standard way or not.Just a work around.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • 1
    I would do it differently. There is no reason to catch Exception in your code. I would just catch `SocketException` or at least rethrow the wrongly catched exceptions to allow other filters to react properly on those exceptions, not just swalling it and printing to the console. – Matthias Oct 30 '13 at 06:32
  • @Matthias Thanks for that spot. Editted with new code. This code posted long back and recently I changed the logic. Catching socket exception and doing nothing there.There is no way to handle that. I given the reason :). All I want to do is just escape that stack trace in server logs. – Suresh Atta Oct 30 '13 at 06:44
  • 3
    Yeah, I understand what you want to achieve and it certainly prevents the log from being scattered with misleading exceptions. The only thing you could do to "handle the SocketException" is to write a small message to your normal log (maybe on debug/info level) that the user aborted the request. This makes it easier to track sessions if you have some issues in production and have to follow a log file. I have that rule to log everything entering or leaving my application so I can track things. – Matthias Oct 30 '13 at 06:50
  • @Matthias yes, yes. Now doing the same. Inside that catch block there is a little business logic to track things :) – Suresh Atta Oct 30 '13 at 07:09
  • 1
    Wonderful, then I believe your workaround is actually a neat solution. – Matthias Oct 30 '13 at 07:15
7

Instead of adding java.lang.Exception in your web.xml why won't you just try to add socket exception in web.xml itself like below

<error-page>
  <exception-type>java.net.SocketException</exception-type>
  <location>/exceptionHandler</location>
</error-page>

and just do nothing in your servlet Or instead add a empty jsp file like

<error-page>
  <exception-type>java.net.SocketException</exception-type>
  <location>/error.jsp</location>
</error-page>
Prakash
  • 693
  • 5
  • 17
3

Use Jboss Custom Logging Handler to solve this problem.

If you don't want to log any SocketException exception stack trace then just skip it while loggin into a file.

Steps to follow:

  • A custom handler must inherit java.util.logging.Handler

Here is the code:

package com.custom.jboss.logging;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

public class SocketExceptionCustomLoggingHandler extends Handler {

    private String logFile;
    public BufferedWriter out = null;

    public SocketExceptionCustomLoggingHandler() {
        super();
        logFile = "";
    }

    @Override
    public void publish(LogRecord record) {
        if (!initialize()) {
            return;
        }
        if (isLoggable(record)) {
            process(record);
        }
    }

    private synchronized boolean initialize() {
        if (out == null && logFile != null && !logFile.equals("")) {
            FileWriter fstream = null;
            try {
                fstream = new FileWriter(logFile, true);
                out = new BufferedWriter(fstream);
            } catch (IOException e) {
                reportError(e.getMessage(), e, ErrorManager.OPEN_FAILURE);
            }
            logToFile("Log file initialized. Logging to: " + logFile);
        }
        return true;
    }

    private void process(LogRecord logRecord) {

        String log = getFormatter().format(logRecord);
        if (log.indexOf("java.net.SocketException") == -1) {
            logToFile(log);
        }
    }

    private void logToFile(String text) {
        try {
            if (out != null) {
                out.write((new Date()).toString() + "\t" + text + "\n");
                out.flush();
            }
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.WRITE_FAILURE);
        }

    }

    @Override
    public void flush() {
        try {
            if (out != null) {
                out.flush();
            }
        } catch (IOException e) {
            reportError(e.getMessage(), e, ErrorManager.FLUSH_FAILURE);
        }
    }

    @Override
    public void close() {
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                reportError(e.getMessage(), e, ErrorManager.CLOSE_FAILURE);
            }

        }
    }

    public void setLogFile(String logFile) {
        this.logFile = logFile;
    }

}
  • The file is then packaged into a jar and placed in the modules directory.

    i.e. Jboss-7.1.1/modules/com/custom/jboss/loggers/main together with a module.xml file. The contents of the module.xml should look like this.

    <?xml version="1.0" encoding="UTF-8"?>   
    <module xmlns="urn:jboss:module:1.0" name="com.custom.jboss.loggers">  
         <resources>      
               <resource-root path="SocketExceptionHandler.jar"/>  
              <!-- Insert resources here -->   
         </resources>    
         <dependencies>      
              <module name="org.jboss.logging"/>  
              <module name="javax.api"/>   
         </dependencies>  
    </module>  
    
  • Then modify the standalone.xml to support logging to the custom logger

    <subsystem xmlns="urn:jboss:domain:logging:1.1">
        ...
        <custom-handler name="SocketExceptionAppender" class="com.custom.jboss.logging.SocketExceptionCustomLoggingHandler" module="com.custom.jboss.loggers">
            <level name="DEBUG"/>
            <formatter>
                <pattern-formatter pattern="%d{HH:mm:ss,SSS} %-5p [%c] (%t) %s%E%n"/>
            </formatter>
            <properties>
                <property name="logFile" value="d:\\temp\\logfile.txt"/>
            </properties>
        </custom-handler>
        ...
        <root-logger>
            <level name="INFO"/>
            <handlers>
                <handler name="SocketExceptionAppender"/>                    
            </handlers>
        </root-logger>
    </subsystem>
    
  • Add more handler in root-logger if needed such as FILE, CONSOLE etc.

  • Now all the logs will be logged in your custom log file via this custom handler where we have skipped SocketException
  • We can make this class more generic passing properties from standalone.xml such as used to pass log file path.

Please let me know if there is any issue.

Braj
  • 46,415
  • 5
  • 60
  • 76
2

You probably will have to override fillInStackTrade method

public static class CustomException extends Exception {
@Override
public Throwable fillInStackTrace() {
    return null;
}       

}

MansoorShaikh
  • 913
  • 1
  • 6
  • 19
2

As I understand it, exceptions are logged to the console when it is not caught before reaching the container. As such using a filter to catch unhandled exceptions makes sense.

Struts2 also has an exception 'interceptor' as its last interceptor, by default. See defaultStack. We need do override this interceptor if we need custom exception handling.

The only thing I would do additionally would be to log the exceptions (atleast to an errors-ignore.txt file) rather than completely skipping them.

Ravindra HV
  • 2,558
  • 1
  • 17
  • 26
1

Another funky idea: you could create exception handler

class SocketExceptionSwallower implements Thread.UncaughtExceptionHandler {
        public void uncaughtException(Thread t, Throwable e) {
            if (e instanceof SocketException) {
                // swallow
            } else {
                e.printStackTrace();
            }
        }
    }

and registered with

Thread.setDefaultUncaughtExceptionHandler(new SocketExceptionSwallower());

or

Thread.currentThread().setUncaughtExceptionHandler(new SocketExceptionSwallower());

Simple, no overhead of another filter in chain, but it messes with threads and will probably break something in Java EE environment )
Might be useful in testing/experimenting or if you fully control threads in your own code

Yuri
  • 1,695
  • 1
  • 13
  • 23
1

You can use the Logger. For this you need log4j library and all the desired behavior and exceptions are written to log file. For this you need to give the log file path

oxfn
  • 6,590
  • 2
  • 26
  • 34
UmeshA
  • 11
  • 1
  • Can you provide an example, how `log4j` can prevent output of unhandled exception stack trace? – oxfn Mar 14 '14 at 05:51