【问题标题】:How to send a stacktrace to log4j?如何将堆栈跟踪发送到 log4j?
【发布时间】:2011-05-19 20:49:33
【问题描述】:

假设你捕获了一个异常并在标准输出(比如控制台)上得到以下信息,如果你执行 e.printStackTrace()

java.io.FileNotFoundException: so.txt
        at java.io.FileInputStream.<init>(FileInputStream.java)
        at ExTest.readMyFile(ExTest.java:19)
        at ExTest.main(ExTest.java:7)

现在我想将它发送到一个记录器,比如 log4j,以获得以下信息:

31947 [AWT-EventQueue-0] ERROR Java.io.FileNotFoundException: so.txt
32204 [AWT-EventQueue-0] ERROR    at java.io.FileInputStream.<init>(FileInputStream.java)
32235 [AWT-EventQueue-0] ERROR    at ExTest.readMyFile(ExTest.java:19)
32370 [AWT-EventQueue-0] ERROR    at ExTest.main(ExTest.java:7)

我该怎么做?

try {
   ...
} catch (Exception e) {
    final String s;
    ...  // <-- What goes here?
    log.error( s );
}

【问题讨论】:

    标签: java logging log4j stack-trace


    【解决方案1】:

    您将异常直接传递给记录器,例如

    try {
       ...
    } catch (Exception e) {
        log.error( "failed!", e );
    }
    

    由 log4j 来呈现堆栈跟踪。

    【讨论】:

    • 记录器将一个对象作为它的第一个参数,并将 toString() 它。但是第二个参数必须是 Throwable 并显示堆栈跟踪。
    • 我永远不知道在第一个字符串中填充什么,通常我最终会做log.error(e.getLocalizedMessage(), e),这完全是多余的。它是否处理第一个参数的空值?
    • @Mark:尝试给它一个比异常消息更贴近上下文的消息,例如当时它到底想做什么?
    • @Mark Peters,一个很好的例子是将当前方法的参数记录为消息,或者 - 对于 FileNotFound 异常,尝试打开的路径的全名。任何可以帮助您找出问题所在的方法——只要认为您无法调试情况即可。
    • @skaffman:实际上我正在使用log4j-1.2.8.jar,我想在我的日志文件上打印所有stackTrace,所以我尝试像上面提到的那样,但只是在我的日志文件上打印nullPointerException .我在我的代码e.printStackTrace() 上使用它打印所有跟踪。为什么是这个 Kolavery?
    【解决方案2】:

    您还可以通过ExceptionUtils.getStackTrace 以字符串形式获取堆栈跟踪。

    见:ExceptionUtils.java

    我只将它用于log.debug,以保持log.error 简单。

    【讨论】:

      【解决方案3】:

      创建这个class

      public class StdOutErrLog {
      
      private static final Logger logger = Logger.getLogger(StdOutErrLog.class);
      
      public static void tieSystemOutAndErrToLog() {
          System.setOut(createLoggingProxy(System.out));
          System.setErr(createLoggingProxy(System.err));
      }
      
      public static PrintStream createLoggingProxy(final PrintStream realPrintStream) {
          return new PrintStream(realPrintStream) {
              public void print(final String string) {
                  logger.info(string);
              }
              public void println(final String string) {
                  logger.info(string);
              }
          };
      }
      }
      

      在你的代码中调用它

      StdOutErrLog.tieSystemOutAndErrToLog();
      

      【讨论】:

        【解决方案4】:

        此答案可能与提出的问题无关,但与问题的标题有关。

        public class ThrowableTest {
        
            public static void main(String[] args) {
        
                Throwable createdBy = new Throwable("Created at main()");
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                PrintWriter pw = new PrintWriter(os);
                createdBy.printStackTrace(pw);
                try {
                    pw.close();
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                logger.debug(os.toString());
            }
        }
        

        public static String getStackTrace (Throwable t)
        {
            StringWriter stringWriter = new StringWriter();
            PrintWriter  printWriter  = new PrintWriter(stringWriter);
            t.printStackTrace(printWriter);
            printWriter.close();    //surprise no IO exception here
            try {
                stringWriter.close();
            }
            catch (IOException e) {
            }
            return stringWriter.toString();
        }
        

        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for(StackTraceElement stackTrace: stackTraceElements){
            logger.debug(stackTrace.getClassName()+ "  "+ stackTrace.getMethodName()+" "+stackTrace.getLineNumber());
        }
        

        【讨论】:

          【解决方案5】:

          只是因为它发生在我身上并且可能有用。 如果你这样做

          try {
             ...
          } catch (Exception e) {
              log.error( "failed! {}", e );
          }
          

          您将获得异常的标头,而不是整个堆栈跟踪。因为记录器会认为您正在传递一个字符串。 正如 skaffman 所说,不用 {} 就可以了

          【讨论】:

          • 您肯定会在这里获得整个堆栈跟踪,但是 {} 也会逐字打印(没有任何替换)?
          • 别那么肯定我的朋友!这对我不起作用,我只有标题。它可能取决于 log4j 的版本
          • @iberbeu 是正确的,因为Throwable.toString() 不返回堆栈跟踪。 (假设您使用的记录器知道如何处理“{}”。)
          【解决方案6】:

          如果您想在不涉及异常的情况下记录堆栈跟踪,只需执行以下操作:

          String message = "";
          
          for(StackTraceElement stackTraceElement : Thread.currentThread().getStackTrace()) {                         
              message = message + System.lineSeparator() + stackTraceElement.toString();
          }   
          log.warn("Something weird happened. I will print the the complete stacktrace even if we have no exception just to help you find the cause" + message);
          

          【讨论】:

          • System.lineSeparator() 的 +1,这帮助我打印了一个堆栈跟踪,这是我从远程服务获得的响应
          • 我搜索过的,但你应该在这里使用 StringBuilder
          【解决方案7】:

          skaffman 的答案绝对是正确的答案。 error()warn()info()debug() 等所有 logger 方法都将 Throwable 作为第二个参数:

          try {
          ...
           } catch (Exception e) {
          logger.error("error: ", e);
          }
          

          但是,您也可以将堆栈跟踪提取为字符串。有时,如果您希望使用“{}”占位符来利用格式化功能,这可能会很有用 - 请参阅方法 void info(String var1, Object... var2); 在这种情况下,假设您有一个堆栈跟踪作为字符串,那么您实际上可以执行以下操作:

          try {
          ...
           } catch (Exception e) {
          String stacktrace = TextUtils.getStacktrace(e);
          logger.error("error occurred for usename {} and group {}, details: {}",username, group, stacktrace);
          }
          

          这将在最后打印参数化消息和堆栈跟踪,方法与方法相同:logger.error("error: ", e);

          实际上,我编写了一个开源库,其中包含一个实用程序,用于将堆栈跟踪提取为字符串,并且可以选择巧妙地从堆栈跟踪中过滤掉一些噪音。 IE。如果您指定您对提取的堆栈跟踪感兴趣的包前缀,则会从一些不相关的部分中过滤掉,并为您留下非常简洁的信息。这是文章的链接,该链接解释了该库具有哪些实用程序以及从何处获取它(作为 maven 工件和 git 源)以及如何使用它。 Open Source Java library with stack trace filtering, Silent String parsing Unicode converter and Version comparison 见段落“Stacktrace 噪声过滤器

          【讨论】:

          • 一个隐藏但很好的答案。
          • 谢谢,@payne。非常感谢您的反馈
          • 谢谢。我最终提出了这个问题,因为我一直在寻找这个答案。
          • @axiopisty - 欢迎您。我很高兴它对你有用
          【解决方案8】:

          这将是很好的 log4j 错误/异常日志记录 - 可由 splunk/其他日志记录/监控软件读取。一切都是键值对的形式。 log4j 将从 Exception obj e 获取堆栈跟踪

              try {
                    ---
                    ---
              } catch (Exception e) {
                  log.error("api_name={} method={} _message=\"error description.\" msg={}", 
                            new Object[]{"api_name", "method_name", e.getMessage(), e});
              }
          

          【讨论】:

            【解决方案9】:
            Try this:
            
            catch (Throwable t) {
                logger.error("any message" + t);
                StackTraceElement[] s = t.getStackTrace();
                for(StackTraceElement e : s){
                    logger.error("\tat " + e);
                }   
            }
            

            【讨论】:

              【解决方案10】:

              您可以使用以下代码:

              import org.apache.logging.log4j.Logger;
              import org.apache.logging.log4j.LogManager;
              
              public class LogWriterUtility {
                  Logger log;
              
                  public LogWriterUtility(Class<?> clazz) {
                      log = LogManager.getLogger(clazz);
                  }
              
              public void errorWithAnalysis( Exception exception) {
              
                      String message="No Message on error";
                      StackTraceElement[] stackTrace = exception.getStackTrace();
                      if(stackTrace!=null && stackTrace.length>0) {
                          message="";
                          for (StackTraceElement e : stackTrace) {
                              message += "\n" + e.toString();
                          }
                      }
                      log.error(message);
              
              
                  }
              
              }
              

              您可以在这里拨打:LogWriterUtility.errorWithAnalysis( YOUR_EXCEPTION_INSTANCE);

              它会将 stackTrace 打印到您的日志中。

              【讨论】:

                【解决方案11】:

                在 Log4j 2 中,您可以使用 Logger.catching() 从捕获的异常中记录堆栈跟踪。

                    try {
                        String msg = messages[messages.length];
                        logger.error("An exception should have been thrown");
                    } catch (Exception ex) {
                        logger.catching(ex);
                    }
                

                【讨论】:

                • 您也可以毫无例外地打印堆栈跟踪,使用:logger.catching(new Throwable());
                猜你喜欢
                • 2012-01-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-09-25
                • 1970-01-01
                • 1970-01-01
                • 2011-01-18
                • 1970-01-01
                相关资源
                最近更新 更多