Log4j 2 jdbc数据库appender删除日志记录

时间:2014-03-18 14:13:42

标签: java logging jdbc log4j

一位同事和我一直试图将log4j记录写入数据库表。 我们在Windows 7上运行Java 1.6_43。数据库服务器是在同一系统上运行的Oracle 10.3。系统有足够的内存和四个CPU。我们使用log4j202.0-rc1和disruptor-3.2.0

我们有数据库的多个回退记录器以及文件记录。当记录未记录到数据库(即它们被删除)时,记录将记录到日志文件中。 我包括代码。当我们在记录器调用之间插入一个1纳秒延迟的Thread.sleep()调用时,所有内容都会记录到数据库中。没有延迟,大量的日志记录不会插入数据库。

以下是测试程序及其支持类:

package net.example.db;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class Bar {

   private static final Logger LOG = LogManager.getLogger(Bar.class);

   public static void main(String[] args) {
      Bar bar = new Bar();
      for (int i = 0; i < 100; i++ ) {
         System.out.println(String.format("1[%s] 2[%s]", bar.blah(i), "outer loop complete"));
      }
   }

   public String blah(int i) {
      String s = null;
      for (int j = 0; j < 100; j++ ) {
         s = phoo(i, j);
      }
      return s;
   }

   public String phoo(int i, int j) {
      try {
         // Even just 1 nanosecond will ensure all messages are persisted through the JDBC Appender
         // However, not sleeping causes dropped messages (some events are not persisted to the DB)
         // "Some", in our tests, has meant 20%-80% of the events 
         Thread.sleep(0, 0);
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
      LOG.info("[" + i + "," + j + "] I'm an info msg!");
      return "hello from phoo";
   }

}

package net.example.db;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.DriverManagerConnectionFactory;
import org.apache.commons.dbcp.PoolableConnection;
import org.apache.commons.dbcp.PoolableConnectionFactory;
import org.apache.commons.dbcp.PoolingDataSource;
import org.apache.commons.pool.impl.GenericObjectPool;

public class ConnectionFactory {
   private static interface Singleton {
      final ConnectionFactory INSTANCE = new ConnectionFactory();
   }

   private final DataSource dataSource;
   private static final String connectionString =
         "jdbc:oracle:thin:@127.0.0.1:1521:db_instance_name";

   private ConnectionFactory() {
      Properties properties = new Properties();
      properties.setProperty("user", "db_user_name");
      properties.setProperty("password", "db_user_password");

      GenericObjectPool<PoolableConnection> pool = new GenericObjectPool<PoolableConnection>();
      DriverManagerConnectionFactory connectionFactory = new DriverManagerConnectionFactory(connectionString, properties);
      new PoolableConnectionFactory(connectionFactory, pool, null, "SELECT 1 FROM DUAL", 3, false, false, Connection.TRANSACTION_READ_COMMITTED);
      pool.setMaxActive(20);
      pool.setMaxIdle(10);
      pool.setMinIdle(3);
      this.dataSource = new PoolingDataSource(pool);
   }

   public static Connection getDatabaseConnection()
         throws SQLException {
      return Singleton.INSTANCE.dataSource.getConnection();
   }
}

这是log4j配置:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="TRACE">

  <Appenders>

    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %m%n"/>
    </Console>

    <RollingFile name="LogFile" fileName="/data/app/log/logfile.log"
        filePattern="/data/app/log/logfile-%d{yyyy-MM-dd-HH}-%i.log.gz" bufferedIO="true">
        <PatternLayout>
            <pattern>%d{ISO8601} [%t] %p %c - %m%n</pattern>
        </PatternLayout>
        <Policies>
            <TimeBasedTriggeringPolicy interval="1" modulate="true" />
            <SizeBasedTriggeringPolicy size="25 MB" />
        </Policies>
    </RollingFile>

    <!-- JdbcAppender -->
    <!-- ignoreExceptions   True causes exceptions encountered while appending events to be internally logged and then ignored. When set to false exceptions will be propagated to the caller, instead.
         bufferSize         If an integer greater than 0, this causes the appender to buffer log events and flush whenever the buffer reaches this size. -->

    <JDBC name="Database" tableName="mst_test.app_log" ignoreExceptions="true" bufferSize="50000" >
        <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
        <Column name="log_timestamp" isEventTimestamp="true" />
        <Column name="log_level" pattern="%level" /> 
        <Column name="thread_name" pattern="%t" />
        <Column name="client_id" pattern="%X{clientId}" />
        <Column name="class_name" pattern="%c" />
        <Column name="nested_diagnostic_context" pattern="%x" />
        <Column name="log_message" pattern="%message" />
        <Column name="ex_full" pattern="%throwable{full}" isClob="true" />
        <Column name="ex_short" pattern="%throwable{short}" />
        <Column name="ex_class_name" pattern="%throwable{short.className}" />
        <Column name="ex_file_name" pattern="%throwable{short.fileName}" />
        <Column name="ex_line_number" pattern="%throwable{short.lineNumber}" />
        <Column name="ex_method_name" pattern="%throwable{short.methodName}" />
        <Column name="ex_message" pattern="%throwable{short.message}" />
        <Column name="ex_localized_message" pattern="%throwable{short.localizedMessage}" />
    </JDBC>

    <JDBC name="Database-queue-full-1" tableName="mst_test.app_log" ignoreExceptions="true" bufferSize="50000" >
        <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
        <Column name="log_timestamp" isEventTimestamp="true" />
        <Column name="log_level" pattern="%level" /> 
        <Column name="thread_name" pattern="%t" />
        <Column name="client_id" literal="'queue-full-1'" />
        <Column name="class_name" pattern="%c" />
        <Column name="nested_diagnostic_context" pattern="%x" />
        <Column name="log_message" pattern="%message" />
        <Column name="ex_full" pattern="%throwable{full}" isClob="true" />
        <Column name="ex_short" pattern="%throwable{short}" />
        <Column name="ex_class_name" pattern="%throwable{short.className}" />
        <Column name="ex_file_name" pattern="%throwable{short.fileName}" />
        <Column name="ex_line_number" pattern="%throwable{short.lineNumber}" />
        <Column name="ex_method_name" pattern="%throwable{short.methodName}" />
        <Column name="ex_message" pattern="%throwable{short.message}" />
        <Column name="ex_localized_message" pattern="%throwable{short.localizedMessage}" />
    </JDBC>

    <JDBC name="Database-queue-full-2" tableName="mst_test.app_log" ignoreExceptions="true" bufferSize="50000" >
        <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
        <Column name="log_timestamp" isEventTimestamp="true" />
        <Column name="log_level" pattern="%level" /> 
        <Column name="thread_name" pattern="%t" />
        <Column name="client_id" literal="'queue-full-2'" />
        <Column name="class_name" pattern="%c" />
        <Column name="nested_diagnostic_context" pattern="%x" />
        <Column name="log_message" pattern="%message" />
        <Column name="ex_full" pattern="%throwable{full}" isClob="true" />
        <Column name="ex_short" pattern="%throwable{short}" />
        <Column name="ex_class_name" pattern="%throwable{short.className}" />
        <Column name="ex_file_name" pattern="%throwable{short.fileName}" />
        <Column name="ex_line_number" pattern="%throwable{short.lineNumber}" />
        <Column name="ex_method_name" pattern="%throwable{short.methodName}" />
        <Column name="ex_message" pattern="%throwable{short.message}" />
        <Column name="ex_localized_message" pattern="%throwable{short.localizedMessage}" />
    </JDBC>

    <JDBC name="Database-queue-full-3" tableName="mst_test.app_log" ignoreExceptions="true" bufferSize="50000" >
        <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
        <Column name="log_timestamp" isEventTimestamp="true" />
        <Column name="log_level" pattern="%level" /> 
        <Column name="thread_name" pattern="%t" />
        <Column name="client_id" literal="'queue-full-3'" />
        <Column name="class_name" pattern="%c" />
        <Column name="nested_diagnostic_context" pattern="%x" />
        <Column name="log_message" pattern="%message" />
        <Column name="ex_full" pattern="%throwable{full}" isClob="true" />
        <Column name="ex_short" pattern="%throwable{short}" />
        <Column name="ex_class_name" pattern="%throwable{short.className}" />
        <Column name="ex_file_name" pattern="%throwable{short.fileName}" />
        <Column name="ex_line_number" pattern="%throwable{short.lineNumber}" />
        <Column name="ex_method_name" pattern="%throwable{short.methodName}" />
        <Column name="ex_message" pattern="%throwable{short.message}" />
        <Column name="ex_localized_message" pattern="%throwable{short.localizedMessage}" />
    </JDBC>

    <JDBC name="Database-queue-full-4" tableName="mst_test.app_log" ignoreExceptions="true" bufferSize="50000" >
        <ConnectionFactory class="net.example.db.ConnectionFactory" method="getDatabaseConnection" />
        <Column name="log_timestamp" isEventTimestamp="true" />
        <Column name="log_level" pattern="%level" /> 
        <Column name="thread_name" pattern="%t" />
        <Column name="client_id" literal="'queue-full-4'" />
        <Column name="class_name" pattern="%c" />
        <Column name="nested_diagnostic_context" pattern="%x" />
        <Column name="log_message" pattern="%message" />
        <Column name="ex_full" pattern="%throwable{full}" isClob="true" />
        <Column name="ex_short" pattern="%throwable{short}" />
        <Column name="ex_class_name" pattern="%throwable{short.className}" />
        <Column name="ex_file_name" pattern="%throwable{short.fileName}" />
        <Column name="ex_line_number" pattern="%throwable{short.lineNumber}" />
        <Column name="ex_method_name" pattern="%throwable{short.methodName}" />
        <Column name="ex_message" pattern="%throwable{short.message}" />
        <Column name="ex_localized_message" pattern="%throwable{short.localizedMessage}" />
    </JDBC>

    <Async name="async-file">
      <AppenderRef ref="LogFile"/>
    </Async>

    <!-- AsyncAppender -->
    <!-- blocking:          If true, the appender will wait until there are free slots in the queue. If false, the event will be written to the error appender if the queue is full.
         errorRef           The name of the Appender to invoke if none of the appenders can be called, either due to errors in the appenders or because the queue is full. If not specified then errors will be ignored.
         ignoreExceptions   True causes exceptions encountered while appending events to be internally logged and then ignored. When set to false exceptions will be propagated to the caller, instead. -->

    <Async name="async-db"
           blocking="false"
           errorRef="async-file"
           ignoreExceptions="true"
           bufferSize="50000"
           includeLocation="false">
      <AppenderRef ref="Database"/>
    </Async>
    <Async name="async-db-queue-full-1"
           blocking="false"
           errorRef="async-db-queue-full-2"
           ignoreExceptions="true"
           bufferSize="500000"
           includeLocation="false">
      <AppenderRef ref="Database-queue-full-1"/>
    </Async>
    <Async name="async-db-queue-full-2"
           blocking="false"
           errorRef="async-db-queue-full-3"
           ignoreExceptions="true"
           bufferSize="500000"
           includeLocation="false">
      <AppenderRef ref="Database-queue-full-2"/>
    </Async>
    <Async name="async-db-queue-full-3"
           blocking="false"
           errorRef="async-db-queue-full-4"
           ignoreExceptions="true"
           bufferSize="500000"
           includeLocation="false">
      <AppenderRef ref="Database-queue-full-3"/>
    </Async>
    <Async name="async-db-queue-full-4"
           blocking="false"
           ignoreExceptions="true"
           bufferSize="500000"
           includeLocation="false">
      <AppenderRef ref="Database-queue-full-4"/>
    </Async>

    <Failover name="async-db-with-failover" primary="async-db" retryInterval="5" suppressExceptions="false">
      <Failovers>
        <AppenderRef ref="async-db-queue-full-1"/>
        <AppenderRef ref="async-db-queue-full-2"/>
        <AppenderRef ref="async-db-queue-full-3"/>
        <AppenderRef ref="async-db-queue-full-4"/>
      </Failovers>
    </Failover>

  </Appenders>

  <Loggers>
    <Root level="trace">
      <!--<AppenderRef ref="Console"/>-->
      <!--<AppenderRef ref="async-file"/>-->
      <AppenderRef ref="async-db"/>
      <!--<AppenderRef ref="async-db-with-failover" />-->
    </Root>
  </Loggers>

</Configuration>

0 个答案:

没有答案