zoukankan      html  css  js  c++  java
  • Log4j 1.x JDBCAppender记录日志失效问题详解

    官网:http://logging.apache.org/log4j/1.2/manual.html

    事件:
    最近在项目中使用log4j 1.x JDBCAppender记录管理员操作日志到数据库,在测试时发现系统启动后运行一段时间无法继续记录相关操作日志到数据库。
    配置如下:
    log4j.properties:

    log4j.logger.oplog=INFO, oplog
    log4j.appender.oplog=com.lenovo.moc.portal.dao.LogJDBCAppender
    log4j.appender.oplog.driver=com.mysql.jdbc.Driver
    log4j.appender.oplog.URL=jdbc:mysql://192.168.2.164:3306/oplog?characterEncoding=utf8
    log4j.appender.oplog.user=xxx
    log4j.appender.oplog.password=xxx
    log4j.appender.oplog.sql=insert into operation_loginfo (staff_id, staff_name, user_role, op_type, op_alias, create_time, content, content_alias) values ('%x{login_staff_id}', '%x{login_staff_name}','%x{login_user_role}', '%x{op_type}', '%x{op_alias}', '%d{yyyy-mm-dd hh:mm:ss}','%m', '%x{content_alias}')
    log4j.appender.oplog.layout=org.apache.log4j.PatternLayout

    java代码:

    public class OperationLogService {
      private static final Logger logger = Logger.getLogger(OperationLogService.class);
      private static ExecutorService threadPool = Executors.newFixedThreadPool(3);;
    
      private static ExecutorService getThreadPool() {
        return threadPool;
      }
    
      /**
      * 记录操作日志
      * @param login_staff_id 员工id
      * @param login_staff_name 员工姓名
      * @param login_user_role 员工角色
      * @param op_type 操作类型
      * @param op_alias 操作别名
      * @param content_alias 操作内容
      * @param msg 附加信息
      */
      public static void log(String login_staff_id, String login_staff_name, String login_user_role, String op_type,
        String op_alias, String content_alias, final String msg) {
        getThreadPool().execute(new Runnable() {
          @Override
          public void run() {
            MDC.put("login_staff_id", login_staff_id);
            MDC.put("login_staff_name", login_staff_name);
            MDC.put("login_user_role", login_user_role);
            MDC.put("op_type", op_type);
            MDC.put("op_alias", op_alias);
            MDC.put("content_alias", content_alias);
           logger.info(msg);
          }
        });
      }
    
      public static void main(String[] args) {
        log("1", "zhangsan", "admin", "add_user", "添加用户", "zhangsan添加用户", "test msg");
      }
    }

    解决办法:
    通过查看log4j 1.x JDBCAppender源码发现,并没有对数据库连接的有效性进行判断。即:一旦数据库连接断开,就无法继续写入日志。
    故而,通过扩展JDBCAppender的方式,进行数据库连接重连处理:

    /**
    * 自定义实现Log4j日志组件,将日志记录到数据库<br />.
    * 解决问题: 原生组件在系统运行过程中可能会出现数据库连接断开,导致无法正常记录日志信息到数据库.
    *
    * @desc com.lenovo.moc.portal.dao.LogJDBCAppender
    * @author chench9@lenovo.com
    * @date 2017年3月15日
    */
    public class LogJDBCAppender extends JDBCAppender {
      private static final Logger logger = Logger.getLogger(LogJDBCAppender.class);
    
      @Override
      protected Connection getConnection() throws SQLException {
        Connection connection = super.getConnection();
        if(connection == null || connection.isClosed()) {
          logger.warn(String.format("reconnect log jdbc appender connection"));
          connection = reconnect();
        }
        return connection;
      }
    
      /**
      * 重新创建数据库连接
      * @return
      * @throws SQLException
      */
      private Connection reconnect() throws SQLException {
        Connection connection = DriverManager.getConnection(databaseURL, databaseUser,databasePassword);
        return connection;
      }
    
      /**
      * 重载父类方法,打印错误信息到日志文件 <br />
      * 同时,处理数据库重连并在出错时重试记录日志信息.
      */
      @Override
      protected void execute(String sql) throws SQLException {
        try {
          super.execute(sql);
        } catch (Exception e) {
          logger.error(String.format("log jdbc appender execute sql eror: %s", getSql()), e);
          closeConnectionInterval();
          super.execute(sql);
        }
      }
    
      // 真正地关闭数据库连接
      private void closeConnectionInterval() {
        if(connection == null) {
          return;
        }
    
        try {
          connection.close();
        } catch (SQLException e) {
          e.printStackTrace();
        } finally {
          connection = null;
        }
      }
    }

    log4j 1.x org.apache.log4j.jdbc.JDBCAppender类图:

    org.apache.log4j.jdbc.JDBCAppender数据库连接实现:

    log4j 2.x org.apache.logging.log4j.core.appender.db.jdbc.JdbcAppender类图:

    显然,在log4j 2.x中,使用了数据库连接池,所以建议使用log4j 2.x版本的JdbcAppender。


    【参考】
    http://stackoverflow.com/questions/3880521/reconnect-to-db-within-log4j Reconnect to DB within log4j

  • 相关阅读:
    SharedPreferences
    Handler
    Gallery 和ImageSwitcher
    poj 1077 Eight (BFS)
    HDU 1208 Pascal's Travels( 记忆化搜索)
    HDU 1619 Unidirectional TSP (dp,dfs)
    HDU 3683 Gomoku (枚举+BFS)
    HDU 3647 Tetris (暴力DFS)
    poj 1020 Anniversary Cake (DFS)
    poj 1375 Intervals(解析几何 过圆外一点求与圆的切线)
  • 原文地址:https://www.cnblogs.com/nuccch/p/6795918.html
Copyright © 2011-2022 走看看