其实如果是通过jdbc去连接数据库,那么下面的链接的
http://www.dankomannhaupt.de/projects/index.html
的jdbcappender.zip 已经能很方便的实现这个功能,
但是在现实情况,特别是大型应用,基本都是通过datasource来获取
connection,而这个zip中已经明确说了不支持 DataSource,那么我们怎么办呢?
我是这样解决的,对应j2ee的应用,本身不管你用spring+hibernate还是c3p0 来获取
Datasource,最终他也是得到jdbc中的connection来进行数据库操作,而jdbcappender
也是通过connection来操作数据库,那么思路就是通过在你框架中获取jdbc的connection,
将他set到jdbcapplender中就可以了。
确定这种思路后,我就需要了解jdbcappender.zip中的代码,看如果将connection 放入jdbcappender中
首先 我们看一下正常如果只是jdbc 的test 方法
public class Log4JTest {
// Create a category instance for this class
static Logger logger = Logger.getLogger(Log4JTest.class);
public static void main(String[] args) {
JDBCAppender ja = new JDBCAppender();
// Set options with method setOption()
ja.setConnector("org.apache.log4j.jdbcplus.examples.OracleConnectionHandler");
ja.setUrl("jdbc:oracle:thin:@..");
ja.setUsername("mex_pr_dev65");
ja.setPassword("mex_pr_dev65");
ja.setSqlhandler("org.apache.log4j.jdbcplus.examples.SqlHandler");
// Add the appender to a category
logger.addAppender(ja);
logger.debug("debug");
}
}
}
上面的类基本分为这么几个部分
1.和一般log4j用法一样, 获取logger instance
2.new 一个JDBCAppender
3.为jdbc设置两部分参数,一个是jdbc 建立连接的参数,如url等 另一部分是具体insert 什么的handler(你可以用handler出来也可以将sql写入log4j的配置文件,这里就用handler处理insert 日志的sql)
4.将logger instance中添加刚才设置的JDBCAppender
5.完成
从上面的例子来看好像不能set connection,后来查看JDBCAppender的源码发现
他有setConnectionHandler(interface JDBCConnectionHandler());
方法,可以通过这个方法能将connection放入jdbcappender中
而接口JDBCConnectionHandler 如下
public interface JDBCConnectionHandler {
/**
* Get a connection
*
* @return The Connection value
* @exception Exception
* Description of Exception
*/
Connection getConnection() throws Exception;
/**
* Get a defined connection
*
* @param _url
* Description of Parameter
* @param _username
* Description of Parameter
* @param _password
* Description of Parameter
* @return The Connection value
* @exception Exception
* Description of Exception
*/
Connection getConnection(String _url, String _username, String _password) throws Exception;
}
这个时候你发现 我们找了半天Connection的地方原来在这里
那么我只要实现这个接口的getConnection() 方法就能将connection放入JDBCAppender中,
现在我们构建一个Handler,我这里前面用的框架只是Hibernate3
我需要从hibernate3中获取connecion就可以了
public class Cas2HibernateConnectionHandler implements JDBCConnectionHandler {
//hibernate 的session Factory
SessionFactory sf = HibernateConnection.getInstance();
public Connection getConnection(){
Connection con =null;
try {
con = sf.openSession().connection();
} catch (Exception e) {
e.printStackTrace();
}
return con;
}
public Connection getConnection(String arg0, String arg1, String arg2)
throws Exception {
// TODO Auto-generated method stub
return null;
}
}
这就是我的handler,下面为了清楚我把我的HibernateConnection也贴出来,这是常见的Sington模式
public class HibernateConnection {
private static SessionFactory sessionFactoryInstance = null;
private HibernateConnection() {
}
//单元测试用的
synchronized public static SessionFactory getInstance() {
if (sessionFactoryInstance == null) {
Configuration config;
try {
config = new Configuration().configure(new File("E:\\cas2\\config\\hibernate\\hibernate.cfg.xml"));
sessionFactoryInstance = config.buildSessionFactory();
} catch (HibernateException e) {
e.printStackTrace();
}
}
return sessionFactoryInstance;
}
}
说到这里我顺便说一下,我这边框架用的是hibernate3,还有很多框架比如hibernate+spring或者c3p0等等,这些都无所谓
只要找到相应如果获得jdbc connection 同样构建自己的ConnectionHandler实现里面的getConnection()就可以了。
到这个时候数据库连接已经能获取了,接下来就需要写具体的insert语句,这里有两种方法,一种就是直接在log4j的配置文件中写
这个配置文件可以xml,也可以properties,这个网站也都有具体描述怎么做
另外一种就是ja.setSqlhandler("org.apache.log4j.jdbcplus.examples.SqlHandler");
自己实现一个sqlHandler 后set到JDBCAppender中就可以了
新构建的sqlHander需要实现接口
public interface JDBCSqlHandler {
/**
* Get a sql-statement.
* Return null or empty string if nothing should be logged.
*
* @return The SQL statement. Null if there is nothing to log.
* @exception Exception
* Any Exception
*/
String getStatement(LoggingEvent event) throws Exception;
}
他里面只有一个方法那就是写人insert语句
public class CasLoginHandler implements JDBCSqlHandler {
private final int MAX_LENGTH_MESSAGE = 3000;
public String getStatement(LoggingEvent event) throws Exception {
// try { throw new Throwable(); } catch (Throwable th) {
// th.printStackTrace(); }
LocationInfo locinfo = event.getLocationInformation();
ThrowableInformation throwableinfo = event.getThrowableInformation();
StringBuffer throwableStringBuffer = new StringBuffer();
String locinfoString = "'', '', '', ''";
if (locinfo != null) {
locinfoString = "'" + locinfo.getClassName() + "', '" + locinfo.getMethodName()
+ "', '" + locinfo.getFileName() + "', '" + locinfo.getLineNumber() + "'";
}
if (throwableinfo != null) {
String[] lines = throwableinfo.getThrowableStrRep();
for (int index = 0; index < lines.length; index++) {
throwableStringBuffer = (StringBuffer) throwableStringBuffer.append(lines[index]
+ "\r\n");
}
}
StringBuffer sb = new StringBuffer();
sb.append("Insert into UM_SYS_LOG (ID, LOG_DATE, LOG_LEVEL, LOGGER, OPERATOR, APPLICATION_NAME, MESSAGE_KEY, LOG_MESSAGE)Values(");
sb.append("SEQ_UM_SYS_LOG.nextval,");
sb.append("TO_DATE('");
sb.append(DateFormatUtil.formDateToyyyyMMdd24(new Date(event.timeStamp)));
sb.append("','YYYY-DD-MM HH24:mi:SS')");
sb.append(",'");
sb.append(event.getLevel().toString());
sb.append("','");
sb.append(event.getLoggerName());
sb.append("','bgao','CAS2','login sucess','user bgao loginSuccess')");
return sb.toString();
}
}
这是我构建的CasLoginHandler。
这样整个将log日志写入数据库就完成了。