Я использую настройку асинхронного ведения журнала базы данных с помощью slf4j / log4j2.Все работает как положено.
Единственным недостатком является то, что иногда, когда сервер выключается, регистратор не завершает запись в базу данных (например, если перед выключением произошел выброс).
ПРЕДУПРЕЖДЕНИЕ AsyncLoggerConfigDisruptor: время ожидания завершено после 0 МИЛЛИСЕКОНД Log4j2-TF-1-AsyncLoggerConfig-1 ОШИБКА Попытка добавить в базу данных незапущенного приложения * Заявитель * 10081009 *
И я теряю все, что было в буфере логгера.
Есть ли способ в slf4j
или log4j2
дождаться завершения асинхронного логгера (например, блокирующий вызов наконец задачи)?
Или, по крайней мере, для получения размера буфера, который все еще нужно записать?
В настоящее время я использую установку с синхронным файловым регистратором и асинхронным регистратором базы данных, поэтому данныевсе еще в файле ...
-> Изменить 02/28/19
Вот пример быстрого и грязного кода:
protected static final Logger logger = LoggerFactory.getLogger(App.class);
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable task = new TestLogging(i);
executor.submit(task);
}
executor.shutdown();
System.out.println("Done");
//LogManager.shutdown();
}
private static class TestLogging implements Runnable {
private int i;
public TestLogging(int i) {
this.i=i;
}
public void run() {
// Generate a big string for DB test
StringBuffer b=new StringBuffer();
IntStream.range(0, 1000).parallel().forEach(i -> b.append(UUID.randomUUID().toString()));
// Writing to context for logging
MDC.put("test", "test"+i);
MDC.put("test1", b.toString());
// Log 1000 lines
IntStream.range(0, 1000).forEach(j -> logger.error("Exception " + j + "-"+ i, new RuntimeException()));
}
}
Конфигурация xml:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<File name="MyFile" fileName="all.log" immediateFlush="false"
append="false">
<PatternLayout
pattern="%d{yyy-MM-dd HH:mm:ss.SSS} tx.id=%X{test} tx.content=%X{test1} [%t] %-5level %logger{36} - %msg%n" />
</File>
<JDBC name="databaseAppender" tableName="log_test">
<PoolingDriver connectionString="jdbc:oracle:thin:@centos.fritz.box:1521:orcl" userName="test" password="test" driverClassName="oracle.jdbc.driver.OracleDriver"/>
<Column name="LOG_ID" pattern="%u" />
<Column name="ENTRY_DATE" isEventTimestamp="true" />
<Column name="LOGGER" pattern="%logger" />
<Column name="LOG_LEVEL" pattern="%level" />
<Column name="MESSAGE" pattern="%m" />
<Column name="EXCEPTION" pattern="%throwable" />
<Column name="ID" pattern="%X{test}" />
<Column name="XML" pattern="%X{test1}" />
</JDBC>
</Appenders>
<Loggers>
<AsyncRoot level="info">
<AppenderRef ref="databaseAppender" />
</AsyncRoot>
<Logger name="com.test" level="trace" includeLocation="true">
<AppenderRef ref="MyFile" />
</Logger>
</Loggers>
</Configuration>
А для Oracle DDL:
CREATE TABLE "TEST"."LOG_TEST"
( "LOG_ID" VARCHAR2(100 BYTE),
"ENTRY_DATE" TIMESTAMP (6),
"LOGGER" VARCHAR2(100 BYTE),
"LOG_LEVEL" VARCHAR2(100 BYTE),
"MESSAGE" CLOB,
"EXCEPTION" CLOB,
"ID" VARCHAR2(20 BYTE),
"XML" CLOB,
PRIMARY KEY ("LOG_ID"))
Если я использую LogManager.shutdown();
Регистрация даже не начинается.Без, в зависимости от БД, я получаю около 500-1000 строк в БД до появления ошибки.
Регистрация в реальной базе данных будет намного более разреженной, это всего лишь тест в худшем случае... и как уже упоминалось, регистрация в файле работает.Было бы неплохо иметь постоянную регистрацию в БД и файле, даже если служба выключена.