自动检测错误log4j静态初始化的方法

时间:2010-01-28 13:20:13

标签: java bash log4j

(请注意,它更像是一个Bash问题,而不是Java问题,请参阅下面的注释)

在每个类中配置log4j时,我们执行以下操作:

public class Example {

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

问题是我们现在有一个中等大小的代码库(200K LOC),其中包含很多Java类和......很多错误配置的log4j记录器。

这是因为人们(包括我,我承认),愚蠢地削减了'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. 如果没有报告
  7. 误报不是问题所以如果解析了一些虚假的“XXX类”,这不是问题。

    注意:问题是我们现在有200 000行代码,我们想自动检测违规(修复可以是手动的)所以问题与以下内容不同:

    [有没有更好的方法来获取java中的当前类变量?1

    实际上它可能更像是一个Bash问题而不是Java问题:)

    对此最热烈的帮助。

6 个答案:

答案 0 :(得分:0)

答案 1 :(得分:0)

您可以尝试使用AspectJ编织Logger.getLogger,以确定您的情况中的参数Example.class是否等于“当前类”名称。

提示:您可以使用以下内容以编程方式获取“当前类”名称:

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

答案 2 :(得分: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

答案 3 :(得分: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。但是用工厂调用替换初始的Logger声明。您需要捕获的唯一内容是局部变量的名称。然后你需要找到你的导入的位置,我假设你可以完全相同,因为你正在导入log4j(或java.util.logging)。找到import语句并在其下方导入您的工厂。

顺便说一下,关于自动执行此操作的所有警告都是正确的,同样适用于此解决方案。至少在尝试此操作后,您需要准备好javac所有内容。实际上,您应该拥有一些带有怪物代码覆盖率的测试套件,以便在此时自动运行。

答案 4 :(得分:0)

FindBugs中可能有一个探测器 - 如果没有,那绝对是一个写...

答案 5 :(得分:-1)

看看checkstyle。您可以编写执行此操作的checkstyle自定义规则。这将是XPath中一个有趣的练习。

但是,如果代码的结构非常可预测,我会提出它可以在sed中完成。如果你想用bash构建计算,那么......

  1. 使用exec打开文件描述符到文件
  2. 循环阅读行
  3. 当你看到第一个'class'语句时,抓住类名。
  4. 当您看到Logger构造时,请抓住并检查。