⑴ 資料庫異常信息為什麼沒有寫入log4j日誌文件中
log4j是一個優秀的開源日誌記錄項目,我們不僅可以對輸出的日誌的格式自定義,還可以自己定義日誌輸出的目的地,比如:屏幕,文本文件,資料庫,甚至能通過socket輸出。本節主要講述如何將日誌信息輸入到資料庫(可以插入任何資料庫,在此主要以MSsql為例進行詳解)。
用log4j將日誌寫入資料庫主要用到是log4j包下的JDBCAppender類,它提供了將日誌信息非同步寫入數據的功能,我們可以直接使用這個類將我們的日誌信息寫入資料庫;也可以擴展JDBCAppender類,就是將JDBCAppender類作為基類。下面將通過一個實例來講解log4j是如何將日誌信息寫入資料庫的。
我們的需求:我們在軟體開發的過程中需要將調試信息、操作信息等記錄下來,以便後面的審計,這些日誌信息包括用戶ID、用戶姓名、操作類、路徑、方法、操作時間、日誌信息。
設計思想:我們採用JDBCAppender類直接將日誌信息插入資料庫,所有隻需要在配置文件配置此類就可以;要獲得用戶信息需要用過濾器來實現;(假如不需要用戶的信息,就不需要設計過濾器,其實大部分情況下都是需要這些用戶信息,尤其是在web應用開發中)在日誌信息中獲得用戶信息,就的通過過濾器的request或session對象,從session中拿到用戶信息怎樣傳到log4j呢,log4j為我們提供了MDC(MDC是log4j種非常有用類,它們用於存儲應用程序的上下文信息(context infomation),從而便於在log中使用這些上下文信息。MDC內部使用了類似map的機制來存儲信息,上下文信息也是每個線程獨立地儲存,所不同的是信息都是以它們的key值存儲在」map」中。相對應的方法,
MDC.put(key, value); MDC.remove(key); MDC.get(key);
在配置PatternLayout的時候使用:%x{key}來輸出對應的value)。有了MDC,我們可以在過濾器中先獲得用戶信息,再用MDC.Put(「key」)方法,log在執行sql語句時通過%x{key}來輸出對應的value。
實現步驟:
1、在你的項目中要確保有log4j和commons-logging這兩個jar文件;
2、設置要你要插入日誌信息的表結構
ifexists(select*fromdbo.sysobjectswhereid=object_id(N'[dbo].[WDZLOG]')andOBJECTPROPERTY(id,N'IsUserTable')=1)
droptable[dbo].[WDZLOG]
GO
CREATETABLE[dbo].[WDZLOG](
[WDZLOGID][int]IDENTITY(1,1)NOTNULL,
[LogName][varchar](255)COLLATEChinese_PRC_CI_ASNULL,//用戶ID
[UserName][varchar](255)COLLATEChinese_PRC_CI_ASNULL,//用戶姓名
[Class][varchar](255)COLLATEChinese_PRC_CI_ASNULL,//類名
[Mothod][varchar](255)COLLATEChinese_PRC_CI_ASNULL//,方法名
[CreateTime][varchar](255)COLLATEChinese_PRC_CI_ASNULL,//產生時間
[LogLevel][varchar](20)COLLATEChinese_PRC_CI_ASNULL,//日誌級別
[MSG][varchar](555)COLLATEChinese_PRC_CI_ASNULL//日誌信息
)ON[PRIMARY]
GO
3、配置文件(摘自我們的項目)後面將對此配置文件進行詳細講解,它也log4j的核心部分。
log4j.properties
log4j.rootLogger=INFO,stdout
log4j.logger.org.springframework.web.servlet=INFO,db
log4j.logger.org.springframework.beans.factory.xml=INFO
log4j.logger.com.neam.stum.user=INFO,db
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-ddHH:mm:ss}%p[%c]--<%m>%n
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/exppower.log
log4j.appender.logfile.DatePattern=.yyyy-MM-dd
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d%p[%c]wang-<%m>%n
########################
#JDBCAppender
#######################
#log4j.logger.business=INFO,db
#log4j.appender.db=com.neam.commons.MyJDBCAppender
log4j.appender.db=JDBCExtAppender
log4j.appender.db.BufferSize=10
log4j.appender.db.sqlname=log
log4j.appender.db.driver=net.sourceforge.jtds.jdbc.Driver
log4j.appender.db.URL=jdbc:jtds:SqlServer://localhost:1433;DatabaseName=pubs
log4j.appender.db.user=sa
log4j.appender.db.password=sa
log4j.appender.db.sql=insertintoWDZLOG(LogName,UserName,Class,Mothod,createTime,LogLevel,MSG)values('%X{userId}','%X{userName}','%C','%M','%d{yyyy-MM-ddHH:mm:ss}','%p','%m')
log4j.appender.db.layout=org.apache.log4j.PatternLayout
4、編寫過濾器(ResFilter.java)
importjava.io.IOException;
importjavax.servlet.Filter;
importjavax.servlet.FilterChain;
importjavax.servlet.FilterConfig;
importjavax.servlet.ServletException;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpSession;
importorg.apache.log4j.Logger;
importorg.apache.log4j.MDC;
importcom.neam.domain.User;
{
_USERID=Math.random()*100000.0;
publicvoiddestroy(){
}
publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
FilterChainchain)throwsIOException,ServletException{
HttpServletRequestreq=(HttpServletRequest)request;
HttpSessionsession=req.getSession();
if(session==null){
MDC.put("userId",DEFAULT_USERID);
}
else{
Usercustomer=(User)session.getAttribute("user");
if(customer==null){
MDC.put("userId",DEFAULT_USERID);
MDC.put("userName",DEFAULT_USERID);
}
else
{
MDC.put("userId",customer.getName());
MDC.put("userName",customer.getName());
}
}
//logger.info("testforMDC.");
chain.doFilter(request,response);
}
publicvoidinit(FilterConfigConfig)throwsServletException{
//this.filterConfig=Config;
//Stringccc=Config.getServletContext().getInitParameter("cherset");
//this.targetEncoding=Config.getInitParameter("cherset");
}
}
5、在需要寫入日誌的地方引入
privateLoglogger=LogFactory.getLog(this.getClass());
在具體方法中就可以寫入日誌
logger.info("");
logger.debug("");
logger.warn("");
logger.error("");
配置文件詳解:
log4j.properties
log4j.properties
log4j.rootLogger=INFO,stdout
//配置根Logger,其語法為:
log4j.rootLogger = [ level ] , appenderName1, appenderName2, …
level : 是日誌記錄的優先順序,分為OFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定義的級別。Log4j建議只使用四個級別,優先順序從高到低分別是ERROR、WARN、INFO、DEBUG。通過在這里定義的級別,您可以控制到應用程序中相應級別的日誌信息的開關。比如在這里定義了INFO級別,則應用程序中所有DEBUG級別的日誌信息將不被列印出來。
appenderName:就是指定日誌信息輸出到哪個地方。您可以同時指定多個輸出目的地。
例如:log4j.rootLogger=info,A1,B2,C3 配置了3個輸出地方我們可以設置讓A1在控制台輸出;B2生產日誌文件;C3讓日誌信息插入資料庫中。
本例中是將所有的日誌信息在控制台列印出來。
log4j.logger.org.springframework.web.servlet=INFO,db
//設置將spring下包的某些類的日誌信息寫入資料庫中,並且在控制台上列印出來。(是通過log4j.rootLogger=INFO,stdout來體現的)db是將日誌信息寫入資料庫中
log4j.logger.org.springframework.beans.factory.xml=INFO
//本實例中為了讓某些包下的日誌信息能寫入資料庫
log4j.logger.com.neam.stum.user=INFO,db
//設置自己某個模塊下的日誌信息既在控制台上列印而且往資料庫中保存
//下面是配置在控制台上列印日誌信息,在這里就不再仔細描述了
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] - - <%m>%n
//下面是配置將日誌信息寫入文件中,在這里也就不再仔細描述了
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/exppower.log
log4j.appender.logfile.DatePattern=.yyyy-MM-dd
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] wang- <%m>%n
########################
# JDBC Appender
#######################
#log4j.appender.db=com.neam.commons.MyJDBCAppender
//下面是配置將日誌信息插入資料庫,
log4j.appender.db=org.apache.log4j.jdbc.JDBCAppender
//配置輸出目標為資料庫(假如要將日誌在控制台輸出,配置為log4j.appender. stdout =org.apache.log4j.ConsoleAppender;將日誌寫入文件,配置為log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
這樣的配置在許多地方都要有,需要可查有關資料),當然你也可以自己擴展org.apache.log4j.jdbc.JDBCAppender這個類,只需要在這里配置就可以了例如我們配置我自己擴展的MyJDBCAppender,配置為#log4j.appender.db=com.neam.commons.MyJDBCAppender
log4j.appender.db.BufferSize=10
//設置緩存大小,就是當有10條日誌信息是才忘資料庫插一次
log4j.appender.db.driver=net.sourceforge.jtds.jdbc.Driver
//設置要將日誌插入到資料庫的驅動
log4j.appender.db.URL=jdbc:jtds:SqlServer://localhost:1433;DatabaseName=pubs
log4j.appender.db.user=sa
log4j.appender.db.password=sa
log4j.appender.db.sql=insert into WDZLOG (LogName,UserName,Class,Mothod,createTime,LogLevel,MSG) values ('%X{userId}','%X{userName}','%C','%M','%d{yyyy-MM-dd HH:mm:ss}','%p','%m')
//設置要插入日誌信息的格式和內容,%X{userId}是置取MDC中的key值,因為我們在過濾器中是將用戶id和用戶姓名放入MDC中,所有在這里可以用%X{userId}和%X{userName}取出用戶的ID和用戶姓名;'%C'表示日誌信息是來自於那個類;%M表示日誌信息來自於那個方法中;%d{yyyy-MM-dd HH:mm:ss}表示日誌信息產生的時間,{yyyy-MM-dd HH:mm:ss}表示一種時間格式,你也可以直接寫成%d;%p表示日誌信息的級別(debug info warn error);
%m表示你寫入的日誌信息
log4j.appender.db.layout=org.apache.log4j.PatternLayout