log4j 滚动日志 及 实现操作日志

Posted TT_DUL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了log4j 滚动日志 及 实现操作日志相关的知识,希望对你有一定的参考价值。

1、建立log4j.xml 文件

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  

<log4j:configuration>  

 <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">  
      <layout class="org.apache.log4j.PatternLayout">  
       <param name="ConversionPattern"  
        value="%dyyyy-MM-dd HH:mm:ss [%t] %-5p %c - %m%n" />  
      </layout>  

      <!--限制输出级别-->  
      <filter class="org.apache.log4j.varia.LevelRangeFilter">  
       <param name="LevelMax" value="ERROR"/>  
       <param name="LevelMin" value="TRACE"/>  
      </filter>  
 </appender>  

 <appender name="FILE" class="org.apache.log4j.FileAppender">  
      <param name="File" value="/data/log/error.log"/>  
      <layout class="org.apache.log4j.PatternLayout">  
       <param name="ConversionPattern"  
        value="%dyyyy-MM-dd HH:mm:ss [%t] %-5p %c - %m%n" />  
      </layout>  
      <filter class="org.apache.log4j.varia.LevelRangeFilter">  
       <param name="LevelMax" value="ERROR"/>  
       <param name="LevelMin" value="TRACE"/>  
      </filter> 
 </appender>   

  <apender name="ROLLING_FILE" class="org.apache.log4j.RollingFileAppender">
      <param name="File" value="/data/log/rolling.log"/> 
      <param name="Append" value="true"/> 
      <param name="MaxFileSize" value="1024KB"/> 
      <layout class="org.apache.log4j.PatternLayout"> 
          <param name="ConversionPattern"  
            value="%dyyyy-MM-dd HH:mm:ss [%t] %-5p %c - %m%n" />  
      </layout>

  </apender>

 <appender name="DATABASE" class="com.test.sys.log.MyJDBCAppender">  
      <param name="Threshold" value="INFO" />  
      <filter class="com.test.sys.log.CustomWarnLevelFilter">     
        </filter> 
      <layout class="org.apache.log4j.PatternLayout">  
           <param name="ConversionPattern"  
            value="INSERT INTO account_operate_log (aol_id,operate_type,operate_content,operate_result,user_id,user_name,operate_date,operate_ip,organization) VALUES(UUID(),'%Xoperate','%Xcontent',1,%Xuserid,'%Xusername',%dyyyyMMddHHmmss,'%Xip','%Xorganization')" />  
      </layout>  
 </appender>  



 <appender name="ASYNC" class="org.apache.log4j.AsyncAppender">  
  <param name="BufferSize" value="256" />  
  <appender-ref ref="ROLLING_FILE" /> 
  <appender-ref ref="FILE" /> 
 </appender>  



 <root>  
  <priority value="debug" />  
  <appender-ref ref="CONSOLE" />  
  <appender-ref ref="FILE" /> 
  <appender-ref ref="ROLLING_FILE" /> 
  <appender-ref ref="DATABASE" />
  <appender-ref ref="ASYNC" />      
 </root>  


</log4j:configuration>  

2、com.test.sys.log.MyJDBCAppender 依赖类的实现


import java.sql.Connection;
import java.sql.SQLException;
import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.ErrorCode;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.alibaba.druid.pool.DruidDataSource;

/**

* @Description MyJDBCAppender.java

* 用于Log4j的数据库Session管理[连接池用Druid]

* @version 1.0

*/

public class MyJDBCAppender extends JDBCAppender



        /* Druid数据源 */

        private static DruidDataSource dataSource;

        public MyJDBCAppender() 

            super();

        

        static
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
             dataSource= (DruidDataSource) context.getBean("dataSource");
// 这里博主是用的alibaba 的Druid 的连接池  ,原先使用的c3p0连接池,使用此种方式获取不到连接池,而且项目中,c3p0总是关闭连接错误,所以果断改为了Druid ,不失所望,Druid 很好用,效率很高,Druid连接池的配置会贴在此文最后
        

        @Override
        protected void closeConnection(Connection con) 

            try 

                /* 如果数据库连接对象不为空和没有被关闭的话,关闭数据库连接 */

                if ( con != null && !con.isClosed())

                con.close();

             catch (SQLException e) 

                errorHandler.error("Error closing MyJDBCAppender.closeConnection() 's connection",e,ErrorCode.GENERIC_FAILURE);

            

        

        @Override 
        protected Connection getConnection() throws SQLException 

            return dataSource.getConnection();
        

        /* 取消初始化 */

        public void uninitialize() 

                try 

                    if (dataSource != null)

                        dataSource.close();

                 finally 

                    super.close();

                

        

3、com.test.sys.log.CustomWarnLevelFilter 依赖类的实现

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.spi.LoggingEvent;
import org.slf4j.MDC;

public class CustomWarnLevelFilter extends org.apache.log4j.spi.Filter

    @Override
    public int decide(LoggingEvent event) 


        //大于等于WARN的日志不允许输出
//      if(event.getLevel().toInt() >= Level. WARN.toInt()) 
//          return DENY;
//       else 
//          return ACCEPT;
//      

        event.getMDCCopy();
        if(event.getMessage()!=null && isContainChinese(event.getMessage().toString()) && null !=event.getMDC("userid"))

            if( isContainGt(event.getMessage().toString()))
                String[] split = event.getMessage().toString().split(">");

                MDC.put("operate", split[0]+"");
                MDC.put("content", event.getMessage().toString()+"");

                return ACCEPT;

            else if( event.getMessage().toString().indexOf("登录")>-1 || event.getMessage().toString().indexOf("退出")>-1 
                    || event.getMessage().toString().indexOf("列表")>-1 || event.getMessage().toString().indexOf("主页")>-1 || event.getMessage().toString().indexOf("导入")>-1)

                MDC.put("operate", event.getMessage().toString());
                MDC.put("content", event.getMessage().toString());

                return ACCEPT;
            else
                return DENY;
            

        else
            return DENY;
        

    

     public static boolean isContainChinese(String str) 

            Pattern p = Pattern.compile("[\\u4e00-\\u9fa5]");
            Matcher m = p.matcher(str);
            if (m.find()) 
                return true;
            
            return false;
        

     public static boolean isContainGt(String str) 

         Pattern p = Pattern.compile("(.*)(?:>)");
            Matcher m = p.matcher(str);
            if (m.find()) 
                return true;
            
            return false;
        

4、在登陆的拦截器 中要将 userId 和 企业id 放入MDC 中去,然后在log4j.xml 中 用 %Xuserid 方式可取出其值

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class LoginInterceptor extends HandlerInterceptorAdapter
private static final Logger LOG = LoggerFactory.getLogger(LoginInterceptor.class);

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception 
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        if ("GET".equalsIgnoreCase(request.getMethod()))   
         
        String requestUri = request.getRequestURI();  
        LOG.info("requestUri:"+requestUri);    
        String requestURI = request.getRequestURI();

        if(null != request.getSession(false))

             UserInfo user = (UserInfo) request.getSession(false).getAttribute("UserInfo");

             if(null == user)

                LOG.info("未登录,请先登录");
                request.getSession(false).setAttribute("msg", "用户未登录,请先登录");
             request.getRequestDispatcher("/pages/login.jsp").forward(request, response);  

                 return false;  
             else
                 MDC.put("userid", user.getUserId()+"");
                 MDC.put("username", user.getUserName()+"");
                 MDC.put("ip", request.getRemoteAddr()+"");

                Enterprise enter = (Enterprise) request.getSession(false).getAttribute("Enterprise");

                if(null !=user.getOrganizationId())
                    MDC.put("organization", enter.getEnterprise()+"");
                else
                    MDC.put("organization","");
                
             
        else
            LOG.info("未登录,请先登录");
     request.getRequestDispatcher("/pages/login.jsp").forward(request, response);      
            return false;  
        
        return true;

5、applicationContext.xml 中的Druid 连接池的配置

<!-- 配置数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
          <!-- 基本属性 url、user、password -->
          <property name="driverClassName" value="com.mysql.jdbc.Driver" />
          <property name="url" value="jdbc:mysql://********:3306/logistic?useUnicode=true&amp;characterEncoding=utf-8" />
          <property name="username" value="****" />
          <property name="password" value="****" />

          <!-- 配置初始化大小、最小、最大 -->
          <property name="initialSize" value="5" />
          <property name="minIdle" value="10" /> 
          <property name="maxActive" value="20" />

          <!-- 配置获取连接等待超时的时间 -->
          <property name="maxWait" value="60000" />

          <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
          <property name="timeBetweenEvictionRunsMillis" value="60000" />

          <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
          <property name="minEvictableIdleTimeMillis" value="300000" />

          <property name="validationQuery" value="SELECT 'x'" />
          <property name="testWhileIdle" value="true" />
          <property name="testOnBorrow" value="false" />
          <property name="testOnReturn" value="false" />

          <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
          <property name="poolPreparedStatements" value="true" />
          <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />

          <!-- 配置监控统计拦截的filters -->
          <property name="filters" value="stat" />
    </bean>

6、在web.xml 中加入Druid 的监控,启动应用,访问http://localhost/应用名/monitor/ 就可以看到Druid 的监控页面了

     <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
     </servlet>
     <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/monitor/*</url-pattern>
     </servlet-mapping>

以上是关于log4j 滚动日志 及 实现操作日志的主要内容,如果未能解决你的问题,请参考以下文章

Log4J日志配置详解和自定义log4j日志级别及输出日志到不同文件实现方法

Mybatis之Log4j实现日志说明及Limit实现分页

log4j2.properties 弹性集群日志滚动和压缩问题

log4j笔记:升级2.X版本的日志滚动问题

多进程log4j日志混乱问题分析

log4j2 异步日志原理及配置