Way to automatically detect wrong log4j static initialization

对着背影说爱祢 提交于 2019-12-06 12:04:12

I guess if you're looking for a one-liner, one-liner

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' \
    {} \;

I would back up your code before trying this. It's probably broken in a couple places, but with a few corrections will get you what you're looking for. If you're using svn or something, you'll have to tweak find to exclude the .svn directories, otherwise your commits will be really messed up.

The gist: don't even bother trying to capture class names. Incorporate the solution indirectly linked to by Alexander. But replace your initial Logger declarations with factory calls. The only thing you need to capture is the name of the local variable. Then you need to find where your imports are, which I'm assuming you can do pretty exactly because you're importing log4j (or java.util.logging). Find that import statement and import your factory right below it.

BTW, all the warnings you're getting about automating this are correct and equally apply to this solution. You need to be prepared to javac everything right after trying this at the very least. Really, you should have some test suites with monster code coverage to automatically run at this point.

Alexander Pogrebnyak

you could try weaving Logger.getLogger with AspectJ, in order to determine if the parameter, Example.class in your case, equals the "current class" name.

Hint: you can get the "current class" name programmatically using something like:

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

Untested:

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

There may be a detector in FindBugs - if there isn't, it's definitely one to write...

bmargulies

Look into checkstyle. You can write a checkstyle custom rule that does this. It will be an interesting exercise in XPath.

However, if the code is very predictably structured, I'd offer that it could be done in sed. If you want to structure the computation in bash, then ...

  1. use exec to open a file descriptor to the file
  2. loop with while reading lines
  3. when you see the first 'class' statement, grab the class name.
  4. when you see the Logger construction, grab and check.
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!