log4j широкоизвестная библиотека логирования, нашедшая своё применение во многих проектах. Её возможности не ограничиваются «добавлением строчек в лог-файлы». На базе log4j можно организовать сложную систему агрегации логов на центральный сервер. Кроме того, сообщество располагает GUI утилитами для анализа логов, которые удобно подключать к центральному серверу для анализа логов.
Когда в компании появляется несколько серверов или россыпь разнообразных приложений логирующих данные в разные файлы, становится крайне не удобным отслеживать все события происходящие в приложениях. Иногда это становится не возможным ввиду отсутствия прав доступа к тому или иному серверу. Именно в таких системах возникает необходимость агрегирования данных на одном центральном сервере. Рассмотрим наиболее простой способ реализации такой системы с использованием библиотеки log4j.
log4j
Интеграция log4j в Java проект чрезвычайна проста. Нужно подключить саму библиотеку и создать файл конфигуарции log4j.properties или log4j.xml. Если рассматривать maven проект, то его конфигурация будет примерно следующая.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.github.caiiiycuk</groupId> <artifactId>log4j-app</artifactId> <version>1.0</version> <name>log4j app</name> <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> </dependencies> </project>
import org.apache.log4j.Logger;
public class Log4JApp {
private final static Logger LOGGER = Logger.getLogger(Log4JApp.class);
public static void main(String[] args) throws InterruptedException {
while (true) {
LOGGER.debug("I'm doing science and I'm still alive.");
LOGGER.info("I feel fantastic and I'm still alive.");
LOGGER.warn("While you're dying I'll be still alive.");
LOGGER.error("And when you're dead I will be, still alive.");
LOGGER.fatal("Still alive, still alive.");
Thread.sleep(1000);
}
}
}
log4j.rootLogger=debug, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Шаблон лог сообщения log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
Файл log4j.properties должен находиться в classpath, что бы log4j смог обнаружить его. Возможно явно указать расположения файла конфигурации с помощью аргумента командной строки java -Dlog4j.configuration=pathToFile, подробнее о конфигурации log4j.
В log4j есть понятие appender, он определяет обработчиков событий, в примере мы использовали стандартный ConsoleAppender который логирует все события в консоль. По счастью в стандартный набор входят так же SocketAppender и SocketHubAppender.
SocketAppender создаёт подключение к удаленному лог серверу и отправляет события на этот сервер. Причем посылаются сериализованные LoggingEvent, т. е. передаётся вся информация о событии а не строка. В случае если удалённый сервер не доступен, сообщения будут отбрасываться, когда же сервер заработает вновь соеденение будет востановленно автоматически.
SocketHubAppender похож на SocketAppender, но работает наоборот. SocketHubAppender создаёт сокет на который могут подключаться удалённые клиенты и при возникновении событий они отправляются всем подключенным клиентам.
Что бы настроить log4j на работу с удалённым сервером в конфигурацию нужно добавить следующее:
log4j.rootLogger=DEBUG, stdout, server (...) log4j.appender.server=org.apache.log4j.net.SocketAppender log4j.appender.server.Port=4560 log4j.appender.server.RemoteHost=localhost log4j.appender.server.ReconnectionDelay=10000 log4j.appender.server.Application=Log4JApp log4j.appender.server.LocationInfo=true
- Port — порт сервера на который посылать события, по умолчанию 4560
- RemoteHost — хост сервера на который посылать события
- ReconnectionDelay — интервал ожидания для переподключения
- Application — имя приложения генерирующего логи
- LocationInfo — включать ли информацию о расположении
С такими настройками приложение будет пытаться подключится к localhost:4560 для отправки лог сообщений. Теперь, настало время настроить сервер который будет агрегировать сообщения. Такой сервер можно запустить одной командой.
java -classpath log4j.jar org.apache.log4j.net.SimpleSocketServer 4560 log4j-server.properties
Первый параметр это порт сервера, а второй конфигурация логера сервера. Все сообщения которые поступают на сервер будут обрабатываться так, как будто сам сервер сгенерировал эти события, т.е. так как вы сконфигурируете log4j-server.properties так и будут сообщения выводиться. Так можно организовывать сложные цепочки пересылки сообщения от сервера к серверу.
Если одновременно запустить сервер и клиент, то в консоле сервера будут печататься все сообщения которые произошли на клиенте (при условии что вы добавили ConsoleAppender).
log4j.rootLogger=debug, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout # Шаблон лог сообщения log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n
Вывод в консоль
INFO [main] (SimpleSocketServer.java:60) - Listening on port 4560 INFO [main] (SimpleSocketServer.java:63) - Waiting to accept a new client. INFO [main] (SimpleSocketServer.java:65) - Connected to client at /127.0.0.1 INFO [main] (SimpleSocketServer.java:66) - Starting new socket node. INFO [main] (SimpleSocketServer.java:63) - Waiting to accept a new client. DEBUG [main] (Log4JApp.java:9) - I'm doing science and I'm still alive. INFO [main] (Log4JApp.java:10) - I feel fantastic and I'm still alive. WARN [main] (Log4JApp.java:11) - While you're dying I'll be still alive. ERROR [main] (Log4JApp.java:12) - And when you're dead I will be, still alive. INFO [SimpleSocketServer-4560] (SocketNode.java:94) - Caught java.io.EOFException closing conneciton.
Анализ логов
Все логи теперь собираются на одном сервере, сконфигурируем сервер что бы он открывал сокет и отправлят события подключенным клиентам. Для этого нужно использовать SocketHubAppender.
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) — %m%n
log4j.appender.server=org.apache.log4j.net.SocketHubAppender
log4j.appender.server.Port=4561
log4j.appender.server.LocationInfo=true
С такой конфигурацией можно подключаться к серверу программами для анализа логов.
chainsaw v2
chainsaw — программа зародившаяся в недрах log4j, позволяет подключаться к SocketHub и отображать информацию о событиях в реальном времени. Кажется что chainsaw давно умер, т.к. последний билд был аж в 2006 году. Тем неменее с задачей своей справляется.
После запуска в chainsaw неообходимо добавить источник данных, щелкнув по соотвествующему значку в правой панели. В контекстном меню нужно выбрать SocketHubReciver, затем указать хост, порт и имя. В случае успеха в главной панели появится одноимённая вкладка в которой будут отображаться последние произошедшие события. chainsaw обладает достаточно примитивными возможностями фильтрации событий по уровню и по приложению, все события хранит в памяти, поэтому при большом их количестве начинаются тормажения. Не рекомендую к использованию.
otroslogviewer
otroslogviewer — более современная программа, которая активно развивается. Подключение к SocketHub выполняется через пункт меню File -> Connect to Log4J SocketHub. Точно так же указываете хост и порт. Отображение событий будет происходить в новой закладке в главной панели.
Внешне конечно выглядит страшно, Swing от него не уйдешь, но зато функционал здесь гораздо богаче. Гибкие фильтры по уровню, времени, вхождению строки, потокам и прочее прочее.
lilith
lilith — автор заявляет, что данная программа может работать с SocketHub. Но я так и не понял как её настроить.
Вопросы безопасности
SocketHubAppender не предусматривает возможность какой-либо авторизации, т.е. теоретически к нему могут подключаться любые пользователи. Поэтому открыть в глобальный доступ такого рода сервер логов апрометчиво. Самый простой способ обезопаситься — пробрасывать порты через ssh тунель. Т.е. запускаем сервер на удаленной машине на порту 4561, но закрываем доступ на этот порт с помощью фаервола. Когда же появляется необходимость посмотреть последнии события пробрасываем порты командой.
ssh -L 4561:localhost:4561 remote-host
После этого можно подключаться анализаторами логов к localhost:4561.
P. S. Существуют и другие технологии решающие эту задачу например scribe от facebook, но как мне кажется, для простых проектов его преимущества не значительны, а настроить его сложнее.
Автор: Caiiiycuk