免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 23856 | 回复: 1

log4j+数据库连接池添加自定义信息 [复制链接]

论坛徽章:
0
发表于 2009-11-29 16:46 |显示全部楼层
   log4j写数据库,通常只能写入log4j提供的信息,如果用来记录用户ID号,操作等的记录,则无法实现.
   这里,我在log4j里加了一个字段userID (当然你可以再加几个)用来记录用户ID,操作
1.log4j配置文件
#向控制台和数据库输出
log4j.rootLogger=DEBUG,stdout,JDBC
log4j.addivity.org.apache=true
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[Datetime]%d{yyyy-MM-dd hh:mm:ss}%n[Priority]%p%n[Location]%l%n[Message]%m%n
log4j.appender.JDBC.Threshold=INFO
log4j.appender.JDBC=xaut.common.log.JDBCExtAppender
log4j.appender.JDBC.driver=oracle.jdbc.driver.OracleDriver
log4j.appender.JDBC.URL=jdbc:oracle:thin:@192.168.88.26:1521:hdptdb
log4j.appender.JDBC.user=hdptdep
log4j.appender.JDBC.password=123456
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.sql=INSERT INTO SYS_LOG(LOGTIME,LOGLEVEL,LOCATION,MESSAGE,USERID)VALUES('%d{yyyy-MM-dd HH:mm:ss}','%p','%l','%m',
   大家注意最后一句log4j.appender.JDBC.sql ,这个sql语句以逗号结束,并没有写完,缺少最后一个字段userID的值(这个值由程序填写)。
2.数据库表结构
   我是在oracle下测试的,表结构如下
create table SYS_LOG
(
  LOGTIME  VARCHAR2(32),
  USERID   VARCHAR2(20),
  LOGLEVEL VARCHAR2(10),
  LOCATION VARCHAR2(80),
  MESSAGE  VARCHAR2(100)
)
3.数据库连接池和自定义信息
   org.apache.log4j.jdbc.JDBCAppender是log4j提供的默认向数据库插入数据的类。这个类采用的是直接通过JDBC连接数据库,效率低,而且不能插入自定义信息。
   如果你的服务器上配置了数据库连接池,而且想插入自定义信息,比如用户ID,必须重载此类。
代码见附录1
说明:
   (1)网上大量的人说至少重载三个方法getconnect,closeconnection,excute,我看了一下源代码,悲从心生。最早应该有一个程序员,对面向对象技术是懂非懂,看了一些资料就草率的下了这个结论,而且还想当然的结出了例子代码。
      比如:
如何给 Log4j 配上数据库连接池
      从面向对象技术上看,重载意味着先当实例化出一个子类对象时,如果子类重载了父类的方法,则执行子类的方法,如果没有重载,则执行父类的方法。
      也就是说你觉得哪个方法达不到你的要求,你就要定制自己的实现代码。很多人把JDBCAppender中的成员变量和方法又重新在自己的类里面又写了一遍,呵呵。
      
   (2)由于我们使用了数据库连接池,所以必须重载getConnection和closeConnection
   (3)由于我们要加入自定义信息,必须重载getLogStatement
   (4)DatabaseConfigure类请在博客内找,这里就不提供超链接了
4.添加自定义信息
   (1)先添加一个ParameterizedMessage接口,见附录2
   (2)再用JDBCLogMessage类实现ParameterizedMessage接口,见附录3
   (3)JDBCExtAppender类重载getLogStatement()方法,在SQL字符串的最后添加用户ID等信息,将SQL语句补充完整
   (4)有的人很巧妙,通过PreparedStatement完成了SQL数据的插入,但是彻底影响了log4j的整体结构,这里不推荐大家使用。参见《
Log4j记录日志到数据库

      这个重载的最根本问题,是重新定义了getLogStatement方法的功能(从提供合法的SQL语句变成了直接进行SQL操作),由于log4j是通常的类库,又不是你自己写的,会引起致命的错误的。
5.测试代码
public class Logtest {
  static Logger logger = Logger.getLogger(Logtest.class.getName());
  public static void main(String[] args) {
     ParameterizedMessage msg = new JDBCLogMessage("question error","1001");   
     logger.error(msg);   
  }
}
说明:
   1001是指用户ID
   惟一美中不足是message字段里会显示
           [question error, 1001]
   多一个中括号和1001信息,呵呵
附录1:
public class JDBCExtAppender extends org.apache.log4j.jdbc.JDBCAppender {
    public JDBCExtAppender() {
        super();
    }
   
    /**
     * 重载JDBCAppender的getConnection()方法
     */
    protected Connection getConnection() throws SQLException {
        if (DatabaseConfigure.getInstance().getDatapool() != null) {
            try{
            Context initCtx = new InitialContext();
            DataSource ds = (DataSource) initCtx.lookup(DatabaseConfigure.getInstance().getDatapool());
            if (ds != null)
                this.connection = ds.getConnection();
            }catch(NamingException namingex){
                namingex.printStackTrace();
                throw new SQLException("-datapool init error ");
            }
        } else {
            
            //如果没有数据库连接池,则直接连接
            try {
                Class.forName(DatabaseConfigure.getInstance().getJdbcDriver());
            } catch (ClassNotFoundException e) {
                System.out.println(" class not found: " + e.getMessage());
                e.printStackTrace();
                throw new SQLException("-Database driver notFind ");
            }
            try {
                this.connection = DriverManager.getConnection(DatabaseConfigure.getInstance()
                        .getDatabaseURL(), DatabaseConfigure.getInstance()
                        .getDatabaseName(), DatabaseConfigure.getInstance()
                        .getDatebasePassword());
            } catch (SQLException sqlex) {
                System.err.println("DatabaseBean connection error"
                        + sqlex.getMessage());
                sqlex.printStackTrace();
                throw new SQLException("-Database connection error ");
            }
        }
        return this.connection;
    }
   
   
   
    /**
     * 重载getLogStatement()方法,
     * 在SQL字符串最后添加用户ID等信息
     */
     protected String getLogStatement(LoggingEvent event) {
         StringBuffer stringBuffer = new StringBuffer();
         stringBuffer.append(layout.format(event));
         
         if (event.getMessage() instanceof ParameterizedMessage) {
            
             //检测SQL的最后一个字符是不是逗号,如果不是,则在这里补上
             if(stringBuffer.charAt(stringBuffer.length()-1)!=',')
                 stringBuffer.append(",");
            
             Object[] params = ((ParameterizedMessage) event.getMessage()).getParameters();   
             for (int i = 1; i 附录2
public interface ParameterizedMessage extends Serializable {   
   
     /**  
      * 获取参数列表  
      * @return 返回参数列表  
      */  
     public Object[] getParameters();   
        
     /**  
      * 获取指定索引位置的参数  
      * @param index 索引位置  
      * @return 返回参数列表中指定索引位置的参数值  
      * @throws IndexOutOfBoundsException 当index >= 参数列表个数时,抛出此异常  
      * @see getParameterCount()  
      */  
     public Object getParameter(int index) throws IndexOutOfBoundsException;   
        
     /**  
      * 获取参数个数  
      * @return 返回参数个数  
      */  
     public int getParameterCount();   
        
}   
附录3
public class JDBCLogMessage implements ParameterizedMessage {
    private static final long serialVersionUID = 1709063421963292637L;
    private Object[] params;
    public JDBCLogMessage(Object... params) {
        this.params = params;
    }
    public Object[] getParameters() {
        return this.params;
    }
    public Object getParameter(int index) throws IndexOutOfBoundsException {
        return this.params[index];
    }
    public int getParameterCount() {
        return this.params.length;
    }
    @Override
    public String toString() {
        return Arrays.toString(this.params);
    }
}
参考文献
1.Log4j记录日志到数据库. http://www.hxhack.com/bbs/read.php?tid-324467.html
2.如何给 Log4j 配上数据库连接池. http://hi.baidu.com/hwaspf/blog/item/e1583dc73562861c9c163d29.html


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/21752/showart_2106760.html

论坛徽章:
0
发表于 2012-07-03 19:23 |显示全部楼层
为了回复你特意注册的。。。。。
DatabaseConfigure类请在博客内找,这里就不提供超链接了  根本就没有!!!!!!!!!!!!!!!!!!!!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

DTCC2021中国数据库技术大会

【数造未来】2021年10月18日-20日第十二届中国数据库技术大会
ITPUB、大会的会员您们好: 因目前国内疫情严峻,为响应北京市最新疫情防控要求,保障参会人员的健康和安全,组委会经协商决定:DTCC2021第十二届中国数据库技术大会延期至10月18日-20日(周一~周三)在北京国际会议中心举行,由此给各位带来的不便,敬请谅解!

大会官网
  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP