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、設置要你要插入日志信息的表結構
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[WDZLOG]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [dbo].[WDZLOG] GO CREATE TABLE [dbo].[WDZLOG] ( [WDZLOGID] [int] IDENTITY (1, 1) NOT NULL , [LogName] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//用戶ID [UserName] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//用戶姓名 [Class] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//類名 [Mothod] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL //,方法名 [CreateTime] [varchar] (255) COLLATE Chinese_PRC_CI_AS NULL ,//產生時間 [LogLevel] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,//日志級別 [MSG] [varchar] (555) COLLATE Chinese_PRC_CI_AS NULL //日志信息 ) 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-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.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=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') log4j.appender.db.layout=org.apache.log4j.PatternLayout
4、編寫過濾器(ResFilter.java)
import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.log4j.Logger; import org.apache.log4j.MDC; import com.neam.domain.User; public class ResFilter implements Filter{ private final static double DEFAULT_USERID= Math.random()*100000.0; public void destroy() { } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)request; HttpSession session= req.getSession(); if (session==null){ MDC.put("userId",DEFAULT_USERID); } else{ User customer=(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("test for MDC."); chain.doFilter(request, response); } public void init(FilterConfig Config) throws ServletException { // this.filterConfig = Config; // String ccc = Config.getServletContext().getInitParameter("cherset"); // this.targetEncoding = Config.getInitParameter("cherset"); } }
5、在需要寫入日志的地方引入
private Log logger = 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
轉自:http://blog.csdn.net/ziruobing/article/details/3919501
