Java 7:抛出异常而没有堆栈跟踪

时间:2012-11-17 11:54:50

标签: java scala stack-trace suppress

EDIT2
@paradigmatic在建议重定向而不是抛出异常时提出了一个很好的观点;这解决了日志记录问题。 Play 2中的问题是重定向需要在所谓的Action范围内发生,而日期解析器调用并不总是如此。

作为一种解决方法,我使用了Play的全局拦截器,可能相当于Java servlet过滤器。

val ymdMatcher = "\\d{8}".r // matcher for yyyyMMdd URI param
val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
def ymd2Date(ymd: String) = ymdFormat.parseDateTime(ymd)

override def onRouteRequest(r: RequestHeader): Option[Handler] = {
  import play.api.i18n.Messages
  ymdMatcher.findFirstIn(r.uri) map{ ymd=>
    try { ymd2Date( ymd); super.onRouteRequest(r) }
    catch { case e:Exception => // kick to "bad" action handler on invalid date 
      Some(controllers.Application.bad(Messages("bad.date.format"))) 
    }
  } getOrElse(super.onRouteRequest(r))
}

修改
以下是一些可以使用的上下文:

// String "pimp": transforms ymdString.to_date call into JodaTime instance
class String2Date(ymd: String) {
  def to_date = {  
    import play.api.i18n.Messages
    try{ ymdFormat.parseDateTime(ymd) } 
    catch { case e:Exception => throw new NoTrace(Messages("bad.date.format")) }
  }
  val ymdFormat = org.joda.time.format.DateTimeFormat.forPattern("yyyyMMdd")
}
@inline implicit final def string2Date(ymd: String) = new String2Date(ymd)

和测试自定义异常处理程序:

public class NoTrace extends Exception {
  static final long serialVersionUID = -3387516993124229948L;

  @Override
  public Throwable fillInStackTrace() {
      return null;
  }      
  public NoTrace(String message) {
    super(message);
  }
}

在无效的yyyyMMdd字符串上调用日期解析器会将30行堆栈跟踪记录到日志中(这发生在Play框架/ Netty容器的上游,优于默认的100行跟踪):

"20120099".to_date

ORIGINAL
有一个问题,我的application.log充满了与uri date解析器操作相关的错误,如果有一个有效的yyyyMMdd uri日期,该操作应该会成功。

但是,有些用户试图通过输入无效日期来避免这种情况,希望获得免费访问付费用户的内容。这是毫无意义的,因为它根本不起作用,但无论如何,我的应用程序日志中都有MB这些错误跟踪。

有没有办法将真正精简的Exception扔到日志中?我发现this SO answer,但在我的应用程序中看起来容器(Netty上的Play框架)进入混合并将其自己的30行堆栈跟踪记录到日志中(30行优于100,但仍然是29许多)

同样,我发现了{7}}关于Java 7和抑制堆栈跟踪的新选项;但是,出于某种原因,尽管使用Java 1.7,Eclipse配置为Java 1.7,但只有Throwable的旧2参数方法可用(当我点击Throwable类时我确实看到了4参数方法;也许是Scala 2.9.2库问题?)

无论如何,理想情况下我只需记录 1行异常消息而不是厨房水槽。

3 个答案:

答案 0 :(得分:2)

你的麻烦在于,尽管你可以抑制你自己的代码抛出的异常的堆栈跟踪,但是对于它将被框架包含的异常,你无能为力。我能看到的唯一途径是不允许框架捕获您的异常(执行您自己的顶级处理)或调整日志记录配置。

答案 1 :(得分:1)

我认为你有两个选择:

  1. 控制日志记录,以便在某些例外情况下不保存堆栈跟踪。
  2. 编写一个过滤掉日志文件中痕迹的后处理器。
  3. 除非您有超出磁盘空间的危险,否则我认为#2是更好的选择,因为如果您确实有错误,您可以返回完整日志并拥有所有异常历史记录。

    理念#2背后的理念是磁盘空间便宜,但在调试过程中信息可能很宝贵。记录大量数据。通常,在将日志写入磁盘后使用脚本检查日志。

    例如,如果存在一种您从未期望看到的日志条目,但是如果它确实出现则需要立即执行操作,请编写一个搜索它的脚本,如果找到一个则发送一封电子邮件

    此方法中最有用的脚本形式之一是删除堆栈跟踪线。通常,您只需要知道发生了什么异常,并且堆栈跟踪占用了大量的屏幕空间而没有告诉您太多。如果确实需要调查异常,请返回完整日志,找到异常行,查看堆栈跟踪以及异常之前发生的事情。

    如果您的日期例外太多,请让脚本删除甚至是异常行。如果要跟踪它们发生的频率,请运行一个计算每小时日期例外的脚本。

    这种脚本通常需要花费几分钟的时间来编写您喜欢的正则表达式脚本语言。

答案 2 :(得分:0)

只需在自定义异常类中添加以下覆盖方法

@Override

public Throwable fillInStackTrace() {
    return this;
}      

添加此方法后,您的跟踪方法将无法打印