最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

给log4j配置数据库连接

来源:动视网 责编:小采 时间:2020-11-09 07:29:06
文档

给log4j配置数据库连接

给log4j配置数据库连接:http://blog.csdn.net/socoolfj/article/details/542169 我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。 现在让我们对日
推荐度:
导读给log4j配置数据库连接:http://blog.csdn.net/socoolfj/article/details/542169 我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。 现在让我们对日


http://blog.csdn.net/socoolfj/article/details/542169 我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。 现在让我们对日志输出


http://blog.csdn.net/socoolfj/article/details/542169


我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的格式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。
现在让我们对日志输出到数据库来进行配置
配置如下:
#---JDBC ---输出到数据库
# JDBCAppender log4j.properties file
#log4j.rootCategory=WARN,JDBC
# APPENDER JDBC
log4j.appender.JDBC=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.JDBC.driver=com.mysql.jdbc.Driver
log4j.appender.JDBC.URL=jdbc:mysql://localhost:3306/test
log4j.appender.JDBC.user=use
log4j.appender.JDBC.password=password
log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')

表结构如下:
log_date varchar2(50)
log_level varchar2(5)
location varchar2(100)
message varchar2(1000)
笔者照做,但没有运行成功,而且此种方法是利用传统的数据库连接方法,对于数据库的管理和效率严重不足,在现在这个连接池横行的时代,为什么我们不能给给Log4j配上连接池,让Log4j利用数据连接池的连接和数据库进行通讯。现查看Log4j的Api,发现JDBCAppender这个类有以下几段话:WARNING: This version of JDBCAppender is very likely to be completely replaced in the future. Moreoever, it does not log exceptions. The JDBCAppender provides for sending log events to a database.

For use as a base class:

  • Override getConnection() to pass any connection you want. Typically this is used to enable application wide connection pooling.
  • Override closeConnection(Connection con) -- if you override getConnection make sure to implementcloseConnection to handle the connection you generated. Typically this would return the connection to the pool it came from.
  • Override getLogStatement(LoggingEvent event) to produce specialized or dynamic statements. The default uses the sql option value.
  • 原来log4j建议我们把其提供的JDBCAppender作为基类来使用,然后Override三个父类的方法:getConnection(),closeConnection(Connection con)和getLogStatement(LoggingEvent event)。
    原来如此,那就写一个子类JDBCPoolAppender来替代这个JDBCAppender
    JDBCPoolAppender代码和其相关代码如下:

    JDBCPoolAppender.java:

    package common.log;
    import java.sql.Connection;
    import org.apache.log4j.spi.LoggingEvent;
    import java.sql.SQLException;
    import java.sql.Statement;
    import java.util.Iterator;
    import org.apache.log4j.spi.ErrorCode;
    import org.apache.log4j.PatternLayout;
    import common.sql.MyDB;
    import common.sql.GeneralDb;

    public class JDBCPoolAppender extends org.apache.log4j.jdbc.JDBCAppender {

    private MyDB mydb = null;
    protected String sqlname=""; //增加一个数据库jndiName的属性
    protected Connection connection = null;
    protected String sqlStatement = "";
    /**
    * size of LoggingEvent buffer before writting to the database.
    * Default is 1.
    */
    protected int bufferSize = 1;

    public JDBCPoolAppender() {
    super();
    }

    /**
    * ArrayList holding the buffer of Logging Events.
    */
    public void append(LoggingEvent event) {
    buffer.add(event);
    if (buffer.size() >= bufferSize)
    flushBuffer();
    }

    /**
    * By default getLogStatement sends the event to the required Layout object.
    * The layout will format the given pattern into a workable SQL string.
    *
    * Overriding this provides direct access to the LoggingEvent
    * when constructing the logging statement.
    *
    */
    protected String getLogStatement(LoggingEvent event) {
    return getLayout().format(event);
    }

    /**
    *
    * Override this to provide an alertnate method of getting
    * connections (such as caching). One method to fix this is to open
    * connections at the start of flushBuffer() and close them at the
    * end. I use a connection pool outside of JDBCAppender which is
    * accessed in an override of this method.
    * */
    protected void execute(String sql) throws SQLException {
    Connection con = null;
    Statement stmt = null;
    try {
    con = getConnection();
    stmt = con.createStatement();
    stmt.executeUpdate(sql);
    } catch (SQLException e) {
    if (stmt != null)
    stmt.close();
    throw e;
    }
    stmt.close();
    closeConnection(con);
    //System.out.println("Execute: " + sql);
    }


    /**
    * Override this to return the connection to a pool, or to clean up the
    * resource.
    *
    * The default behavior holds a single connection open until the appender
    * is closed (typically when garbage collected).
    */
    protected void closeConnection(Connection con) {
    mydb=null;
    try {
    if (connection != null && !connection.isClosed())
    connection.close();
    } catch (SQLException e) {
    errorHandler.error("Error closing connection", e,
    ErrorCode.GENERIC_FAILURE);
    }

    }

    /**
    * Override 此函数来利用连接池返回一个Connetion对象
    *
    */
    protected Connection getConnection() throws SQLException {
    try {
    mydb = GeneralDb.getInstance(sqlname);
    connection = mydb.getConnection();
    } catch (Exception e) {
    errorHandler.error("Error opening connection", e, ErrorCode.GENERIC_FAILURE);
    }
    return connection;
    }

    /**
    * Closes the appender, flushing the buffer first then closing the default
    * connection if it is open.
    */
    public void close() {
    flushBuffer();

    try {
    if (connection != null && !connection.isClosed())
    connection.close();
    } catch (SQLException e) {
    errorHandler.error("Error closing connection", e,
    ErrorCode.GENERIC_FAILURE);
    }
    this.closed = true;
    }

    /**
    * loops through the buffer of LoggingEvents, gets a
    * sql string from getLogStatement() and sends it to execute().
    * Errors are sent to the errorHandler.
    *
    * If a statement fails the LoggingEvent stays in the buffer!
    */
    public void flushBuffer() {
    //Do the actual logging
    removes.ensureCapacity(buffer.size());
    for (Iterator i = buffer.iterator(); i.hasNext(); ) {
    try {
    LoggingEvent logEvent = (LoggingEvent) i.next();
    String sql = getLogStatement(logEvent);
    execute(sql);
    removes.add(logEvent);
    } catch (SQLException e) {
    errorHandler.error("Failed to excute sql", e,
    ErrorCode.FLUSH_FAILURE);
    }
    }

    // remove from the buffer any events that were reported
    buffer.removeAll(removes);

    // clear the buffer of reported events
    removes.clear();
    }


    /** closes the appender before disposal */
    public void finalize() {
    close();
    }


    /**
    * JDBCAppender requires a layout.
    * */
    public boolean requiresLayout() {
    return true;
    }


    /**
    *
    */
    public void setSql(String s) {
    sqlStatement = s;
    if (getLayout() == null) {
    this.setLayout(new PatternLayout(s));
    } else {
    ((PatternLayout) getLayout()).setConversionPattern(s);
    }
    }


    /**
    * Returns pre-formated statement eg: insert into LogTable (msg) values ("%m")
    */
    public String getSql() {
    return sqlStatement;
    }

    public void setSqlname(String sqlname){
    sqlname=sqlname;
    }

    public String getSqlname(){
    return sqlname;
    }


    public void setBufferSize(int newBufferSize) {
    bufferSize = newBufferSize;
    buffer.ensureCapacity(bufferSize);
    removes.ensureCapacity(bufferSize);
    }


    public int getBufferSize() {
    return bufferSize;
    }
    }


    MyDB.java:
    package common.sql;
    import java.sql.*;
    import com.codestudio.sql.*; //引入开源项目Poolman数据库连接池的包

    public class MyDB {
    public static final String module = MyDB.class.getName();
    private String dbName = "";
    private PoolMan plmn = null;


    public MyDB(String dbName) {
    try {
    if (plmn == null) {
    plmn = (PoolMan) Class.forName("com.codestudio.sql.PoolMan").
    newInstance();
    }
    } catch (Exception ec) {
    System.out.println(ec.toString()+module);
    }
    this.dbName = dbName;
    }


    private Connection getNewConnection() {
    Connection conn = null;
    try {
    conn = plmn.connect("jdbc:poolman://" + dbName);
    conn.setAutoCommit(true);
    } catch (Exception ec) {
    System.out.println(ec.toString()+"First:Connect sqlsever failed"+module);
    try {
    Thread.sleep(1000);
    conn = plmn.connect("jdbc:poolman://" + dbName);
    conn.setAutoCommit(true);
    } catch (Exception ecs) {
    System.out.println(ecs.toString()+"Again:Connect sqlsever faile"+module);
    }
    }
    return conn;
    }

    public Connection getConnection() {
    return getNewConnection();
    }
    }
    GeneralDb.java:

    package common.sql;

    package common.sql;

    import java.util.*;

    public class GeneralDb {
    private static Hashtable dbPool;
    public static MyDB getInstance(String dbname) {
    if (dbPool == null) {
    dbPool = new Hashtable();
    }
    MyDB db = (MyDB) dbPool.get(dbname);
    if (db == null) {
    db = new MyDB(dbname);
    dbPool.put(dbname, db);
    }
    return db;
    }
    }

    Log4j数据库连接池的配置如下:
    log4j.appender.JDBC=common.log.JDBCPoolAppender
    log4j.appender.JDBC.sqlname=log
    log4j.appender.JDBC.layout=org.apache.log4j.PatternLayout
    log4j.appender.JDBC.sql=INSERT INTO LOGGING (log_date, log_level, location, message) VALUES ('%d{ISO8601}', '%-5p', '%C,%L', '%m')


    poolman.xml配置如下:

    〈?xml version="1.0" encoding="UTF-8"?>
    〈poolman>
    〈management-mode>local〈/management-mode>
    〈datasource>
    〈dbname>log〈/dbname>
    〈jndiName>log〈/jndiName>
    〈driver>com.mysql.jdbc.Driver〈/driver>
    〈url>jdbc:mysql://localhost:3306/test〈/url>
    〈username>use〈/username>
    〈password>password〈/password>
    〈minimumSize>0〈/minimumSize>
    〈maximumSize>10〈/maximumSize>
    〈logFile>logs/mysql.log〈/logFile>
    〈/datasource>

    〈/poolman>


    运行成功!对于JDBCPoolAppender的属性(比如sqlname属性)我们可以利用Log4j的反射机制随便添加,只要在配置文件给其附上值即可应用,而原来的父类里面的一些属性(username什么的)和其get,set方法由于在连接池中不需要,所以删除。而在JDBCPoolAppender类中,我也只是将getConnection 方法Override ,在这个方法中我们可以根据需要生成我们的Connection对象,另外两个方法大家可以根据需求来决定怎样Override。:)

    文档

    给log4j配置数据库连接

    给log4j配置数据库连接:http://blog.csdn.net/socoolfj/article/details/542169 我们都知道log4j是一个优秀的开源日志记录项目,我们不仅可以对输出的日志的式自定义,还可以自己定义日志输出的目的地,比如:屏幕,文本文件,数据库,甚至能通过socket输出。 现在让我们对日
    推荐度:
    标签: 链接 连接 数据库
    • 热门焦点

    最新推荐

    猜你喜欢

    热门推荐

    专题
    Top