1

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

原始
有一个问题,我的 application.log 充满了与 uri 日期解析器操作相关的错误,如果给定有效的yyyyMMdduri 日期,该操作应该成功。

然而,一些用户试图通过输入无效日期来规避这一点,以期获得免费访问仅限付费订阅者的内容。这是没有意义的,因为它根本不起作用,但无论如何,我的应用程序日志中有这些错误跟踪的 MB 数。

有没有办法将一个真正修剪Exception的日志扔到日志中?我找到了这个 SO 答案,但在我的应用程序中,它看起来像容器(Netty 上的 Play 框架)进入混合状态并将其自己的 30 行堆栈跟踪记录到日志中(30 行优于 100 行,但仍有 29 行太多)

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

无论如何,理想情况下,我可以简单地记录一条1 行异常消息,而不是厨房水槽。

4

3 回答 3

3

只需在您的自定义异常类中覆盖此方法:

@Override
public Throwable fillInStackTrace() {
    return this;
}      

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

于 2018-12-10T05:24:58.940 回答
2

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

于 2012-11-17T11:59:32.183 回答
2

我认为你有两个选择:

  1. 控制日志记录以不保存某些异常的堆栈跟踪。
  2. 编写一个后处理器,从日志文件中过滤掉跟踪。

除非您面临磁盘空间不足的危险,否则我认为#2 是更好的选择,因为如果您确实有错误,您可以返回完整日志并查看所有异常历史记录。

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

例如,如果有一种您从没想过会看到的日志条目,但如果它确实出现则需要立即采取行动,请编写一个搜索它的脚本,如果找到它就给您发送一封电子邮件。

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

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

这种脚本通常需要几分钟的时间,用您最喜欢的支持正则表达式的脚本语言进行编程。

于 2012-11-17T12:13:00.253 回答