【问题标题】:How to stop printing exception stack trace on Console?如何停止在控制台上打印异常堆栈跟踪?
【发布时间】:2013-09-21 20:47:04
【问题描述】:

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

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

这是我在异常处理 servlet service 方法中所做的:

@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);
         }
    }.

问题:

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

问题:

每当出现SocketException 时,如何停止将堆栈跟踪打印到 JBoss 控制台?

这样做的原因:

我想避免在一天结束时看到所有日志的SocketExceptions,因为我对这些信息无能为力。

【问题讨论】:

  • 如果您知道异常发生的原因,那么您不应该根据您的要求处理该异常何时它发生吗?像您建议的过滤器将过滤所有出现的异常,即使它们的发生是出于您预期之外的原因。
  • @Daemon 没有办法处理它。我给出了原因:)。我想做的只是逃避服务器日志中的堆栈跟踪。
  • 啊,我明白了。异常作为ServletRequest 的一个属性被保存,直到请求被处理后才会被捕获。
  • 我不确定您为什么必须覆盖 service()。我认为这可以在doGet 和doPost 方法中完成。此外,您的 doGet 和 doPost 方法看起来如何。还有一件事,你为什么不在你的服务方法中调用这两个方法?
  • 你确定使用'java.lang.Exception'来指定异常类型有效吗?尝试使用 java.lang.Throwable,它应该用于指定通用错误处理程序。 java.lang.Throwable 因为你想处理 SocketException,你可能想使用这样的东西:java.net.SocketException跨度>

标签: java tomcat servlets web.xml socketexception


【解决方案1】:

这就是我所做的,所以战争就像变通一样。

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

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

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

【讨论】:

  • 我会做不同的事情。没有理由在代码中捕获异常。我只会捕获SocketException 或至少重新抛出错误捕获的异常,以允许其他过滤器对这些异常做出正确反应,而不仅仅是将其吞噬并打印到控制台。
  • @Matthias 谢谢你的那个位置。用新代码编辑。这段代码很久以前就发布了,最近我改变了逻辑。捕获套接字异常并且在那里什么都不做。没有办法处理它。我给出了原因:)。我想做的只是逃避服务器日志中的堆栈跟踪。
  • 是的,我了解您想要实现的目标,它确实可以防止日志因误导性异常而分散。您唯一可以做的“处理 SocketException”就是在您的正常日志(可能在调试/信息级别)中写入一条用户中止请求的小消息。如果您在生产中遇到一些问题并且必须遵循日志文件,这使得跟踪会话变得更加容易。我有这个规则来记录进入或离开我的应用程序的所有内容,以便我可以跟踪。
  • @Matthias 是的,是的。现在也在做同样的事情。在那个 catch 块里面有一点业务逻辑来跟踪事情:)
  • 太好了,那么我相信您的解决方法实际上是一个很好的解决方案。
【解决方案2】:

与其在 web.xml 中添加 java.lang.Exception,不如尝试在 web.xml 本身中添加套接字异常,如下所示

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

在你的 servlet 中什么也不做 或者改为添加一个空的jsp文件,例如

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

【讨论】:

    【解决方案3】:

    使用Jboss Custom Logging Handler来解决这个问题。

    如果您不想记录任何 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 目录中。

      即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以支持记录到自定义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>
      
    • 如果需要,在 root-logger 中添加更多处理程序,例如 FILE、CONSOLE 等。

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

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

    【讨论】:

    • 感谢您的宝贵回复。会尽力回复您。
    【解决方案4】:

    您可能必须重写 fillInStackTrade 方法

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

    }

    【讨论】:

    • 要写这篇文章,我需要控制 http 响应。这阻止了我这样做。
    【解决方案5】:

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

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

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

    【讨论】:

      【解决方案6】:

      另一个时髦的想法:你可以创建异常处理程序

      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 环境中的某些东西)
      可能在测试/实验或您在自己的代码中完全控制线程时很有用

      【讨论】:

        【解决方案7】:

        您可以使用Logger。为此,您需要 log4j 库,并且所有所需的行为和异常都将写入日志文件。为此,您需要提供日志文件路径

        【讨论】:

        • 您能否举个例子,log4j 如何防止输出未处理的异常堆栈跟踪?
        猜你喜欢
        • 2014-08-06
        • 2015-06-07
        • 1970-01-01
        • 2012-03-03
        • 1970-01-01
        • 2012-09-04
        • 1970-01-01
        • 2010-09-18
        • 2011-01-18
        相关资源
        最近更新 更多