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版 ...
随机推荐
- 洛谷P4907【CYH-01】小奔的国庆练习赛 :$A$换$B$ $problem$(DFS,剪枝)
洛谷题目传送门 顺便提一下题意有一个地方不太清楚,就是如果输出No还要输出最少需要添加多少张牌才能满足要求.蒟蒻考完以后发现四个点Too short on line 2... 比较需要技巧的搜索 既然 ...
- 学习1__STM32--FatFS之逻辑盘符与物理盘符
FatFS源代码中的函数逻辑关系 第一 调用函数 f_mount() result = f_mount(&fs, FS_VOLUME_NAND, ); /* Mount a logical d ...
- django从零开始-模板
1.应用中添加模板 INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contentt ...
- Python3 与 C# 面向对象之~继承与多态
2.继承¶ 代码裤子:https://github.com/lotapp/BaseCode 在线编程:https://mybinder.org/v2/gh/lotapp/BaseCode/mast ...
- 图像处理之gamma校正
1 gamma校正背景 在电视和图形监视器中,显像管发生的电子束及其生成的图像亮度并不是随显像管的输入电压线性变化,电子流与输入电压相比是按照指数曲线变化的,输入电压的指数要大于电子束的指数.这说明暗 ...
- Unity 物体移动的理解
Unity通过内置的Input类获取外部输入,具体查看: Editor---Project Setting---Input,常见的输入比如:Vertical.Horizontal.Fire1.Jump ...
- mysql ibdata1损坏
机房一台服务器上的mysql运行一段时间了,突然出现了一个很奇怪的现象:重启后无法恢复了!准确情况是:启动mysql后随即就又关闭了. 查看mysql错误日志如下: 160920 22:41:41 m ...
- 使用postman测试hystrix
当在浏览器发送多次请求检测hystrix的作用时,我们可以使用postman来自动发送多次请求: 1.将链接保存到一个collection中 2.点击runner 3.设定运行次数
- fork()、vfork()、clone()的区别
因为生活的复杂,这是一个并行的世界,在同一时刻,会发生很多奇妙的事情,北方下雪,南方下雨,这里在吃饭,那边在睡觉,有人在学习,有人在运动,所以这时一个多彩多姿的世界,每天都发生着很多事情,所以要想很好 ...
- (贪心 区间) 51nod1091 线段的重叠
X轴上有N条线段,每条线段包括1个起点和终点.线段的重叠是这样来算的,[10 20]和[12 25]的重叠部分为[12 20]. 给出N条线段的起点和终点,从中选出2条线段,这两条线段的重叠部分是最长 ...