Гибкое журналирование с помощью log4j
Log4j – это инструмент для журналирования с открытым исходным кодом, разработанный под эгидой глобального проекта Jakarta Apache. Он представляет собой набор API с помощью которых, разработчики могут вставлять в свой код выражения, которые выводят некоторую информацию (отладочную, информационную, сообщения об ошибках и т.д.), и конфигурировать этот вывод с помощью внешний конфигурационных файлов. В этой статье рассматриваются основные идеи, положенные в данный инструмент, а также будут затронуты некоторые интересные моменты, касающиеся написания демонстрационного web-приложения.
Программа, использованная в этой статье в качестве примера, представляет собой web-приложение, которое было разработано и протестировано с помощью JDK 1.3.1, Tomcat 4.0.1 (http://jakarta.apache.org/tomcat), log4j 1.2.4 (http://jakarta.apache.org/log4j) и Ant 1.4.1 (http://jakarta.apache.org/ant). Вся работа выполнялась на компьютере с установленной операционной системой Windows XP. Вы можете загрузить файл приложения log4jdemo.war (http://java.linux.by/bible-arc/log4jdemo.war), которое можно легко развернуть в любом сервлет-контейнере. Вы также можете загрузить исходный код этого приложения (http://java.linux.by/bible-arc/log4jsrc.zip).
Наше приложение содержит следующие ветки, очень часто встречающиеся во многих web-приложениях:
- Основная страница -> Авторизированный вход -> Страничка приветствия -> Отправление комментария
- Основная страница -> Регистрация -> Авторизированный вход
- Основная страница -> Страничка для тех, кто забыл пароль
Очень важно, чтобы вы понимали, что данное приложение является очень тривиальным. Единственная его цель в этой статье – это помочь вам научиться работать с log4j. Вы вправе спросить, почему было выбрано именно web-приложение, а не обычное Java-приложение. Все просто. На сегодняшний день очень многие web-приложения используют предпочтительно механизм журналирования именно на основе log4j. В свою очередь среди обычных Java-приложений процент несколько ниже, но популярность log4j стремительно растет, что не удивительно.
Настройка
Загрузить log4j можно с сайта Apache: http://jakarta.apache.org/log4j/docs/download.html. На сайте вам будет предложено выбрать один из двух типов форматов архива с log4j – это tar.gz (http://jakarta.apache.org/log4j/jakarta-log4j-1.2.4.tar.gz) и zip (http://jakarta.apache.org/log4j/jakarta-log4j-1.2.4.zip). Каждый из этих архивов содержит в себе исходный код log4j, документацию, примеры и непосредственно дистрибутивные .jar-архивы log4j. Распакуйте загруженный вами архив в какую-нибудь директорию по вашему выбору. Исходный код поставляется для того, если вы вдруг захотите скомпилировать и собрать log4j самостоятельно. Эту операцию вы можете провести с помощью Ant и, предоставляемых вместе с исходниками, файлов build.xml. Если потребуется, вы можете легко изменить эти скрипты (build.xml). После компиляции и сборки, вы получите файл log4j-1.2.4.jar, который будет находиться в директории dist/lib. Учтите, что успешной сборки вам понадобится Java Management Extensions (JMX) API, который должен быть прописан в переменной окружения CLASSPATH.
Чтобы использовать классы log4j в своем приложении, вам необходимо добавить в CLASSPATH вашего приложения файл log4j-1.2.4.jar. Этот файл, как уже было упомянуто ранее, находится в директории dist/lib. В случае с нашим примером web-приложения, необходимо чтобы этот файл располагался внутри .jar-архива этого приложения, в директории WEB-INF/lib. Это все что необходимо, чтобы наше приложение могло работать с log4j API. Остальные усилия нужно приложить лишь для написания конфигурационного файла, который будет определять для log4j что, куда и как нужно журналировать, а также для вставки выражений в код самого приложения, которые непосредственно будут журналировать события.
Что такое Logger?
Прежде чем приступить к рассмотрению кусков кода нашего web-приложения, давайте разберем основные понятия в log4j. Log4j имеет три базовые составляющие: logger (журналирующий элемент), appender (элемент, определяющий куда нужно журналировать) и layout (представление в котором будет производится журналирование). Для удобства мы так и будем их называть на протяжении всей статьи. Logger берет на себя функцию журналирования какого-либо события в место назначения, определяемое элементом appender, в специально определенном формате, который задается элементом layout.
Logger можно представлять себе, как компонент некого приложения, который будет принимать и выполнять ваши запросы на запись каких-либо событий в регистрационный журнал, представленный файлом, базой данных, консолью и т.д. (определяется appender’ом). Каждый класс вашего приложения может иметь свой собственный logger или же быть привязанным к общему logger’у. Log4j предусматривает корневой logger, от которого будут наследоваться все создаваемые вами объекты этого типа. Это значит, что если у вас не предусмотрен для каждого объекта свой logger, то вы всегда сможете воспользоваться корневым, с помощью метода Logger.getRootLogger(), однако так поступать не рекомендуется.
Для того чтобы создать logger и использовать его для журналирования каких-либо событий, возникающих в этом классе, вам в самом просто случае необходимо вызвать статический метод класса Logger, который получит за вас этот объект по указанному имени. Если такой объект на данный момент еще не существует, он будет создан. Но нужно учесть, что в любой момент времени может существовать только один экземпляр объекта logger’а с одним и тем же именем.
Logger’ы обязательно должны знать куда им нужно слать ваши запросы на запись событий. Эта функция ложится непосредственно на плечи элементов appender. Log4j поддерживает запись в файлы (FileAppender), на консоль (ConsoleAppender), в базы данных (JDBCAppender), в журнал событий операционных систем семейства Windows NT/2000/XP (NTEventLogAppender), на SMTP-сервера (SMTPAppender), на удаленные сервера (SocketAppender) и не только. Таким образом, понятно, что appender определяет место, куда нужно журналировать события. Так, например, если мы привяжем JDBCAppender к одному из наших logger’ов, это будет означать для log4j, что все запросы на журналирование событий, поступающих от этого logger’а, будут записываться в определенную базу данных с заданными параметрами (URL, имя пользователя, пароль и т.д.). Эти параметры являются свойствами объектов элементов типа appender (в данном случае JDBCAppender).
Итак, logger’ы и appender’ы занимаются созданием и направлением наших запросов на журналирование. А что насчет формата вывода? Тут в игру вступают элементы layout. Эти элементы определяют стиль и содержание выводимых в журнал записей. Log4j предоставляет несколько предопределенных layout’ов. Однако вы можете без проблем создать свой собственный, если возникнет такая необходимость. Элемент layout может определять включать или не включать в выводимые записи дату и время, включать ли информацию об используемом для вывода объекте logger, включать или нет информацию о номере текущей строки, в которой был создан этот запрос на журналирование и т.д.
Все элементы logger следуют шаблону отношений типа родитель-потомок. Как упоминалось ранее, log4j предусматривает по умолчанию корневой элемент logger. Отношение типа родитель-потомок также соответствует шаблону именования классов. Это подразумевает, что абсолютно все наши элементы logger будут наследовать корневой элемент. Отношения типа родитель-потомок хорошо просматриваются в шаблоне именования классов. Скажем, у вас есть класс MyClass, который находится в пакете с именем com.foo.bar. Теперь создадим экземпляр элемента logger с именем com.foo.bar.MyClass. В этом случае, logger с именем com.foo.bar.MyClass будет потомком logger’а com.foo.bar, если такой существует. Если же он не существует, то родителем logger’а com.foo.bar.MyClass будет считаться корневой элемент logger (это конечно в случае, если не существует также logger’ов с именами com.foo и com).
Каждому элементу logger в log4j привязывается свой уровень. Если такой уровень не будет привязан к какому-нибудь конкретному элементу, то этот элемент будет автоматически приобретать уровень своего родителя. Даже в случае, если пользователь совсем не будет присваивать никаких уровней, создаваемым им элементам logger, они будут иметь уровень корневого элемента, который по умолчанию равен DEBUG. Таким образом, каждый элемент logger будет гарантированно иметь определенный уровень.
Log4j предусматривает пять уровней журналирования:
- DEBUG
- INFO
- WARN
- ERROR
- FATAL
Эти уровни определяют также порядок журналирования, которому следует log4j. Об этом ниже.
Каким образом установленный для элемента logger уровень влияет на его функциональность? Все просто. Дело в том, что запрос на занесение в журнал какого-либо события, с помощью определенного элемента appender, из нашего приложения будет выполнен лишь в том случае, если уровень журналируемого события (запроса) не ниже, чем уровень самого элемента logger, через который этот запрос был создан. Это означает, что все запросы, которые мы можем создавать в нашем приложении, могут быть только какого-то одного из этих пяти уровней. Это очень важное правило и, фактически, это является ядром функциональности log4j. Давайте вернемся к нашему предыдущему примеру com.foo.bar.MyClass и попробуем более подробно рассмотреть все, о чем сейчас говорилось.
Предположим в пределах класса com.foo.bar.MyClass (мы назвали класс и logger для этого класса одним и тем же именем – это обычная практика для программистов, использующих log4j), используя его logger, вы пытаетесь журналировать некоторое сообщение типа WARN. Теперь, скажем, ваш logger com.foo.bar.MyClass имеет уровень ERROR, который был установлен вами при конфигурации. Что это означает? Это означает, что ваш запрос на журналирование, типа WARN, выполнен не будет.
Почему? Потому что log4j определяет, что уровень запроса на журналирование ниже, чем уровень самого logger’а, через который этот запрос был сделан. Если бы этот запрос имел уровень ERROR или FATAL, то он без проблем был бы выполнен, и сообщение заняло бы свое место в регистрационном журнале, согласно используемому элементу appender. Аналогично, если бы уровень logger'а был WARN, то этот запрос также был бы выполнен. Итак, мы пришли к очень важной идее, заложенной в log4j. Вы можете извне менять уровень каждого из ваших элементов logger без необходимости вносить какие-либо изменения в исходный код приложения, без необходимости перекомпилировать приложение и разворачивать ее заново.
Основное конфигурирование log4j происходит посредством внешнего конфигурационного файла. API также предоставляет возможность конфигурировать систему log4j и из приложения. Далее мы рассмотрим простой пример приложения и посмотрим, как правильно создавать конфигурационный файл.
Пример использования log4j
Приложение, которое мы собрались рассматривать в качестве примера, содержит пять сервлетов (SetupServlet (стартует при запуске сервлет-контейнера), LogonServlet, GetCommentsServlet, ForgotPasswordServlet, RegisterServlet), четыре JSP-страницы (forgotpassword, logon, register, welcome), а также базу данных в виде файла, в которой хранится информация о пользователях (файл userDB, который должен располагаться в директории WEB-INF; убедитесь, что путь к нему корректно прописан в конфигурационном файле web.xml).
Чтобы увидеть это приложение в действии, разверните файл log4jdemo.war в вашем сервлет контейнере. Как только вы это сделали, измените файл web.xml таким образом, чтобы параметр init сервлета SetupServlet для файла props содержал путь к файлу config-simple.properties. Этот файл находится в директории WEB-INF нашего приложения (там также содержатся три других конфигурационных файла: config-JDBC, config-MDC, config-NDC). Теперь перезапустите ваш сервер (в данном случае имеется в виду сервлет-контейнер). На консоли вашего сервера появятся некоторые сообщения. Если SetupServlet смог найти файл userDB, то вы, возможно, увидите следующие сообщения:
Using properties file:
C:\jakarta-tomcat-4.0.1\webapps\Log4JDemo\WEB-INF\config-simple.properties
Watch is set to: null
DEBUG - Added line: JohnDoe,herbert,johndoe@john.com,John Doe
Первые два выражения, появившиеся на вашем экране, представляют собой простой вывод с помощью выражений System.out.println. Следующие же два сообщения были выведены с помощью log4j. Давайте посмотрим, как это было сделано в программе.
Откройте файл config-simple.properties в вашем любимом текстовом редакторе. Этот файл содержит всего три строчки (не считая комментариев). Первая строка (log4j.rootLogger=debug, R) сообщает log4j, что уровень корневого элемента logger будет DEBUG. Такой уровень для корневого элемента устанавливается по умолчанию, и поэтому эта строчка не обязательна. Однако значение после запятой (R) является обязательным. Оно сообщает log4j, что корневой элемент logger должен быть привязан к элементу appender с именем “R”. Оставшиеся строки в этом файле определяют свойства этого appender’а R.
Строка log4j.appender.R=org.apache.log4j.ConsoleAppender говорит о том, что appender R имеет тип ConsoleAppender; т.е. это означает, что вывод будет производиться на консоль. Строка log4j.appender.R.layout=org.apache.log4j.SimpleLayout сообщает log4j, что для appender’а R будет использоваться простой элемент layout, который, как вы могли заметить, просто выводит две вещи: имя уровня запроса на журналирование и непосредственно само сообщение.
Теперь, когда мы разобрались с простым примером конфигурационного файла, самое время посмотреть, как происходит журналирование в самом коде приложения. Для начала откройте файл SetupServlet.java в текстовом редакторе и найдите 81 строку:
PropertyConfigurator.configure(props);
Пока не обращайте внимания на выражения, находящиеся рядом с этой строкой. Эта строчка сообщает log4j, что требуется найти файл, определенный переменной props и использовать его для установки настроек log4j. Это и есть тот самый файл, который мы только что с вами разобрали, config-simple.properties. Это строка должна выполняться только один раз за всю работу цельного приложения. Обычно она вызывается при старте приложения, а сервлет, вызываемый при старте сервлет-контейнера – это идеальное место для выполнения этого конфигурирования в web-приложении.
Как только мы выполнили все операции по конфигурированию log4j, можно приступать непосредственно к журналированию. Следующим шагом необходимо получить или создать нужный logger, и уже потом с его помощью вставлять в код программы выражения для вывода сообщений в регистрационный журнал. Это можно сделать либо с помощью корневого элемента logger, вызвав метод Logger.getRootLogger(), либо же попытаться взять logger класса, в котором мы сейчас находимся (т.е. из которого хотим журналировать какое-либо событие), в нашем случае – это SetupServlet. В случае второго варианта мы получим logger с именем demo.log4j.servlet.SetupServlet, выполнив следующую строчку кода:
Logger log = Logger.getLogger(SetupServlet.class);
С помощью этой строчки кода мы получаем объект класса Logger, с помощью которого можно посылать запросы на журналирование событий. Так, например, в строке с номером 112 мы вызываем DEBUG-метод этого logger’а: log.debug("Added line: " + data);. Это и есть то сообщение, которое мы недавно наблюдали на консоли. Заметьте, что, поскольку наш конфигурационный файл установил уровень для корневого элемента logger в DEBUG, мы не озадачиваем себя установкой какого-либо уровня для нашего logger’а с именем demo.log4j.servlet.SetupServlet, поскольку он наследует этот уровень от корневого элемента. Так, когда мы выполняем операцию log.debug("Added line: " + data); в пределах нашего класса, этот запрос на журналирование сообщения посылается appender’у (ConsoleAppender). Теперь попробуйте изменить уровень корневого элемента logger на ERROR. В этом случае строчки, которые ранее выводились, теперь не появляются, поскольку уровень logger’а стал выше, чем уровень самого запроса. Также заметьте, что для того, чтобы изменить уровень корневого элемента logger, нужно всего лишь модифицировать конфигурационный файл и перезапустить сервлет-контейнер (хотя это не обязательно, позже мы поговорим о том, как можно не перегружать сервер, используя ConfigureAndWatch).
На этом мы завершим рассмотрение нашего примера. Давайте еще раз вспомним, что нужно для того, чтобы начать пользоваться log4j в нашем простом примере:
1. Написать конфигурационный файл. В этом файле:
- Определить уровень корневого элемента logger и привязать его к appender’у.
- Определить свойства appender’а.
- Определить layout для этого appender’а.
3. Начать журналирование с помощью методов: log.debug(), log.info(), log.warn(), log.error(), log.fatal().
Хоть мы и рассмотрели пример web-приложения, в котором для журналирования использовался log4j, и вы, надеюсь, увидели его мощь и функциональность, однако наше приложение слишком простое, чтобы предоставить хоть сколько-то полноценный обзор возможностей log4j. Например:
- Журналирование на консоль не всегда является хорошим ходом, поскольку требует от пользователя, чтобы тот постоянно наблюдал за происходящим на экране, чтобы отследить сообщения уровня ERROR и FATAL.
- SimpleLayout, который мы использовали слишком прост и предоставляет минимум информации.
- В web-приложениях разные пользователи, обращаясь к различным сервлетам, будут генерировать всевозможные сообщения в регистрационный журнал, каждый свои. И это значительно затрудняет идентифицировать, разделить и изолировать сообщения, поступающие от разных пользователей приложения.
Давайте посмотрим, как мы можем решить эти проблемы с помощью log4j. Не будем долго останавливаться на втором пункте, поскольку это довольно просто, заменить SimpleLayout на PatternLayout и определить специальный шаблон для формата вывода сообщений. Для этого достаточно обратиться к документации Javadoc по классу PatternLayout, поставляемой вместе с дистрибутивом log4j, чтобы узнать обо всех существующих шаблонах и способах их задания.
Дополнительные возможности
JDBCAppender
Сейчас мы попробуем журналировать наши сообщения куда-нибудь иначе, чем просто на консоль. Поскольку с недавних пор журналирование в базы данных стало заметно популярнее, давайте попробуем модифицировать наш пример для записи сообщений в базу данных. Для тестирования примера использовался сервер управления базами данных MySQL, но этот пример должен работать с любым другим сервером, поскольку мы целиком и полностью придерживались технологии JDBC. Главное, чтобы для этого сервера баз данных был подходящий JDBC-драйвер. Одно маленькое замечание по поводу использования JDBCAppender в текущей версии log4j: в документации сказано, что данный appender, в будущих версиях будем полностью заменен целиком переработанной новой версией. Однако не стоит беспокоиться. Хотя внутренняя часть может быть кардинально изменена, но интерфейс работы с этим appender’ом измениться не должен.
Итак, давайте начнем с того, что откроем файл config-JDBC.properties из нашего приложения. Первое выражение, которое встречается в этом файле, не должно быть вам незнакомым. Так же как и в случае с простым приложением, которое мы рассмотрели ранее, мы устанавливаем уровень корневого элемента logger в DEBUG, и привязываем его к appender’у R. Следующие несколько строчек определяют R, как объект класса JDBCAppender и объявляют его свойства:
log4j.appender.R=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.R.URL=jdbc:mysql://localhost/LOG4JDemo
log4j.appender.R.user=default
log4j.appender.R.password=default
log4j.appender.R.sql=INSERT INTO JDBCTEST (Message) VALUES ('%d - %c - %p - %m')
Первая строчка сообщает log4j о том, что R – это JDBCAppender. Вторая строка определяет URL к базе данных, в которую мы хотим записывать сообщения. Строки третья и четвертая задают имя пользователя и пароль для доступа к этой базе данных. Последняя строка – это SQL-запрос, который будет выполняться при записи сообщений. Об этом мы поговорим поподробнее чуть позже.
Разработчики, которым раньше доводилось работать с JDBC, сразу заметят схожесть между значениями, которые задаются в этом конфигурационном файле и общими параметрами при соединении с базой данных в нормальном JDBC. Это те значения, которые вы должны обязательно задать в любом нормально JDBC-приложении. Вы, безусловно, можете изменить эти значения так, как вам будет нужно. Например, если вы планируете соединяться с сервером баз данных Oracle, то в этом случае URL будет иметь вид, например вот такой: jdbc:oracle:thin:@yourhostSID. Помимо этого нельзя забывать о том, что эти драйвера (JDBC-драйвера к конкретным СУБД) должны быть доступны вашему приложению, чтобы log4j мог корректно выполнять возложенные на него функции.
Давайте более подробно рассмотрим последнее выражение этого конфигурационного файла. SQL-выражение, которое вы используете для журналирования сообщений в базу данных, может изменяться, согласно вашим потребностям. То выражение, которое использовалось в примере конфигурационного файла, записывает в таблицу JDBCTEST следующие данные: дату (%d), logger (%c), приоритет (%p), само сообщение (%m). Все эти данные объединяются в строку в определенном формате и записываются в поле Message. Log4j берет это выражение и пропускает его через специальный фильтр, который, применяя layout специально для этого appender’а, заменяет формальные параметры (%d, %c, %p, %m и пр.) на действительные значения. После чего, log4j просто выполняет отформатированный SQL-запрос.
Если необходимо, вы можете записывать разные значение в разные поля. Например, как в данном выражении:
INSERT INTO JDBCTEST (Date, Logger, Priority, Message) VALUES ('%d', '%c', '%p', '%m')
Это означает, что в нашей базе данных, мы должны определить таблицу JDBCTEST, которая будет содержать поля Date, Logger, Priority и Message.
После всего этого вы еще раз должны были убедиться, что для того, чтобы перенаправить запись сообщений в базу данных, абсолютно не нужно изменять какой-либо код приложения. Мы просто меняем конфигурационные файлы или редактируем параметры старого файла для того, чтобы журналирование шло не на консоль, а в таблицу JDBCTEST нашей базы данных.
NDC/MDC
Nested Diagnostic Context (NDC) и Mapped Diagnostic Context (MDC) помогают в ситуациях, когда одно приложение вынуждено обслуживать одновременно несколько клиентов, и вы заинтересованы в том, чтобы разделить содержание журнала сообщений или хотя бы иметь возможность различать, при каком из пользователей было записано сообщение. Web-приложение – это великолепный пример для такой ситуации.
Так каким образом мы сможем различать наших пользователей? Очень просто, мы будем записывать специфичную для каждого из клиентов информацию. Например, в случае с web-приложением, можно включить, помимо прочих вещей, IP-адрес, который всегда можно получить из сервлета. В NDC вы кладете эту информацию в стек, при входе в контекст, и удаляете (получаете) ее из стека при выходе из этого же контекста. Log4j заменяет шаблон %x на специфичную для контекста информацию при записи в свой appender. Этот шаблон нужно использовать в связанном с appender’ом layout’е. Чтобы посмотреть, как это работает, давайте обратимся к конфигурационному файлу config-NDC.properties и файлу GetCommentsServlet.java.
В конфигурационном файле config-NDC вы можете видеть заметные различия по сравнению с предыдущими. Во-первых, в нем определено несколько logger’ов. Первые несколько строк схожи со строками файла config-simple. Для всех остальных logger’ов в нашем приложении, кроме того, который связан с классом GetCommentsServlet, мы хотим, чтобы вывод был связан с консолью и представлен простым layout’ом (SimpleLayout). Для logger’а с именем demo.log4j.servlet.GetCommentsServlet нам нужно иметь свой appender (R1), который также будет выводить информацию на экран, но помимо этого, его шаблон будет содержать символ %x.
log4j.logger.demo.log4j.servlet.GetCommentsServlet=debug, R1
...
log4j.appender.R1.layout.ConversionPattern=%p - [%x] - %m%n
Обратите внимание, как мы ссылаемся на logger GetCommentsServlet. На все logger’ы (кроме rootLogger, который обычно именуется как log4j.rootLogger) можно ссылаться при помощи log4j.logger.<имя logger’а>. Такого типа именование подходит для большинства элементов log4j.
Теперь обратимся к исходному коду класса GetCommentsServlet. Именно в этом классе мы может посмотреть, как реализована работа с добавлением и удалением уникальной информации о клиенте из стека NDC.
А сейчас посмотрите на строки 40 и 57. В строке 40 мы заносим уникальную информацию о клиенте в стек. Теперь любое выражение, которое выполняет журналирование сообщения, будет содержать эту информацию, вставляя ее вместо шаблона %x. Строкой 57, мы удаляем эту информацию из стека. Таким образом, мы можем записывать сообщения, по которым не составит труда узнать, какой именно клиент повлек за собой запись данной информации в журнал.
Теперь давайте поговорим немного о Mapped Diagnostic Context (MDC). MDC очень многим похож на NDC, но с той лишь разницей, что вместо записи и удаления информации о клиенте из стека, она сохраняется в структуре Map (java.util.Map). Это подразумевает, что каждый кусок специфичной для клиента информации должен сопровождаться каким-либо уникальным ключом. Если вы посмотрите на строку 43 в файле GetCommentsServlet.java, вы увидите, как это реализовано.
MDC.put("RemoteHost", remHost);
Класс MDC предоставляет статический метод для манипулирования специфичной для каждого из клиентов информацией. Таким образом, с каждый выражением для записи в журнал какого-либо сообщения, эта информация соответствующая RemoteHost будет заменять шаблон MDC, который имеет вид %X{key}. Что такое key? В нашем случае key мы ассоциируем со значением remHost, которое мы добавляем в Map, под именем RemoteHost. Если, например, мы хотим добавить RemoteAddress к нашему выводу, то можно написать следующее:
В исходном коде:
MDC.put("RemoteAddress", req.getRemoteAddr());
А в конфигурационном файле добавить следующее:
%X{RemoteAddress}
Пример такого конфигурационного файла вы можете найти в файле config-MDC.properties. Хоть он и схож с файлом config-NDC.properties, но имеет два очень важных отличия. Во-первых, мы используем MDC вместо NDC, а во-вторых, appender для нашего второго logger’а – это RollingFileAppender, вместо ConsoleAppender.
Несколько советов напоследок
Первый совет, который окажет вам неоценимую помощь и даст не одну тысячу советов, особенно если вы собираетесь стать постоянным пользователем log4j – это подписаться на лист рассылки посвященный log4j. Архив всех сообщений вы можете найти на сайте http://www.mail-archive.com/log4j-user@jakarta.apache.org. Подписаться же на сам лист рассылки можно, послав письмо по адресу log4j-user-subscribe@jakarta.apache.org.
ConfigureAndWatch: Вы уже должны знать, что после того, как вы внесли изменения в конфигурационный файл, чтобы эти изменения вступили в силу, необходимо перезапустить сервлет-контейнер. Но это иногда бывает очень обременительно и неудобно. Lo4j предоставляет механизм, с помощью которого он может постоянно отслеживать изменения в конфигурационном файле из вашего приложения. Для того чтобы воспользоваться этой возможностью замените выражение PropertyConfigurator.configure(props); на PropertyConfigurator.configureAndWatch(props);, которое использует значение по умолчанию (60 секунд) в качестве промежутка времени, по истечению которого, нужно проверить, не изменился ли конфигурационный файл. Естественно, что вы без проблем можете изменить это значение, если вам это понадобится.
Заключение
Log4j – это популярный инструмент для журналирования проекта Apache Project. Помимо него существует еще и другие инструменты для журналирования, включая специальный API, встроенный в JDK 1.4. Однако log4j является признанным лидером среди всех существующих инструментов, поскольку позволяет поддерживать беспрецедентный контроль над всеми аспектами журналирования, помимо этого он является иерархическим. Он предоставляет контроль во время выполнения приложения над процессом журналирования, без необходимости вносить какие-либо изменения в исходный код приложения.