【Log4J 系列】:log4j 整合SpringMVC+MyBatis 實現日誌記錄(01)

1、準備工做

一、工程目錄java

  

二、所需jar包 web

     <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

2、配置log4j

一、修改log4j DailyRollingFileAppender.java 這個類太大就不復制了,直接看關鍵性代碼spring

因爲log4j自帶的DailyRollingFileAppender在根據時間來生成日誌文件時控制檯日誌會顯示Failed to rename(沒法重命名)sql

因此沒辦法根據log4j提供的方法去根據日期生成日誌文件,咱們先去看看log4j的這個BUG數據庫

因爲tomcat在運行期間會一直佔用該文件,在調用該方法的時候就會拋出這個異常來,接下來咱們須要建立本身的DailyRollingFileAppender類,apache

log4j提供的DailyRollingFileAppender類有不少方法在咱們的項目中是沒法重寫的在這裏咱們去繼承DailyRollingFileAppender父類FileAppender.java緩存

文件來達到咱們想要的效果tomcat

public class CmsDailyRollingFileAppender extends FileAppender

 在這裏只爲你們演示關鍵性代碼,PS:這段代碼是在網上Copy下來的,在咱們本身定義的DailyRollingFileAppender 添加一個複製方法用來處理log4j的這個bugapp

boolean copy(File src, File dst) throws IOException {  
          try {  
           InputStream in = new FileInputStream(src);  
           
           OutputStream out = new FileOutputStream(dst);  
           
           // Transfer bytes from in to out  
           byte[] buf = new byte[8192];  
           int len;  
           while ((len = in.read(buf)) > 0) {  
            out.write(buf, 0, len);  
           }  
           in.close();  
           out.close();  
           return true;  
          } catch (FileNotFoundException e) {  
           LogLog.error("源文件不存在,或者目標文件沒法被識別." );  
           return false;  
          } catch (IOException e) {  
           LogLog.error("文件讀寫錯誤.");  
           return false; 
          }
      }

修改rollOver()方法,找到這段代碼幹掉替換成 copy方法保存文件框架

2.配置log4j.properties文件

# 這裏的INFO,Stdout,D,E 看官們能夠理解爲變量,也能夠說是輸出平臺,在下面咱們能夠看到
log4j.rootLogger = info,stdout,D,E # 控制檯輸出,stdout在這裏就對應了上面的變量,consoleAppender 看名字也能夠明白這個是控制檯輸出日誌信息 log4j.appender.stdout = org.apache.log4j.ConsoleAppender
# 這裏沒人的是System.out,也就是輸出 out輸出是黑色字體,err輸出的字體是紅色 log4j.appender.stdout.Target
= System.out
# layout是指佈局,也就是說輸出日誌信息的格式樣式,在這裏咱們使用的是log4j提供的 log4j.appender.stdout.layout
= org.apache.log4j.PatternLayout
# 這裏就是指定咱們日誌文件以哪種格式去輸出 log4j.appender.stdout.layout.ConversionPattern
= [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} %m%n
# INFO級別輸出日誌文件
# 這裏能夠看到使用的是咱們自定義的DailyRollingFileAppender.java log4j.appender.D
= com.nc.rms.log4j.CmsDailyRollingFileAppender
# 指定日誌輸出位置${catalina.home}這個是tomcat的變量,不瞭解的看官能夠自行腦補下 log4j.appender.D.File
= ${catalina.home}/logs/rms/info/info
#這個的意思是指是追加仍是覆蓋 默認是 true true是追加 false是覆蓋 log4j.appender.D.Append
= true
# 這個是指日誌輸出的級別在這裏指定的是 INFO級別 log4j.appender.D.Threshold = INFO
#這個就不作介紹了 log4j.appender.D.layout
= org.apache.log4j.PatternLayout log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
#這裏就根據時間來生成日誌文件了,在這裏爲了演示定義的是每分鐘生成日誌文件 log4j.appender.D.DatePattern
= '.'yyyy-MM-dd-HH-mm'.log' # ERROR級別輸出日誌文件
# 這個跟上面同樣 只不過是日誌級別是 ERROR級的,方便咱們直接查看系統異常信息 log4j.appender.E
= com.nc.rms.log4j.CmsDailyRollingFileAppender log4j.appender.E.File =${catalina.home}/logs/rms/error/error log4j.appender.E.Append = true log4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayout log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n log4j.appender.E.DatePattern = '.'yyyy-MM-dd-HH-mm'.log'
# 記錄日誌至數據庫
# 這裏定義了數據源 log4j.appender.db
=com.nc.rms.log4j.JndiDSAppender
# 這玩意就是每次緩存多少條數據而後插入數據庫,爲了演示這裏設置爲1 log4j.appender.db.BufferSize
=1
# 這裏使用的是tomcat的中提供的數據庫鏈接池
log4j.appender.db.jndiName=java:comp/env/jdbc/DefaultDS
# 看名字也該明白這裏是定義Sql語句的啦 log4j.appender.db.sql
=insert into my_log (ID,DATE,MESSAGE,USER_NAME) values (REPLACE(UUID(), '-', ''),'%d{yyyy-MM-dd HH\:mm\:ss}','%m','%X{userName}')
log4j.appender.db.layout
=org.apache.log4j.PatternLayout
# 這裏定義的哪些包下的日誌信息須要記錄到數據庫當中 log4j.logger.com.nc.rms.manage.web
=info,db log4j.logger.com.nc.rms.service=info,db log4j.logger.com.nc.rms.dao=info,db

3. 在將日誌記錄進數據庫時候 log4j.appender.db=com.nc.rms.log4j.JndiDSAppender 在這裏定義了咱們的DataSource

log4j.appender.db.jndiName=java:comp/env/jdbc/DefaultDS這玩意不瞭解的朋友能夠看下tomcat,context.xml文件

接下來咱們去看看如何獲取數據源,在這裏咱們須要去繼承org.apache.log4j.jdbc.JDBCAppender.java

package com.nc.rms.log4j;

import java.sql.Connection;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.LoggingEvent;

public class JndiDSAppender extends JDBCAppender {

    protected DataSource ds = null;
    protected String jndiName;

    public void setJndiName(String jndiName) {
        this.jndiName = jndiName;
    }
    
    protected synchronized void init() {
        if (ds != null) {
            return;
        }
        try {
            InitialContext context = new InitialContext();
            ds = (DataSource) context.lookup(jndiName);
        } catch (NamingException e) {
            this.errorHandler.error(e.getMessage());
        }
    }
    @Override
    public synchronized void doAppend(LoggingEvent event) {
        if (!StringUtils.isEmpty(name) && "db".equals(name) && closed) {
            closed = false;
        }
        super.doAppend(event);
    }
    
     @Override  
    protected Connection getConnection() throws SQLException {  
        while(ds==null){
            init();
        }
        
        Connection conn = ds.getConnection();
        conn.setAutoCommit(true);
        
        return conn;
    }
    
    @Override  
    protected void closeConnection(Connection conn) {  
        try {  
            if(conn!=null&&!conn.isClosed()) {
                conn.close();  
            } 
        } catch (SQLException e) {  
            this.errorHandler.error(e.getMessage());  
        }  
    }  
}

4.配置Log4jMDCUserFilter過濾器主要是用於配置登陸用戶

 

package com.nc.rms.log4j;

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 org.apache.log4j.MDC;

import com.nc.rms.bean.User;


/**
 * log4j
 * @author Carl
 *
 */
public class Log4jMDCUserFilter implements Filter {

    private final String LOG4J_USER_ACCOUNT = "account";

    private final String LOG4J_USER_NAME = "userName";
    
    private final String LOG4J_REMOTE_UNITID = "remoteUnitId";

    
    public Log4jMDCUserFilter() {
    }

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        try {
            User user = (User) req.getSession().getAttribute("user");
            if (user != null) {
                MDC.put(LOG4J_REMOTE_UNITID, user.getName());
                MDC.put(LOG4J_USER_ACCOUNT, user.getName());
                MDC.put(LOG4J_USER_NAME, user.getName());
            }else {
                MDC.put(LOG4J_REMOTE_UNITID, LOG4J_REMOTE_UNITID);
                MDC.put(LOG4J_USER_ACCOUNT, LOG4J_USER_ACCOUNT);
                MDC.put(LOG4J_USER_NAME, LOG4J_USER_NAME);
            }
        } catch (Exception e) {
        }
        chain.doFilter(request, response);
    }

    public void init(FilterConfig fConfig) throws ServletException {

    }

}

 

5.配置web.xml文件,寫了這麼多,認真的朋友或許已經發現無論那個框架哪門技術都離不開配置web.xml

喜歡看web項目源碼的朋友能夠先從web.xml 去了解該項目究竟使用了哪些技術。廢話點到爲止看配置

<!-- 配置log4j  %X{userName} ,主要用於將日誌記錄數據庫中,如:userName 作了什麼樣的操做-->
    <filter>
        <filter-name>Log4jMDCUserFilter</filter-name>
        <filter-class>com.nc.rms.log4j.Log4jMDCUserFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Log4jMDCUserFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!--設置log4j的配置文件位置 -->
    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>classpath:conf/log4j.properties</param-value>
    </context-param>
    
    <!--使用監聽加載log4j的配置文件 -->
    <listener>
        <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
    </listener>

一切準備就緒運行起來看看效果吧!

數據庫記錄正常

 

日誌文件按照分鐘生成成功。

相關文章
相關標籤/搜索