学会logger和exception结合使用

为什么exception.printStackTrace()认为不好的做法?

 

java 异常处理exception-handling printstacktrace
有大量的材料在那里这表明打印异常的堆栈轨迹是不好的做法。 例如从的Checkstyle的RegexpSingleline检查: 这种检查可以[...]以不好的做法,如呼叫ex.printStacktrace() 然而,我苦苦寻找的任何地方,给出了一个有效的理由,因为肯定的堆栈轨迹追查什么异常。事情我是知道的: 1)一个堆栈轨迹不应该visibile至(经验和安全的目的) 2)生成一个堆栈轨迹是一个相对昂贵的过程(虽然不太可能在大多数'exception'al情况下一个问题) 3)许多记录将打印堆栈轨迹你(我们不不,我们不能轻易改变它) 4)打印堆栈轨迹并不构成错误处理。它应该有日志记录和异常处理。 还有什么其他的原因都是为了避免在你的代码打印一个堆栈轨迹?
本文地址 :CodeGo.net/356766/ 
------------------------------------------------------------------------------------------------------------------------- 
1. Throwable.printStackTrace()写入堆栈轨迹System.errPrintStream的。该System.err流和底层标准的“错误”输出的JVM进程的数据流可以通过重定向 调用System.setErr()这改变所指向的目的地System.err。 或通过重定向进程的错误输出流。错误输出流可以被重定向到一个文件/设备 其内容可以由人员被忽略, 文件/设备可能不能够日志旋转,推断的过程需要重新启动,关闭打开的文件/设备句柄,归档文件/设备的现有内容之前。 或文件/设备实际上丢弃写入的所有数据,因为是的情况下,/dev/null。 从上面的推断 CodeGo.net,调用Throwable.printStackTrace()构成有效的(不好/大),异常处理行为,只 如果你没有System.err被重新分配在整个应用程序的持续时间 如果你不需要日志轮换的应用程序运行时, 如果接受/应用程序的设计记录的做法是写System.err(和JVM的标准错误输出流)。 在大多数情况下,上述条件不满足。人们可能没有意识到在JVM上运行其他代码,以及一个无法预测的日志文件的大小或过程的持续时间,以及精心设计的测井做法将围绕写作“机器解析的”日志文件(一个可取但在记录仪可选函数)在一个已知的目标,以帮助支持。 最后,一个人应该是输出Throwable.printStackTrace()肯定会得到与交错写入其他内容System.err(甚至可能System.out如果两者都重定向到文件/设备)。这是一个烦恼(对于单线程应用程序),一个必须处理,对周围异常的数据不便于解析在这样一个事件。更糟的是,它极有可能是一个多线程应用程序会产生非常日志,Throwable.printStackTrace()是不是线程安全的。 没有堆栈轨迹的写作同步System.err当多个线程调用Throwable.printStackTrace()在解决这实际上需要你的代码与相关的监视器上同步System.err(也System.out如果目标文件/设备的,这是相当沉重的代价,日志文件的理智。取一个例子,ConsoleHandlerStreamHandler类负责追加日志记录到控制台中提供的日志工具java.util.logging;publishing日志记录的实际操作是同步的-试图发布一个日志记录每个线程还必须获得与关联的监视器上的锁StreamHandler实例。如果你想拥有具有非交错日志的保证System.out/System.err,你必须确保-发布到这些流在可序列化的方式。 考虑到所有上述factor,以及非常有限的情况下,其中Throwable.printStackTrace()难道是经常原来调用它是一个不好的做法。 扩展的段落之一,它也是一个糟糕的选择Throwable.printStackTrace在一个记录器,写入控制台配合使用。这部分是由于该记录器将同步不同的显示器上,而你的应用程序将(可能是,如果你不希望交织的日志记录)不同的显示器上同步的原因。在还拥有不错的,当两个不同的记录器写入到目标,在你的应用程序。 
2. 优先件事情的printStackTrace()也不是很贵,你的状态,堆栈轨迹时异常被自己创建的填充。 我们的想法是通过任何经过一个记录器来记录,这样的记录是可以控制的。因此代替的printStackTrace,像Logger.log(msg, exception); 
3. 你都在触摸多的问题在这里: 1)一个堆栈轨迹不应该visibile至(经验和安全的目的) 是的,它应该是可访问的诊断的问题,但不应该看到他们有两个原因: 他们是非常blur的,无法读取,该应用程序将寻找 显示一个堆栈轨迹可能会引入潜在的安全风险。如果我错了,PHP的实际打印函数的堆栈轨迹-辉煌,但很-如果在连接到数据库时,你会得到异常,你这是有可能的堆栈轨迹? 2)生成一个堆栈轨迹是一个相对昂贵的过程(虽然不太可能在大多数'exception'al情况下一个问题) 抛出正在创建异常时生成一个堆栈轨迹情况/(这就是为什么有代价的抛出异常),印刷是不贵。事实上,你可以重写Throwable#fillInStackTrace()在您的自定义异常有效地使抛出异常几乎一样便宜简单的GOTO 3)许多记录将打印堆栈轨迹你(我们不不,我们不能轻易改变它) 写得非常好。这里的主要问题是:如果日志异常对你来说,什么也不做如果你想自己记录异常,使用日志记录像Logback和Log4J的,不要把它们放在原始的控制台是(但要确保它!)很难控制它。 与日志记录您可以轻松地重定向堆栈轨迹到文件,控制台,甚至将其发送到指定的电子邮件地址。用硬编码printStackTrace()你必须生活在sysout。 4)打印堆栈轨迹并不构成错误处理。它应该有日志记录和异常处理。 还是那句话:登录SQLException正确(与完整的堆栈轨迹,使用记录和展示美好。?“很抱歉,我们目前无法处理您的请求”消息你真的认为有兴趣的原因,你见过StackOverflow的错误画面这是非常,但不没有透露任何细节,但它确保这个问题将进行调查。 但他会打电话给你,你需要能够诊断问题。所以,你既需要:适当的异常记录 要总结的东西了:总是记录异常(记录,但不暴露他们仔细和有关想想在你的图形用户界面,显示堆栈轨迹仅在模式。 
4. printStackTrace()打印到控制台。在生产设置,没有人是永远看那个。苏拉杰是正确的,应该传递到记录器。 
5. 打印异常的堆栈轨迹,本身并不构成不好的做法,但只打印灯光音响轨迹发生异常时可能是这里的问题-往往只是打印堆栈轨迹是不够的。 此外,还有一种倾向,怀疑是正确的异常处理是不是被如果这一切是在一个被catch块是一个e.printStackTrace。处理不当,充其量一个问题被忽略,而在最坏的一个程序,继续执行在一个不确定的或意想不到的状态。 例子 让我们来考虑下面的例子:

try {
 initializeState();
} catch (TheSkyIsFallingEndOfTheWorldException e) {
 e.printStackTrace();
}
continueProcessingAssumingThatTheStateIsCorrect();

在这里,我们想要做的初始化处理之前,我们继续来处理,需要的初始化发生了。 在上面的代码中,异常应该被捕获并妥善处理,以防止程序在进行continueProcessingAssumingThatTheStateIsCorrect方法,我们可以将问题的。 在许多情况下,e.printStackTrace()迹象显示异常被吞噬和处理可以继续进行,如同没有问题每一个发生了。 为什么有这个问题吗? 可能是那个可怜的异常处理具有更普遍的最大原因之一是由于怎样的IDE,比如Eclipse会自动生成代码,将执行e.printStackTrace对于异常处理:

try {
 Thread.sleep(1000);
} catch (InterruptedException e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
}

(以上是实际try-catch被Eclipse自动生成处理的InterruptedException抛出Thread.sleep。) 对于大多数应用程序,只需在打印栈轨迹到标准错误可能不会是足够的。不当的异常处理可能在许多情况下导致运行的状态下,是意想不到的应用,并且可以导致意想不到的和不确定的行为。 
6. 我觉得你的上榜理由是一个。 我已经遇到不止一次一个特别糟糕的例子是这样的:

 try {
  // do stuff
 } catch (Exception e) {
  e.printStackTrace(); // and swallow the exception
 }

与上述代码的问题是,在处理完全由该printStackTrace拨打:异常是不是真的正确处理也不是允许逃脱。 在另一方面,作为一项规则我总是登录堆栈轨迹,每当有一个在我的代码意外的异常。多年来,这一policy有很多的调试 最后,在一个较为轻松,上帝的完美异常。 
7. 这不是不好的做法是“错误”的有关的printStackTrace(),但它的“代码味道”。 大多数的的printStackTrace()调用的是有没有适当地处理异常.a旦你处理异常以适当的方式,你通常不关心堆栈轨迹了。 此外,在stderr显示堆栈轨迹,一般调试时,没有在生产中往往标准错误是条死胡同。记录更有意义。但是,仅仅更换的printStackTrace()与记录异常仍留给你的哪些应用程序失败,但继续运行就像什么都没有发生。 
8. 在服务器应用程序的堆栈轨迹炸毁你的标准输出/标准错误文件。它可能大,而填充数据你没有上下文和无等。 例如catalina.out的tomcat作为容器 
9. 这里是一个很好的StackTrace我为我的项目之一:

public class reverseSlick { 
 public static String reverse(String str){
  for (String part : str.split(" ")) {
   System.out.println(new StringBuffer(part).reverse().toString());
   // System.out.print(" ");
  }
 return str;
 }
 public static void main(String[] args) {
  try{
    reverse("abcdefghigklmnopqrstuvwxyz");
  } catch(Exception ex){
   ex.printStackTrace();
   System.out.println("\n" + ex.getMessage());
   System.out.println("\n" + ex.toString());
   System.out.println("\nTrace info obtained from getStackTrace");
   StackTraceElement[] traceElements = ex.getStackTrace();
   for(int i=0 ; i<traceElements.length ; i++){
    System.out.println("Method" + traceElements[i].getMethodName());
    System.out.println("(" + traceElements[i].getClassName() + ":");
    System.out.println(traceElements[i].getLineNumber() + ")");
   }
  }
 }
}




怎么能将e.printStackTrace()写入log4j文件

 

工程中有很多e.printStackTrace(); 这些目前只在控制台输出,现在想把这些信息都加入到log文件当中,又不想修改太多地方,有没有方法或者log4j配置能将控制台的信息输出到log文件?
比如:如下代码:
try{
String test = null;
test.trim();
}catch(Exception e){
e.printStackTrace();
}
在不做代码修改或只修改个别方法的情况下,把打出的异常堆栈写入到log文件中,不知道log4j有没有这种配置。
用logger.error()的解决办法就不用说了,这样要改的地方太多,需要不修改代码或尽量少的修改代码。
log4j配置文件如下:

log4j.rootLogger=ERROR,A1,CA

#===================================================================================================
# Thirdparty log, CA(console) output DEBUG level only.
#
log4j.A1.org.springframework=ERROR,CA
log4j.A1.org.apache=error,CA
log4j.A1.net=ERROR,CA
log4j.A1.antlr=ERROR,CA
log4j.A1.com.sun=ERROR,CA
log4j.A1.freemarker=ERROR,CA
log4j.A1.com.caucho=ERROR,CA
log4j.A1.junit=ERROR,CA
log4j.A1.common=ERROR,CA
log4j.A1.jxl=ERROR,CA
log4j.A1.oracle=ERROR,CA
log4j.A1.com.lining=error,CA
log4j.A1.xjavadoc=ERROR,CA
log4j.A1.org.exolab=error,CA
log4j.A1.org.hibernate.SQL=error,CA
log4j.A1.org.hibernate=error,CA

#==================================================================================================
# CA is set to be a ConsoleAppender,DailyRollingFileAppender
log4j.logger.CA=error,CA
log4j.appender.CA=org.apache.log4j.ConsoleAppender
log4j.appender.CA.layout=org.apache.log4j.PatternLayout 
log4j.appender.CA.layout.ConversionPattern=[%p] %-d{HH:mm:ss,SSS} [%c:%L] %m%n

#========================File==================
log4j.logger.A1=error,A1

log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=C:/log/cba_log.log
log4j.appender.A1.DatePattern = '.'yyyy-MM-dd
log4j.appender.A1.Append = true
#log4j.appender.A1.MaxFileSize=5000KBs
#log4j.appender.A1.MaxBackupIndex=100
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
#log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd,HH:mm:ss} %-5p %3x %m%n
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd,HH:mm:ss} [%c:%L] %m%n
log4j.additivity.A1=false

#log4j.logger.sql=error,sql

#log4j.appender.sql=org.apache.log4j.RollingFileAppender
#log4j.appender.sql.File=../WEB-INF/ZyyStudyLog.log
#log4j.appender.sql.MaxFileSize=5000KBs
#log4j.appender.sql.MaxBackupIndex=10
#log4j.appender.sql.layout=org.apache.log4j.PatternLayout
#log4j.appender.sql.layout.ConversionPattern=%-d{yyyy-MM-dd,HH:mm:ss} %-5p %3x %m%n
#log4j.additivity.sql=false

 
 
 
评论 (0) •  • 链接 • 2012-12-19 
 
4个答案
 

e.printStackTrace(); 默认并没有输出到控制台,尤其是在web开发中,所以,我想到的办法是,为 Tomcat 配置 log4j。

  1. 第一步:下载 log4j.jar,并把 log4j.jar 放入 $CATALINA_HOME/common/lib
  2. 第二步:新建 log4j.properties 文件,放到 $CATALINA_HOME/common/classes/ 目录下
  3. 第三步:写配置文件log4j.properties

日志文件会记录在 ${catalina.home}/logs/tomcat_log_xxxx。

评论 (2) • 链接 • 2012-12-19
  • 0
    哎,难道是我写的不清楚,我知道怎么配log4j,现在配置没有问题,我是想把所有有e.printStackTrace()的输出堆栈在不修改代码的情况下写入log文件, – LT_刚 2012-12-19
  • 0
    @LT_刚 你没有理解我的意思。我说不是配置你webapp的log,而是配置tomcat的log。 – justjavac2012-12-19
 

System.setErr(new PrintStream(new File("/test.log")));
new Exception(":)").printStackTrace();

冒昧的问下..为啥有这个奇怪的需求...

评论 (3) • 链接 • 2012-12-19
  • 0
    就是以前输出的异常堆栈只用的e.printStackTrace(),没有用logger.error(),所以只在控制台显示,没有写入log文件,现在想把这些堆栈也加到log文件中以便查询,但是代码里的地方比较多,不想做修改,就想看看有没有方法把控制台的信息都写入文件。最终想要达到的效果就是我只在代码中写e.printStackTrace(),这些堆栈信息就都写入log文件 – LT_刚 2012-12-19
  • 0
    方式我已经告诉你啦..楼下说的也对。
    你调用System.setErr()方法,将out流替换成log4j的out流就可以啦...
    但是我告诉你,你这样想不对。既然log4j提供了你error、debug和info等输出日志类型。你为啥不用呢?与其犯懒去修改这个。倒不如重新整理下你的代码吧。
    logger.error(msg , Throwable) 这个也可以输出堆栈信息啊。 – 犀利猫 2012-12-19
  • 0
    有日志系统干嘛还用out.print那一套... – 犀利猫 2012-12-19
 

看看Throwable类的printStackTrace方法

public void printStackTrace(){
printStackTrace(System.err);
}
 

这里说明,printStackTrace是把消息输出到System.err的,所以要只要重定向System.err即可:

File log4j = new File("log");
PrintStream ps = new PrintStream(new DataOuputStream(new FileOutputStream(log4j)));
System.setErr(ps);
 

不过这里有个缺点就是所有的错误信息都会输出到这个文件里。
如果需要只针对printStackTrace的话,那么可以考虑用字节码增强来修改printStackTrace()的调用了。

评论 (0) • 链接 • 2012-12-19
 

logger.error(e,e.fillInStackTrace());

评论 (0) • 链接 • 2014-06-25

 

posted @ 2017-03-15 17:19  guodaxia  阅读(479)  评论(0)    收藏  举报