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
Log4j 1.x JDBCAppender记录日志失效问题详解的更多相关文章
- 《手把手教你》系列基础篇(八十七)-java+ selenium自动化测试-框架设计基础-Log4j 2实现日志输出-上篇(详解教程)
1.简介 Apache Log4j 是一个非常古老的日志框架,并且是多年来最受欢迎的日志框架. 它引入了现代日志框架仍在使用的基本概念,如分层日志级别和记录器. 2015 年 8 月 5 日,该项目管 ...
- java log4j基本配置及日志级别配置详解
java log4j日志级别配置详解 1.1 前言 说出来真是丢脸,最近被公司派到客户公司面试外包开发岗位,本来准备了什么redis.rabbitMQ.SSM框架的相关面试题以及自己做过的一些项目回顾 ...
- Flume中的flume-env.sh和log4j.properties配置调整建议(图文详解)
GC是内存的回收的意思. Flume中的flume-env.sh配置调整建议 [hadoop@master conf_HostInterceptor]$ pwd /home/hadoop/app/fl ...
- Android 定时器实现的几种方式和removeCallbacks失效问题详解
实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + Runnable的方式 Handler handler = new Handler(); Runnable runna ...
- 【转】Android 定时器实现的几种方式和removeCallbacks失效问题详解--不错
原文网址:http://blog.csdn.net/xiaanming/article/details/9011193 实现定时器有很多种方式,在这里我简单的介绍几种方式 (1)使用Handler + ...
- IDEA里运行代码时出现Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger的解决办法(图文详解)
不多说,直接上干货! 问题详情 运行出现log4j的问题 -classpath "C:\Program Files\Java\jdk1.8.0_66\jre\lib\charsets.jar ...
- 《手把手教你》系列基础篇(八十八)-java+ selenium自动化测试-框架设计基础-Log4j 2实现日志输出-下篇(详解教程)
1.简介 上一篇宏哥讲解和分享了如何在控制台输出日志,但是你还需要复制粘贴才能发给相关人员,而且由于界面大小限制,你只能获取当前的日志,因此最好还是将日志适时地记录在文件中直接打包发给相关人员即可.因 ...
- mysql 索引B-Tree类型对索引使用的生效和失效情况详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt343 当人们谈论索引的时候,如果没有特别指明类型 ,那多半说的是 B-Tre ...
- 对于maven创建spark项目的pom.xml配置文件(图文详解)
不多说,直接上干货! http://mvnrepository.com/ 这里,怎么创建,见 Spark编程环境搭建(基于Intellij IDEA的Ultimate版本)(包含Java和Scala版 ...
随机推荐
- [luogu2051][bzoj1801][AHOI2009]chess中国象棋【动态规划】
题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中国象棋中炮的行走方式是 ...
- django从零开始-模型
1.设置统计表 配置models.py from django.db import models # Create your models here. # 发布会 class Event(models ...
- IIS最小配置
目的 : IIS按需要配置练习 测试环境 IIS 10 WIN10 1.安装IIS与建立网站 安装IIS略,服务器版用添加角色,用户版添加删除WINDOWS组件. 装好IIS之后,建一个网 ...
- Scout YYF I POJ - 3744(概率dp)
Description YYF is a couragous scout. Now he is on a dangerous mission which is to penetrate into th ...
- [APIO2013]机器人(斯坦纳树)
题目描述 VRI(Voltron 机器人学会)的工程师建造了 n 个机器人.任意两个兼容的机 器人站在同一个格子时可以合并为一个复合机器人. 我们把机器人用 1 至 n 编号(n ≤ 9).如果两个机 ...
- map映照容器
//map映照容器是由一个键值和一个映照数据组成的,键值与映照数据之间具有一一映照的关系 //map映照容器的键值不允许重复 ,比较函数值对元素 //的键值进行比较,元素的各项数据可通过键值检索出来 ...
- Vim在图形环境下全屏产生黑边
在终端中运行Vim或运行GVim都会遇到这个问题,当窗口全屏时,左右和底部可能会出现边框,这个边框在终端中的Vim表现为Terminal的背景颜色.下图为SpaceVim+Neovim+Termina ...
- A1003. Emergency
As an emergency rescue team leader of a city, you are given a special map of your country. The map s ...
- RSA签名验证
/// <summary> /// 验证签名 /// </summary> /// <param name="content">待签名字符串&l ...
- 使用python制作验证码
方法一 简单型:使用random模块制作一个随机字母与数字的验证码 import random def make_code(n): res='' for i in range(n): num=str( ...