2010-01-28 71 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的检测器 - 如果没有,这绝对是一个写...