Подтвердить что ты не робот

Как использовать log4j с несколькими классами?

В настоящее время я пишу большой проект в java, с многочисленными классами, некоторые классы тихие, небольшие, которые просто представляют объекты только с несколькими методами. У меня есть логгер, установленный в моем основном классе, и он отлично работает. Я хочу иметь возможность использовать только один регистратор (с одним консольным приложением) со всеми классами. Я попытался передать ссылку на регистратор на разные классы, но это выглядит неправильно. Кроме того, иногда я запускаю тесты классов без запуска main, и поэтому регистратор не инициализируется для других классов.

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

4b9b3361

Ответ 1

Если я правильно понимаю, то, что у вас есть в данный момент:

public class Main {
    public static final Logger LOGGER = Logger.getLogger(Main.class);
}

public class AnotherClass {
    public void doSomething() {
        Main.LOGGER.debug("value=" + value);
    }
}

или вы передаете ссылки на регистратор в конструкторы класса.

Во-первых, вы можете использовать один глобальный регистратор, просто используя то же значение, которое передается в Logger.getLogger, например:

public class Main {
    private static final Logger LOGGER = Logger.getLogger("GLOBAL");
}

public class AnotherClass {
    private final Logger LOGGER = Logger.getLogger("GLOBAL");

    public void doSomething() {
        LOGGER.debug("value=" + value);
    }
}

Это использует точно такой же журнал, Logger.getLogger возвращает один и тот же объект в обоих вызовах. У вас больше нет зависимости между классами, и это будет работать.

Другая вещь, которую я собираю из ваших комментариев, заключается в том, что вы настраиваете вручную (используя BasicConfigurator.configure. В большинстве случаев это необязательно, и вы должны выполнять свою конфигурацию, просто добавляя log4j.properties или log4j.xml к вашему пути к классам. В Eclipse это делается путем добавления его в src/(или src/main/resources, если вы используете maven). Если вы используете junit, добавьте его в каталог test/source (или src/test/resources с maven). Это гораздо лучший долгосрочный способ настройки log4j, потому что вам не нужно передавать информацию между классами.

Кроме того, рекомендуется использовать класс Logger.getLogger() для использования журналов. Таким образом, вы можете фильтровать свой результат на основе имени класса, который обычно намного полезнее, чем просто один глобальный регистратор:

public class Main {
    private static final Logger LOGGER = Logger.getLogger(Main.class);
    public static final main(String[] args) {
        LOGGER.debug("started");
    }
}

public class AnotherClass {
    private final Logger LOGGER = Logger.getLogger(this.getClass());

    public void doSomething() {
        LOGGER.debug("value=" + value);
    }
}

Затем в log4j.properties вы можете настроить одно приложение в один файл.

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

Наконец, нет необходимости объявлять все ваши регистраторы статическими. Это только делает заметную разницу, если вы делаете много [*] создания объекта. Объявление ваших регистраторов как нестатических полей позволяет использовать Logger.getLogger(this.getClass());, и в этом случае добавление регистратора в класс становится вырезанием и вставкой одной строки. См. Должен ли я объявлять записи журналов статическими или нет? (к сожалению, ссылка на страницу wiki сломана), но slf4j page содержит также хорошее объяснение. Поэтому используйте нестатические поля, если у вас нет оснований для этого.

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

[*], и я имею в виду партии.

Ответ 2

Обычно ваши экземпляры журналов должны быть private, static и final. Таким образом, каждый класс будет иметь свой собственный экземпляр журнала (который создается после загрузки класса), чтобы вы могли идентифицировать класс, в котором была создана запись журнала, а также вам больше не нужно передавать экземпляры журнала в классах.

Ответ 3

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

Например:

class A {
    private static final Logger log = Logger.getLogger(A.class);
}

class B {
    private static final Logger log = Logger.getLogger(B.class);
}

Затем ваши log4j.properties могут выглядеть как пример в документации log4j:

# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=DEBUG, A1

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

Оба A и B будут регистрироваться в корневом журнале и, следовательно, в том же приложении (в данном случае в консоли).

Это даст вам то, что вы хотите: каждый класс является независимым, но все они записываются в тот же журнал. Вы также получаете бонусную функцию, которую вы можете изменить уровень ведения журнала для каждого класса в конфигурации log4j.

Как вариант, вы можете рассмотреть возможность перехода на slf4j, если проект все еще находится в раннем развитии. slf4j имеет некоторые улучшения по сравнению с log4j, что упрощает работу с ним.

Ответ 4

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

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

final public class Logger {
    private static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger("Log");

    enum Level {Error, Warn, Fatal, Info, Debug}

    private Logger() {/* do nothing */};

    public static void logError(Class clazz, String msg) {
        log(Level.Error, clazz, msg, null);
    }

    public static void logWarn(Class clazz, String msg) {
        log(Level.Warn, clazz, msg, null);
    }

    public static void logFatal(Class clazz, String msg) {
        log(Level.Fatal, clazz, msg, null);
    }

    public static void logInfo(Class clazz, String msg) {
        log(Level.Info, clazz, msg, null);
    }

    public static void logDebug(Class clazz, String msg) {
        log(Level.Debug, clazz, msg, null);
    }


    public static void logError(Class clazz, String msg, Throwable throwable) {
        log(Level.Error, clazz, msg, throwable);
    }


    public static void logWarn(Class clazz, String msg, Throwable throwable) {
        log(Level.Warn, clazz, msg, throwable);
    }

    public static void logFatal(Class clazz, String msg, Throwable throwable) {
        log(Level.Fatal, clazz, msg, throwable);
    }

    public static void logInfo(Class clazz, String msg, Throwable throwable) {
        log(Level.Info, clazz, msg, throwable);
    }

    public static void logDebug(Class clazz, String msg, Throwable throwable) {
        log(Level.Debug, clazz, msg, throwable);
    }

    private static void log(Level level, Class clazz, String msg, Throwable throwable) {
        String message = String.format("[%s] : %s", clazz, msg);
        switch (level) {
            case Info:
                logger.info(message, throwable);
                break;
            case Warn:
                logger.warn(message, throwable);
                break;
            case Error:
                logger.error(message, throwable);
                break;
            case Fatal:
                logger.fatal(message, throwable);
                break;
            default:
            case Debug:
                logger.debug(message, throwable);
        }
    }

}