Как прочитать вывод log4j на веб-страницу? - PullRequest
5 голосов
/ 31 марта 2010

У меня есть веб-страница, используемая в целях администрирования, которая запускает задачу (выборка изображений с удаленного сайта).
Чтобы иметь возможность отлаживать задачу только с помощью браузера, без ssh и т. Д., Я хотел бы иметь возможность прочитать весь вывод журнала из потока выполнения и выплюнуть его на веб-страницу.
Задача сводится к:

  1. Изменение уровня журнала для текущего потока в начале вызова и восстановление после завершения вызова.
  2. Чтение всего вывода журнала текущим потоком и сохранение его в виде строки.

Так что в псевдокоде мой метод execute () будет выглядеть так: (я использую struts2)

public String execute() throws Exception {
  turnLoggingLevelToDebugOnlyForThisThread()
  ... do stuff...
  restoreLoggingLevelForThisThread()
  String logs = readAllLogsByThisThread();
}

Можно ли это сделать с помощью log4j?

Я использую tomcat, struts2, log4j и slf4j.

РЕДАКТИРОВАТЬ 1: Я должен отметить, что мотивация состоит в том, чтобы иметь возможность видеть существующие журналы на веб-странице без необходимости добавлять новые строки журнала в коде. Подумайте о хорошем веб-интерфейсе для отладки, который позволяет вам запускать операцию, а результат выдает журналы операции.
РЕДАКТИРОВАТЬ 2: Я должен также отметить, что я уже использую log4j (через slf4j) и log4j.xml, поэтому решение, которое я ищу, должно жить в стороне от текущей системы журналирования, а не разрушать ее.

1 Ответ

14 голосов
/ 31 марта 2010

Вы можете создать приложение log4j для записи в StringWriter. Вот пример, который я сделал некоторое время назад:

consoleWriter = new StringWriter();
WriterAppender appender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"),consoleWriter);
appender.setName("CONSOLE_APPENDER");
appender.setThreshold(org.apache.log4j.Level.ERROR);
Logger.getRootLogger().addAppender(appender);

Он записывает все журналы ОШИБКИ в consoleWriter, но вы можете установить объем или уровень журналов по своему усмотрению. Область (имя регистратора) должна быть уникальным идентификатором потока. как то так:

Logger.getLogger("Thread-00001").addAppender(appender);

Ваша ветка должна писать в этот логгер.

Logger.getLogger("Thread-00001").info("blah blah blah");

А когда вы хотите закончить запись потока:

Logger.getLogger("Thread-00001").removeAppender("CONSOLE_APPENDER");

UPDATE: Вот рабочий пример. Записывает журналы ошибок в файл (установленный в log4j.xml) + записывает все журналы потоков в StringWriter, если он включен:

import java.io.StringWriter;
import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import org.apache.log4j.WriterAppender;
import org.apache.log4j.PatternLayout;

public class Log4jTest implements Runnable {

    public static final String CONSOLE_APPENDER = "CONSOLE_APPENDER";
    private static WriterAppender appender = null;
    private static int counter = 1;

    public static synchronized String getNextId() {
        return "Thread_00"+(counter++);
    }

    public void run() {
        String id="UNKNOWN";
        try {
            id = getNextId();
            Logger log = Logger.getLogger(id);
            log.addAppender(appender);
            log.setLevel(Level.DEBUG);
            log.info(id+" log message 1");
            log.removeAppender(CONSOLE_APPENDER);
            log.info(id+" log message 2");
            log.error(id+" log message 3");
        } catch (Exception e) {
            System.out.println("Error in "+id);
            e.printStackTrace();
        }
    }

    public static void main(String [] args) {
        try {
            StringWriter consoleWriter = new StringWriter();
            appender = new WriterAppender(new PatternLayout("%d{ISO8601} %p - %m%n"),consoleWriter);
            appender.setName(CONSOLE_APPENDER);
            appender.setThreshold(org.apache.log4j.Level.DEBUG);

            for (int i=0; i<5; i++) {
                Thread t = new Thread(new Log4jTest());
                t.start();
            }

            Thread.sleep(200);
            System.out.println(consoleWriter.getBuffer().toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

А вот мой log4j.xml:

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>
  <appender name="FILE" class="org.apache.log4j.RollingFileAppender">
    <param name="File" value="./Log4jTest.log" />
    <param name="MaxFileSize" value="1000KB" />
    <param name="MaxBackupIndex" value="5" />
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d{ISO8601} %p - %m%n" />
    </layout>
    <filter class="org.apache.log4j.varia.LevelRangeFilter">
      <param name="LevelMin" value="WARN" />
      <param name="LevelMax" value="FATAL" />
    </filter>
  </appender>
  <root>
    <level value="ERROR" />
    <appender-ref ref="FILE" />
  </root>
</log4j:configuration>
...