给log4j配置数据库连接

Jun 07, 2016 pm 03:36 PM
http log4j データベース 接続する 構成

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。:)


このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Go 言語はデータベースの追加、削除、変更、クエリ操作をどのように実装しますか? Go 言語はデータベースの追加、削除、変更、クエリ操作をどのように実装しますか? Mar 27, 2024 pm 09:39 PM

Go 言語は、効率的かつ簡潔で習得が容易なプログラミング言語であり、同時プログラミングやネットワーク プログラミングに優れているため、開発者に好まれています。実際の開発ではデータベースの操作が欠かせませんが、今回はGo言語を使ってデータベースの追加・削除・変更・クエリ操作を実装する方法を紹介します。 Go 言語では、データベースを操作するために通常、よく使用される SQL パッケージや gorm などのサードパーティ ライブラリを使用します。ここでは SQL パッケージを例として、データベースの追加、削除、変更、クエリ操作を実装する方法を紹介します。 MySQL データベースを使用していると仮定します。

C++ を使用して HTTP ストリーミングを実装するにはどうすればよいですか? C++ を使用して HTTP ストリーミングを実装するにはどうすればよいですか? May 31, 2024 am 11:06 AM

C++ で HTTP ストリーミングを実装するにはどうすればよいですか? Boost.Asio と asiohttps クライアント ライブラリを使用して、SSL ストリーム ソケットを作成します。サーバーに接続し、HTTP リクエストを送信します。 HTTP 応答ヘッダーを受信して​​出力します。 HTTP 応答本文を受信して​​出力します。

PHP で MySQLi を使用してデータベース接続を確立するための詳細なチュートリアル PHP で MySQLi を使用してデータベース接続を確立するための詳細なチュートリアル Jun 04, 2024 pm 01:42 PM

MySQLi を使用して PHP でデータベース接続を確立する方法: MySQLi 拡張機能を含める (require_once) 接続関数を作成する (functionconnect_to_db) 接続関数を呼び出す ($conn=connect_to_db()) クエリを実行する ($result=$conn->query()) 閉じる接続 ( $conn->close())

Hibernate はポリモーフィック マッピングをどのように実装しますか? Hibernate はポリモーフィック マッピングをどのように実装しますか? Apr 17, 2024 pm 12:09 PM

Hibernate ポリモーフィック マッピングは、継承されたクラスをデータベースにマップでき、次のマッピング タイプを提供します。 join-subclass: 親クラスのすべての列を含む、サブクラス用の別個のテーブルを作成します。 table-per-class: サブクラス固有の列のみを含む、サブクラス用の別個のテーブルを作成します。 Union-subclass: join-subclass と似ていますが、親クラス テーブルがすべてのサブクラス列を結合します。

iOS 18では、紛失または破損した写真を復元するための新しい「復元」アルバム機能が追加されます iOS 18では、紛失または破損した写真を復元するための新しい「復元」アルバム機能が追加されます Jul 18, 2024 am 05:48 AM

Apple の最新リリースの iOS18、iPadOS18、および macOS Sequoia システムでは、さまざまな理由で紛失または破損した写真やビデオをユーザーが簡単に回復できるように設計された重要な機能が写真アプリケーションに追加されました。この新機能では、写真アプリのツール セクションに「Recovered」というアルバムが導入され、ユーザーがデバイス上に写真ライブラリに含まれていない写真やビデオがある場合に自動的に表示されます。 「Recovered」アルバムの登場により、データベースの破損、カメラ アプリケーションが写真ライブラリに正しく保存されない、または写真ライブラリを管理するサードパーティ アプリケーションによって失われた写真やビデオに対する解決策が提供されます。ユーザーはいくつかの簡単な手順を実行するだけで済みます

HTML がデータベースを読み取る方法の詳細な分析 HTML がデータベースを読み取る方法の詳細な分析 Apr 09, 2024 pm 12:36 PM

HTML はデータベースを直接読み取ることはできませんが、JavaScript と AJAX を通じて実現できます。この手順には、データベース接続の確立、クエリの送信、応答の処理、ページの更新が含まれます。この記事では、JavaScript、AJAX、および PHP を使用して MySQL データベースからデータを読み取る実践的な例を示し、クエリ結果を HTML ページに動的に表示する方法を示します。この例では、XMLHttpRequest を使用してデータベース接続を確立し、クエリを送信して応答を処理することで、ページ要素にデータを埋め込み、データベースを読み取る HTML の機能を実現します。

Go WebSocket はどのようにデータベースと統合しますか? Go WebSocket はどのようにデータベースと統合しますか? Jun 05, 2024 pm 03:18 PM

GoWebSocket をデータベースと統合する方法: データベース接続をセットアップする: データベースに接続するには、database/sql パッケージを使用します。 WebSocket メッセージをデータベースに保存する: INSERT ステートメントを使用して、メッセージをデータベースに挿入します。データベースから WebSocket メッセージを取得する: データベースからメッセージを取得するには、SELECT ステートメントを使用します。

PHP でデータベース接続エラーを処理する方法 PHP でデータベース接続エラーを処理する方法 Jun 05, 2024 pm 02:16 PM

PHP でデータベース接続エラーを処理するには、次の手順を使用できます。 mysqli_connect_errno() を使用してエラー コードを取得します。 mysqli_connect_error() を使用してエラー メッセージを取得します。これらのエラー メッセージをキャプチャしてログに記録することで、データベース接続の問題を簡単に特定して解決でき、アプリケーションをスムーズに実行できるようになります。

See all articles