2010-01-28 52 views
2

(請注意,它比一個Java問題Bash的問題,請參見下面的註釋)方法來自動檢測錯誤log4j的靜態初始化

當每班配置log4j的,我們做到以下幾點:

public class Example { 

    private static final Logger log = Logger.getLogger(Example.class); 

問題是,我們現在有一箇中等規模的代碼庫(200K LOC),包含大量的Java類和...很多錯誤配置的log4j記錄器。

這是因爲人們(包括我在內,我承認),的確在這有時會導致傻cut'n'paste:

public class Another { 

    private static final Logger log = Logger.getLogger(Example.class); 

與繁榮,而不必Another.class,這是老Example.class這是留下來,因此錯誤地出現在日誌中(因此導致相當多的頭痛)。

我覺得有點奇怪,這種錯誤配置可能會發生,但它可以和我們現在的主要問題不是它可能發生,但我們必須修復錯誤記錄的記錄器。

我們該如何去自動檢測這些? (修復可以是手動的,但我想找一種方式來找到log4j配置錯誤的所有類)。

例如,Bash shell腳本將會非常受歡迎。

  1. 每一個java文件
  2. 發現每一個 「類XXX」
  3. 解析下一個 'X' 線(例如20)
  4. 是有一個Logger.getLogger(...)線?
  5. 如果是,它是否與「XXX級」匹配?
  6. 如果沒有報告

假陽性是不是一個問題,所以它不是如果一些虛假的「類XXX」進行解析的問題等

注意:這個問題確實是我們現在有20萬行代碼,我們希望自動檢測違規(修復可以是手動),所以問題不是類似於:

[是否有更好的方式來獲取當前類變量在Java ? 1

其實它可能更多的是Bash的問題不是一個Java的問題:)的

在這個最歡迎任何幫助。

回答

0

我想,如果你正在尋找一個班輪,一個班輪

find -name "*.java" -exec sed -i \ 
    -e 's/private static final Logger \([a-zA-Z_][a-zA-Z0-9_]*).*$/private static final Logger \1 = LoggerFactory.make()/g' \ 
    -e 's/import org\.apache\.log4j\.Logger;/&\nimport path.to.LoggerFactory;/g' \ 
    {} \; 

嘗試此之前,我會支持你的代碼。它可能在幾個地方被打破,但有一些更正會讓你找到你想要的。如果你使用的是svn或者其他東西,你必須調整find來排除.svn目錄,否則你的提交將會真的搞砸了。

的要點:甚至不打擾試圖捕獲類名。納入the solution indirectly linked to by Alexander。但用工廠調用取代你的初始記錄器聲明。唯一需要捕獲的是局部變量的名稱。那麼你需要找到你的進口,哪個我假設你可以做的很完全,因爲你正在導入log4j(或java.util.logging)。找到import聲明並在其下面導入您的工廠。

順便說一句,所有關於自動化的警告都是正確的,同樣適用於此解決方案。您至少需要需要以準備javac一切正確。真的,你應該有一些具有怪物代碼覆蓋率的測試套件在這一點上自動運行。

+0

+1你的方法很有趣。我沒有考慮自動改變類名來使用Factory make方法。不要擔心代碼:Mercurial/hg到處都是,海量的代碼覆蓋,單元測試等。同時,我寫了一些與Denis發佈的內容非常相似的東西,並且它的確行得通。現在我可能會添加工廠並使用您的一個班輪。再一次,不用擔心它是Mercurial :) – SyntaxT3rr0r 2010-01-28 14:56:41

0

你可以嘗試編織Logger.getLogger和AspectJ,以確定參數,Example.class你的情況,等於「當前類」名。

提示:程序可以用類似拿到「當前類」名:

String className = new Exception().getStackTrace()[0].getClassName(); 
+0

啊,這很有趣:我沒有AspectJ的經驗,說並希望通過一些「命令行」的方式來快速找到違規行爲。 – SyntaxT3rr0r 2010-01-28 13:35:47

-1

查找到的CheckStyle。你可以寫一個checkstyle自定義規則來做到這一點。在XPath中這將是一個有趣的練習。

但是,如果代碼是非常可預測的結構,我會提供它可以在sed中完成。如果你想構建計算在bash,然後...

  1. 使用EXEC打開一個文件描述符文件
  2. 循環與在閱讀線
  3. 當你看到第一個「類」
  4. 聲明,抓住班級名稱。
  5. 當你看到記錄器的構造時,抓住並檢查。
+0

我想我會添加一個更精確的新問題。 Un * x環境的許多強大力量一如既往地能夠快速結合幾條命令,務實地完成工作。你聽起來像我試圖解析一個結構化的Java文件來檢索AST,但我真的不是。我所要求的是非常合理的,對於比find/awk/grep更熟悉的用戶來說,可能並不難。 – SyntaxT3rr0r 2010-01-28 13:53:49

+0

@OldEnthusiast - 如果你的代碼是非常非常可預測的格式,那麼我不會否認sed和bash可以完成這項工作。 – bmargulies 2010-01-28 14:25:49

+0

@bm - 即使它不是非常可預測的,該腳本將與循環中的人一起使用來檢查誤報。它很笨拙,但卻不像正則表達式XML那樣危險......嵌入到一些生產服務器中。 – 2010-01-28 15:29:29

0

未經測試:

find *.java | while read file 
    do 
     lines=$(grep -A 20 "public class .* {" "$file") 
     class=$(echo "$lines" | sed -n '1 s/public class \(.*\) {/\1/p' 
     log=$(echo "$lines" | grep "Logger.getLogger" 
     log=$(echo "$log" | sed -n 's/.*(*\(.*\).class *).*') 
     if [[ "$log" != "$class" ]] 
     then 
      echo "There's a mis-match in file $file, class $class, for logger $log" 
     fi 
    done 
+0

非常感謝,我最終寫了類似的東西,它讓我能夠找到相當多的類,記錄器被無法正確初始化。 – SyntaxT3rr0r 2010-01-28 14:52:16

0

有可能在FindBugs的檢測器 - 如果沒有,這絕對是一個寫...