- 論壇徽章:
- 0
|
log4j寫數(shù)據(jù)庫,通常只能寫入log4j提供的信息,如果用來記錄用戶ID號,操作等的記錄,則無法實現(xiàn).
這里,我在log4j里加了一個字段userID (當(dāng)然你可以再加幾個)用來記錄用戶ID,操作
1.log4j配置文件
#向控制臺和數(shù)據(jù)庫輸出
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語句以逗號結(jié)束,并沒有寫完,缺少最后一個字段userID的值(這個值由程序填寫)。
2.數(shù)據(jù)庫表結(jié)構(gòu)
我是在oracle下測試的,表結(jié)構(gòu)如下
create table SYS_LOG
(
LOGTIME VARCHAR2(32),
USERID VARCHAR2(20),
LOGLEVEL VARCHAR2(10),
LOCATION VARCHAR2(80),
MESSAGE VARCHAR2(100)
)
3.數(shù)據(jù)庫連接池和自定義信息
org.apache.log4j.jdbc.JDBCAppender是log4j提供的默認向數(shù)據(jù)庫插入數(shù)據(jù)的類。這個類采用的是直接通過JDBC連接數(shù)據(jù)庫,效率低,而且不能插入自定義信息。
如果你的服務(wù)器上配置了數(shù)據(jù)庫連接池,而且想插入自定義信息,比如用戶ID,必須重載此類。
代碼見附錄1
說明:
(1)網(wǎng)上大量的人說至少重載三個方法getconnect,closeconnection,excute,我看了一下源代碼,悲從心生。最早應(yīng)該有一個程序員,對面向?qū)ο蠹夹g(shù)是懂非懂,看了一些資料就草率的下了這個結(jié)論,而且還想當(dāng)然的結(jié)出了例子代碼。
比如:
如何給 Log4j 配上數(shù)據(jù)庫連接池
從面向?qū)ο蠹夹g(shù)上看,重載意味著先當(dāng)實例化出一個子類對象時,如果子類重載了父類的方法,則執(zhí)行子類的方法,如果沒有重載,則執(zhí)行父類的方法。
也就是說你覺得哪個方法達不到你的要求,你就要定制自己的實現(xiàn)代碼。很多人把JDBCAppender中的成員變量和方法又重新在自己的類里面又寫了一遍,呵呵。
(2)由于我們使用了數(shù)據(jù)庫連接池,所以必須重載getConnection和closeConnection
(3)由于我們要加入自定義信息,必須重載getLogStatement
(4)DatabaseConfigure類請在博客內(nèi)找,這里就不提供超鏈接了
4.添加自定義信息
(1)先添加一個ParameterizedMessage接口,見附錄2
(2)再用JDBCLogMessage類實現(xiàn)ParameterizedMessage接口,見附錄3
(3)JDBCExtAppender類重載getLogStatement()方法,在SQL字符串的最后添加用戶ID等信息,將SQL語句補充完整
(4)有的人很巧妙,通過PreparedStatement完成了SQL數(shù)據(jù)的插入,但是徹底影響了log4j的整體結(jié)構(gòu),這里不推薦大家使用。參見《
Log4j記錄日志到數(shù)據(jù)庫
》
這個重載的最根本問題,是重新定義了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 {
//如果沒有數(shù)據(jù)庫連接池,則直接連接
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 {
/**
* 獲取參數(shù)列表
* @return 返回參數(shù)列表
*/
public Object[] getParameters();
/**
* 獲取指定索引位置的參數(shù)
* @param index 索引位置
* @return 返回參數(shù)列表中指定索引位置的參數(shù)值
* @throws IndexOutOfBoundsException 當(dāng)index >= 參數(shù)列表個數(shù)時,拋出此異常
* @see getParameterCount()
*/
public Object getParameter(int index) throws IndexOutOfBoundsException;
/**
* 獲取參數(shù)個數(shù)
* @return 返回參數(shù)個數(shù)
*/
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記錄日志到數(shù)據(jù)庫. http://www.hxhack.com/bbs/read.php?tid-324467.html
2.如何給 Log4j 配上數(shù)據(jù)庫連接池. http://hi.baidu.com/hwaspf/blog/item/e1583dc73562861c9c163d29.html
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/21752/showart_2106760.html |
|