Способ автоматического определения неправильной статической инициализации log4j - PullRequest
2 голосов
/ 28 января 2010

(обратите внимание, что это вопрос Bash, а не вопрос Java, см. Примечание ниже)

При настройке log4j в каждом классе мы делаем следующее:

public class Example {

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

Проблема в том, что теперь у нас есть кодовая база среднего размера (200K LOC), содержащая множество классов Java и ... Довольно неправильно настроенные логгеры log4j.

Это потому, что люди (включая меня, я признаю) делали глупую нарезку и пасту, что иногда приводило к этому:

public class Another {

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

И бум, вместо того, чтобы иметь Другой.класс , это старый Пример.класса , который остается и, следовательно, ошибочно появляется в журналах (что вызывает немало головных болей).

Я нахожу довольно странным, что такая неправильная конфигурация может произойти, но это возможно, и наша главная проблема сейчас не в том, что это может произойти, а в том, что мы должны исправить неправильно настроенные регистраторы.

Как мы можем автоматически обнаруживать их? (исправление может быть ручным, но я хотел бы найти способ найти все классы, в которых log4j настроен неправильно).

Сценарий Bash, например, будет очень кстати.

  1. для каждого файла .java
  2. найти каждый "класс XXX"
  3. разбирать следующие строки 'x' (скажем, 20)
  4. есть ли строка Logger.getLogger (...)?
  5. если да, соответствует ли он "классу XXX"?
  6. если нет отчета

Ложное срабатывание не является проблемой, поэтому не проблема, если несколько поддельных "классов XXX" проанализированы и т. Д.

ПРИМЕЧАНИЕ : проблема в том, что у нас теперь есть 200 000 строк кода, и мы хотели бы обнаружить нарушение автоматически (исправление может быть ручным), поэтому вопрос не похож на:

[Есть ли лучший способ получить текущую переменную класса в Java? 1

На самом деле это скорее вопрос Bash, чем вопрос Java:)

Любая помощь в этом наиболее приветствуется.

Ответы [ 6 ]

0 голосов
/ 28 января 2010

В FindBugs может быть детектор - если его нет, его обязательно нужно написать ...

0 голосов
/ 28 января 2010

Я думаю, если вы ищете однострочник, однострочник

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 или что-то еще, вам придется настроить поиск, чтобы исключить каталоги .svn, в противном случае ваши коммиты будут действительно испорчены.

Суть: даже не пытайтесь захватывать имена классов. Включить решение, косвенно связанное с Александром . Но замените ваши первоначальные объявления Logger заводскими вызовами. Единственное, что вам нужно захватить, это имя локальной переменной. Затем вам нужно найти, где находится ваш импорт, что, я полагаю, вы можете сделать довольно точно, потому что вы импортируете log4j (или java.util.logging). Найдите это утверждение import и импортируйте ваш завод прямо под ним.

Кстати, все предупреждения, которые вы получаете об автоматизации этого процесса, верны и в равной степени относятся к этому решению. Вам нужно , чтобы быть готовым к javac всему сразу после попытки по крайней мере этого. Действительно, у вас должны быть некоторые тестовые наборы с покрытием кода монстра для автоматического запуска в этот момент.

0 голосов
/ 28 января 2010

Непроверенные:

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 голосов
/ 28 января 2010

Загляни в чекстайл. Вы можете написать пользовательское правило checkstyle, которое делает это. Это будет интересное упражнение в XPath.

Однако, если код очень предсказуемо структурирован, я бы предложил, что это можно сделать в sed. Если вы хотите структурировать вычисления в bash, то ...

  1. используйте exec, чтобы открыть дескриптор файла для файла
  2. цикл с чтением строк
  3. когда вы видите первый оператор 'class', возьмите имя класса.
  4. когда вы увидите конструкцию Logger, возьмите и проверьте.
0 голосов
/ 28 января 2010

вы можете попробовать соткать Logger.getLogger с AspectJ, чтобы определить, соответствует ли параметр Example.class в вашем случае "текущий класс" имя.

Подсказка : вы можете получить "текущий класс" имя программно, используя что-то вроде:

String className = new Exception().getStackTrace()[0].getClassName();
0 голосов
/ 28 января 2010
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...