2011-10-02 3 views
18

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

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

ответ

16

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

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, вы можете настроить один Appender в один файл ,

# 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());, и в этом случае добавление регистратора в класс становится срезом и вставкой одной строки. См. Should I declare Log references static or not? (к сожалению, ссылка на wiki-страницу сломана), но также есть хорошее объяснение, но slf4j page. Поэтому используйте нестатические поля, если у вас нет оснований для этого.

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

[*] и я имею в виду много.

+0

Я сделал то, что вы упоминали, но печатаются только журналы в классе Main, журналы других методов не печатаются? как это исправить –

5

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

+0

Где я могу установить «BasicConfigurator.configure();» В классе без основного метода? – stdcall

+0

@Mellowcandle, вам не нужно вызывать 'BasicConfigurator.configure()' в каждом классе. Сделайте это только в своем основном методе класса, который инициализирует ваше приложение, и только если вам нужно. Изменить: ['BasicConfigurator.configure'] (http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/BasicConfigurator.html#configure%28%29) используется для создания установки log4j, когда вам не хватает функционального файла log4j.properties, настроенного с помощью приложений и макетов. –

+0

Что вы имеете в виду? Мне нужно запустить модульные тесты на нескольких классах. когда я должен его запустить? – stdcall

4

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

Например:

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, что упрощает работу с ним.

+0

Где я могу поставить «BasicConfigurator.configure();» В классе без основного метода? – stdcall

+2

@Mellowcandle: Не надо. Используйте файл 'log4j.properties'.Вам просто нужно поместить его в путь класса, и log4j будет использовать его. –

+0

@CameronSkinner Я сделал то, что вы упоминали, но только журналы в классе Main печатаются в консоли, журналы других методов не печатаются, как их исправить? –

1

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

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

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); 
     } 
    } 

} 
Смежные вопросы