Java 如何停止在控制台上打印异常堆栈跟踪?

Java 如何停止在控制台上打印异常堆栈跟踪?,java,tomcat,servlets,web.xml,socketexception,Java,Tomcat,Servlets,Web.xml,Socketexception,我编写了一个servlet来处理web应用程序中出现的异常,并将它们映射到web.xml中 <error-page> <exception-type>java.lang.Exception</exception-type> <location>/exceptionHandler</location> </error-page> 问题: 上述方法不起作用,堆栈跟踪正在打印到控制台。当用

我编写了一个servlet来处理web应用程序中出现的异常,并将它们映射到web.xml中

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

上述方法不起作用,堆栈跟踪正在打印到控制台。当用户请求某些内容,然后关闭浏览器时,就会发生这种情况

问题:

当出现
SocketException
时,如何停止将stacktrace打印到JBoss控制台

这样做的原因:


我想避免在第天结束时看到所有日志的
SocketException
s,因为我无法处理这些信息。

您可能必须重写fillInStackTrade方法

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

}

以下是我所做的工作,以避免战争

添加一个筛选器并劫持所有请求和响应。捕获异常并检查类型

/**
 * 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.    
        }
    }


}
web.xml
中,过滤映射

<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>  

例外处理程序
com.nextenders.server.ExceptionHandler
例外处理程序
要求
/*

我不会将此标记为答案,因为我不确定这是否是一种标准方法。这只是一种解决方法。

据我所知,在到达容器之前未捕获异常时,会将异常记录到控制台。因此,使用过滤器捕获未处理的异常是有意义的

默认情况下,Struts2还有一个异常“拦截器”作为其最后一个拦截器。看见如果我们需要自定义异常处理,我们需要重写这个拦截器


另外,我要做的唯一一件事是记录异常(至少记录到errors-ignore.txt文件),而不是完全跳过它们。

而不是在web.xml中添加
java.lang.Exception
,为什么不尝试在web.xml中添加套接字异常,如下所示

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

java.net.SocketException
/例外处理程序
在servlet中什么也不做 改为添加一个空jsp文件,如

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

java.net.SocketException
/error.jsp

使用Jboss自定义日志处理程序来解决此问题

如果您不想记录任何
SocketException
异常堆栈跟踪,那么只需在登录到文件时跳过它即可

应采取的步骤:

  • 自定义处理程序必须继承java.util.logging.handler
代码如下:

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;
    }

}
  • 然后将该文件打包到一个jar中并放在modules目录中

    i、 e.
    Jboss-7.1.1/modules/com/custom/Jboss/loggers/main
    以及module.xml文件。module.xml的内容应该如下所示

    <?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>  
    
    
    
  • 然后修改standalone.xml以支持记录到自定义记录器

    <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>
    
    
    ...
    ...
    
  • 如果需要,在根记录器中添加更多处理程序,如文件、控制台等

  • 现在,所有日志都将通过这个自定义处理程序记录到您的自定义日志文件中,我们跳过了
    SocketException
  • 我们可以使这个类从standalone.xml(例如用于传递日志文件路径)中传递更通用的属性

如果有任何问题,请告诉我。

另一个有趣的想法:您可以创建异常处理程序

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

Thread.setDefaultUncaughtExceptionHandler(new SocketExceptionSwallower());

Thread.currentThread().setUncaughtExceptionHandler(new SocketExceptionSwallower());
简单,没有链中另一个过滤器的开销,但它会弄乱线程,可能会破坏Java EE环境中的某些东西)

在测试/实验中可能很有用,或者如果您在自己的代码中完全控制线程

,则可以使用
记录器
。为此,您需要
log4j
库,所有需要的行为和异常都会写入日志文件。为此,您需要提供日志文件路径

来编写此文件,我需要获得对http响应的控制权。这阻止了我这样做。我会以不同的方式进行。没有理由捕捉代码中的异常。我只想捕获
SocketException
,或者至少重新捕获错误捕获的异常,以允许其他过滤器对这些异常做出正确反应,而不仅仅是将其清洗并打印到控制台。@Matthias感谢您的帮助。用新代码编辑。这段代码很早以前就发布了,最近我改变了逻辑。捕获套接字异常并在那里什么也不做。没有办法处理它。我给出了理由:)。我所要做的就是避开服务器日志中的堆栈跟踪。是的,我理解您想要实现的目标,这当然可以防止日志因错误的异常而分散。“处理SocketException”所能做的唯一一件事就是在普通日志(可能在调试/信息级别)中写入一条小消息,说明用户中止了请求。如果您在生产过程中遇到一些问题,并且必须遵循日志文件,则可以更轻松地跟踪会话。我有一个规则,记录所有进入或离开我的应用程序的事情,这样我就可以跟踪事情了。@Matthias是的,是的。现在我也在做同样的事情。在catch块内部有一个跟踪事物的小业务逻辑:)太好了,那么我相信您的解决方案实际上是一个整洁的解决方案。如果您知道异常发生的原因,那么您不应该在异常发生时根据您的需求处理该异常吗?像您建议的过滤器会过滤所有出现的异常,即使这些异常是由于您预期以外的原因发生的。@Daemon无法处理。我给出了理由:)。我所要做的就是在服务器日志中转义stacktrace。啊,我明白了。异常作为
ServletRequest
的一个属性保留,在处理请求之前不会被捕获。我不确定您为什么必须重写
服务()。我不能
Thread.currentThread().setUncaughtExceptionHandler(new SocketExceptionSwallower());