Log4J: стратегии для создания экземпляров регистратора
Я решил использовать log4j logging framework для нового проекта Java.
Мне интересно, какую стратегию следует использовать для создания/управления экземплярами Logger и почему?
один экземпляр регистратора на класс
например,
class Foo {
private static final Logger log = Logger.getLogger(Foo.class);
}
- один экземпляр регистратора на поток
- один экземпляр регистратора для каждого приложения
- горизонтальная нарезка : один экземпляр регистратора в каждом слое приложения (например, слой представления, контроллер слой и слой персистентности)
- вертикальная нарезка : один экземпляр регистратора в функциональных разделах приложения
Примечание: этот вопрос уже рассматривается в некоторой степени в этих статьях:
что накладные расходы на создание log4j Logger
10 ответов:
Как правило, у вас будут настройки регистраторов для каждого класса, потому что это хороший логический компонент. Потоки уже являются частью сообщений журнала (если ваш фильтр отображает их), поэтому нарезка регистраторов таким образом, вероятно, избыточна.
Что касается регистраторов на основе приложений или слоев, проблема в том, что вам нужно найти место для размещения этого объекта регистратора. Не очень большое дело. Большая проблема заключается в том, что некоторые классы могут использоваться на нескольких уровнях из нескольких приложений... он мог бы трудно получить ваш регистратор право. Или, по крайней мере, сложно.
...и последнее, что вы хотите, это плохие предположения в вашей настройке ведения журнала.
Если вы заботитесь о приложениях и слоях и имеете легкие точки разделения, NDC-это путь. Иногда код может быть немного чрезмерным, но я не знаю, сколько раз я был сохранен точным стеком контекста, показывающим мне, что Foo.bar () был вызван из приложения X в слое Y.
наиболее часто используемая стратегия заключается в создании регистратора для каждого класса. Если вы создаете новые потоки, дайте им полезное имя, поэтому их ведение журнала легко различимо.
создание логгеров для каждого класса имеет то преимущество, что вы можете включать/выключать ведение журнала в структуре пакетов ваших классов:
log4j.logger.org.apache = INFO log4j.logger.com.example = DEBUG log4j.logger.com.example.verbose = ERRORвыше будет установлен весь код библиотеки apache в
INFOуровень, переключите ведение журнала с вашего собственного кода на
Я уверен, что это не лучшая практика, но я уволил некоторое время запуска приложений, прежде чем сохранять строки кода. В частности, при вставке в:
Logger logger = Logger.getLogger(MyClass.class);...разработчики часто забывают изменить "MyClass" на текущее имя класса, и несколько регистраторов всегда указывают на неправильное место. Это Плохо.
Я иногда написано:
static Logger logger = LogUtil.getInstance();и:
class LogUtil { public Logger getInstance() { String callingClassName = Thread.currentThread().getStackTrace()[2].getClass().getCanonicalName(); return Logger.getLogger(callingClassName); } }"2" в этом коде может быть неправильным, но суть там; возьмите хит производительности (при загрузке класса, как статическая переменная) найдите имя класса, чтобы разработчик действительно не мог ошибиться или ввести какую-либо ошибку.
Я вообще не в восторге от потери производительности, чтобы предотвратить ошибки разработчиков во время выполнения, но если это происходит как синглтон, один раз? Часто звучит как хорошая сделка для меня.
Как уже было сказано другими, я бы создал регистратор для каждого класса:
private final static Logger LOGGER = Logger.getLogger(Foo.class);или
private final Logger logger = Logger.getLogger(this.getClass());однако, я нашел это полезным в прошлом, чтобы иметь другую информацию в регистраторе. Например, если у вас есть веб-сайт, вы можете включить идентификатор пользователя в каждое сообщение журнала. Таким образом, вы можете отслеживать все, что делает пользователь (очень полезно для отладки проблем и т. д.).
самый простой способ сделать это-использовать MDC, но вы можете использовать регистратор, созданный для каждый экземпляр класса с именем, включая идентификатор пользователя.
еще одно преимущество использования MDC - если вы используете SL4J, вы можете изменить настройки в зависимости от значений в вашем MDC. Поэтому, если вы хотите зарегистрировать все действия для конкретного пользователя на уровне отладки и оставить всех других пользователей в состоянии ошибки, вы можете. Вы также можете перенаправить различные выходные данные в разные места в зависимости от вашего MDC.
некоторые полезные ссылки:
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html
- создать один регистратор для каждого класса.
- Если у вас есть зависимости, которые требуют Commons Logging (вполне вероятно) используйте slf4j мост для ведения журнала Commons. Создайте экземпляр своих регистраторов (для каждого класса) с помощью интерфейса ведения журнала Commons:
private static final Log log = LogFactory.getLog(MyClass.class);- проявите этот шаблон в своей среде IDE с помощью ярлыков. Я использую идею живые шаблоны для этой цели.
- предоставление контекстной информации для потоков с помощью NDC (поток локальный стек строк) или MDC (локальная карта потока строки → ?).
примеры для шаблонов:
private static final Log log = LogFactory.getLog($class$.class); // live template 'log' if (log.isDebugEnabled()) log.debug(String.format("$string$", $vars$)); // live template 'ld', 'lw', 'le' ...
другой вариант : вы можете попробовать AspectJ поперечная резка при регистрации. Проверьте здесь : Упростить Ведение Журнала. (Если вы не хотите использовать АОП можно смотреть slf4j)
//Without AOP Class A{ methodx(){ logger.info("INFO"); } } Class B{ methody(){ logger.info("INFO"); } } //With AOP Class A{ methodx(){ ...... } } Class B{ methody(){ ...... } } Class LoggingInterceptor{ //Catched defined method before process public void before(...xyz){ logger.info("INFO" + ...xyz); } //Catched defined method after processed public void after(...xyz){ logger.info("INFO" + ...xyz); } ..... }P. S:АОП будет лучше, это сухой(не повторяйтесь) путь.
лучший и самый простой способ создания пользовательских регистраторов, не связанных с каким-либо именем класса:
// create logger Logger customLogger = Logger.getLogger("myCustomLogName"); // create log file, where messages will be sent, // you can also use console appender FileAppender fileAppender = new FileAppender(new PatternLayout(), "/home/user/some.log"); // sometimes you can call this if you reuse this logger // to avoid useless traces customLogger.removeAllAppenders(); // tell to logger where to write customLogger.addAppender(fileAppender); // send message (of type :: info, you can use also error, warn, etc) customLogger.info("Hello! message from custom logger");теперь, если вам нужен другой регистратор в том же классе, нет проблем :) просто создайте новый
// create logger Logger otherCustomLogger = Logger.getLogger("myOtherCustomLogName");теперь смотрите код выше и создайте новый fileappender, чтобы ваш вывод был отправлен в другой файл
это полезно для (по крайней мере) 2 ситуаций
Если вы хотите отделить ошибку от информации и предупреждает
когда вы управляете несколькими процессами и вам нужно выводить данные из каждого процесса
ps. есть вопросы ? не стесняйтесь спрашивать! :)
общее соглашение - это "класс PR регистратора и использовать имя класса в качестве его имени". Это хороший совет.
мой личный опыт заключается в том, что эта переменная регистратора не должна быть объявлена статической, а переменной экземпляра, которая извлекается для каждого нового. Это позволяет структуре ведения журнала обрабатывать два вызова по-разному в зависимости от того, откуда они поступают. Статическая переменная одинакова для всех экземпляров этого класса (в этом загрузчике классов).
также вы должны узнать все возможности с вашим журналированием бэкэнд выбора. У вас могут быть возможности, которых вы не ожидали.
при развертывании нескольких ушей / войн может быть лучше упаковать log4j.jar выше в иерархии загрузчика классов.
т. е. не в WAR или EAR, а в System-classloader вашего контейнера, иначе несколько экземпляров Log4J будут писать в один и тот же файл одновременно, что приведет к странному поведению.
Если ваше приложение следует принципам SOA, для каждой службы A вы будете иметь следующие компоненты:
- Контроллер
- Реализация Сервиса
- Исполнитель
- В Настойчивость
Так что это делает жизнь проще иметь контролер.бревно как услуга.бревно aExecutor.бревно и аперсивность.журнал
Это разделение на основе слоев, поэтому все ваши классы Remoting / REST/SOAP будут писать в aController.журнал
весь ваш механизм планирования, серверная служба и т. д. будут писать в aService.журнал
и все выполнения задач записываются в aExecutor.войти и так далее.
Если у вас есть многопоточный исполнитель, вам может потребоваться использовать накопитель журналов или другой метод для правильного выравнивания сообщений журнала для нескольких потоков.
таким образом, вы всегда будете иметь 4 файла журнала, который не много и не слишком меньше, я говорю вам из опыта этого делает жизнь действительно проще.
Comments