我正在通过slf4j / log4j2使用异步数据库日志记录设置。一切都按预期进行。
唯一的缺点是,有时在服务器关闭时,记录器尚未完成对数据库的写入(例如,在关闭前是否有突发事件)。
我得到:
WARN AsyncLoggerConfigDisruptor:0后关闭超时 MILLISECONDS Log4j2-TF-1-AsyncLoggerConfig-1错误尝试附加 到未启动的附加程序databaseAppender
我失去了记录缓冲区中的所有内容。
在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行。
实际数据库中的日志记录将更加稀疏,这只是最坏的测试……而且如上所述,文件中的日志记录有效。即使关闭了服务,也要在数据库和文件中保持一致的日志记录,这还是很好的。