2012-11-17 66 views
1

EDIT2
@paradigmatic提出了重定向而不是拋出異常的好處;解決了日誌記錄問題。 Play 2中的問題是重定向需要在所謂的Action範圍內發生,而日期解析器調用並非總是如此。Java 7:拋出沒有堆棧跟蹤的異常

作爲一種解決方法,我使用了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); 
    } 
} 

上調用一個無效的年月日的日期解析器字符串記錄30行堆棧跟蹤到日誌(這發生在Play框架/ Netty容器的上游,是tter比默認的100線跡):

"20120099".to_date 

ORIGINAL
有在我的application.log是越來越充滿了與該應該成功提供有效的yyyyMMdd URI日期URI日期解析器操作失誤的問題。

但是,一些用戶試圖通過輸入無效日期來避免這種情況,希望獲得免費訪問付費用戶專用內容。這是毫無意義的,因爲它根本無法工作,但無論如何,我的應用程序日誌中都有這些錯誤跟蹤的MB。

有沒有辦法將一個真正修剪到日誌中的Exception?我發現this SO answer,但在我的應用程序中,它看起來像容器(Netty上的Play框架)進入混合並將其自己的30行堆棧跟蹤記錄到日誌中(30行比100好,但仍有29太多)

同樣,我發現this thread在Java 7和新的選項抑制堆棧跟蹤;然而,出於某種原因,儘管使用了Java 1.7,但爲Java 1.7配置了Eclipse,但只有Throwable的舊2參數方法可用(並且在單擊到Throwable類時可以看到4參數方法;也許是Scala 2.9.2庫問題?)

無論如何,理想情況下,我可以簡單地記錄單行異常消息而不是廚房水槽。

+0

寫下你的代碼,你可能沒有打印堆棧跟蹤 –

+1

爲什麼在第一個地方拋出Exception?是否有可能接受任何日期(有效與否),並在無效時重定向到頁面? – paradigmatic

+0

@paradigmatic好點,問題是我相信Play 2 Scala重定向必須發生在Action範圍內(例如「def index = Action {Ok.redirect(」/ foo「)}」); uri日期解析器調用站點並不總是出現在Action範圍內,所以我沒有辦法重定向(你是對的,這是首選解決方案) – virtualeyes

回答

2

你的問題是,雖然你可以抑制你自己的代碼拋出異常的堆棧跟蹤,但是你不能對它將被框架封裝的異常做任何事情。我能看到的唯一途徑是不允許框架根據您的異常(執行您自己的頂級處理)或調整日誌記錄配置。

+0

+1,儘管這不是我想聽到的;-)也許調整log4j config會給我希望有靈活性。謝謝 – virtualeyes

1

我認爲你有兩個選擇:

  1. 控制記錄不保存堆棧跟蹤一些例外。
  2. 編寫一個後處理器,用於過濾掉日誌文件中的痕跡。

除非您有磁盤空間不足的危險,否則我認爲#2是更好的選擇,因爲如果您確實有錯誤,則可以返回完整日誌並獲取所有異常歷史記錄。

想法#2背後的理念是磁盤空間很便宜,但在調試過程中信息可能很珍貴。記錄大量數據。通常情況下,使用腳本將日誌寫入磁盤後檢查日誌。

例如,如果有一種您不希望看到的日誌條目類型,但如果它確實出現需要立即採取措施,請編寫一個腳本來搜索它,並在發現電子郵件時發送給您一。

這種方法中最有用的腳本形式之一是刪除堆棧跟蹤行。通常,您只需要知道發生了什麼異常,並且堆棧跟蹤佔用很多屏幕空間而不會告訴你很多。如果您確實需要調查異常,請返回完整日誌,查找異常行,並查看堆棧跟蹤以及緊接異常之前發生的事情。

如果您的日期例外太多,請讓腳本放下即使是異常行。如果您想跟蹤它們發生的頻率,請運行一個腳本來計算每小時的日期異常。

這種腳本通常會花費幾分鐘的時間用最喜歡的正則表達式語言編程。

+0

+1,磁盤空間不是問題,它更需要日誌中的相關痕跡。我會調整log4j,看看我是否可以在沒有跟蹤的情況下記錄這個特定的錯誤條件。謝謝 – virtualeyes

+0

@virtualeyes我根據磁盤空間不是問題的假設擴展了我的答案。 –