记录使用log4j定制开发

需求:总客户和分客户登陆日志,要求目录结构

logs
 |
 |-- login.log
 |-- A000008 
 |     |-- login.log
 |-- A000009     
       |-- login.log
分析:总客户的日志比较好做,配置一下单独的输出文件就可以,配置见

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  
  <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">  
    <!-- Console output -->  
    <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">  
        <layout class="org.apache.log4j.PatternLayout">  
            <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss} %m  (%F:%L) \n" />  
        </layout>  
    </appender>  
   <!--全局登陆日志-->
     <appender name="allClientLoginAppender" class="org.apache.log4j.FileAppender">  
        <param name="file" value="../logs/login.log" />    
        <param name="append" value="true" /> 
       	<layout class="org.apache.log4j.PatternLayout">  
         	<param name="ConversionPattern" value="%-5p %d{yyyy-MM-dd HH:mm:ss} %m  \n" />   
        </layout> 
    </appender> 
     <category name="java.sql">
        <priority value="debug"/>
    </category>
    	<logger name="com.lizp.framework.interceptor.LoginInterceptor">
		 <appender-ref ref="allClientLoginAppender"/>
	</logger>	
    <root>
        <priority value="info"/>
        <appender-ref ref="STDOUT"/>
       </root>
  
</log4j:configuration> 

难点:输出日志中检出含clientNo并输出到指定clientNo下面的文件夹下,呵呵,大家先考虑一下。

—————————————————————————————————————————————————————————————

分客户的肯定与总的日志相差不大,只是多了一个过滤功能。只好先看下log4j中FileAppender了

FileAppender类

FileAppender继承自WriterAppender,它将日志写入文件。主要的日志写入逻辑已经在WriterAppender中处 理,FileAppender主要处理的逻辑主要在于将设置日志输出文件名,并通过设置的文件构建WriterAppender中的 QuiteWriter字段实例。如果Log文件的目录没有创建,在setFile()方法中会先创建目录,再设置日志文件。另外,所有 FileAppender字段在调用activateOptions()方法中生效。

(上述解析来自http://www.cnblogs.com/duanxz/archive/2013/02/01/2889500.html

WriterAppender又依赖于AppenderSkeleton,里面的这个方法是写入文件的,注意中间有个Filter,过滤字符

  /**
    * This method performs threshold checks and invokes filters before
    * delegating actual logging to the subclasses specific {@link
    * AppenderSkeleton#append} method.
    * */
  public
  synchronized 
  void doAppend(LoggingEvent event) {
    if(closed) {
      LogLog.error("Attempted to append to closed appender named ["+name+"].");
      return;
    }
    
    if(!isAsSevereAsThreshold(event.getLevel())) {
      return;
    }

    Filter f = this.headFilter;
    
    FILTER_LOOP:
    while(f != null) {
      switch(f.decide(event)) {
      case Filter.DENY: return;
      case Filter.ACCEPT: break FILTER_LOOP;
      case Filter.NEUTRAL: f = f.getNext();
      }
    }
    
    this.append(event);    
  }


在org.apache.log4j.varia下发现StringMatchFilter,匹配相应的字符并过滤到,与需求相近了(这里我的想法是不可能要把其他的clientNo都匹配过滤吧,也得想法改写了)

  /**
     Returns {@link Filter#NEUTRAL} is there is no string match.
   */
  public
  int decide(LoggingEvent event) {
    String msg = event.getRenderedMessage();

    if(msg == null ||  stringToMatch == null)
      return Filter.NEUTRAL;
    

    if( msg.indexOf(stringToMatch) == -1 ) {
      return Filter.NEUTRAL;
    } else { // we've got a match
      if(acceptOnMatch) {
	return Filter.ACCEPT;
      } else {
	return Filter.DENY;
      }
    }


而这里我是要抓取字符串,也就是把if( msg.indexOf(stringToMatch) != -1 ) { // 更改为只接受对应的字符串,而原来的是只过滤到相应的字符串

public class StringCatchFilter extends StringMatchFilter {
  
  /**
     @deprecated Options are now handled using the JavaBeans paradigm.
     This constant is not longer needed and will be removed in the
     <em>near</em> term.
   */
  public static final String STRING_TO_MATCH_OPTION = "StringToMatch";

  /**
     @deprecated Options are now handled using the JavaBeans paradigm.
     This constant is not longer needed and will be removed in the
     <em>near</em> term.
   */
  public static final String ACCEPT_ON_MATCH_OPTION = "AcceptOnMatch";
  
  boolean acceptOnMatch = true;
  String stringToMatch;
  
  /**
     Returns {@link Filter#NEUTRAL} is there is no string match.
   */
  public
  int decide(LoggingEvent event) {
    String msg = event.getRenderedMessage();

    if(msg == null ||  stringToMatch == null)
      return Filter.NEUTRAL;
    

    if( msg.indexOf(stringToMatch) != -1 ) { // 更改为只接受对应的字符串,而原来的是只过滤到相应的字符串
      return Filter.NEUTRAL;
    } else { // we've got a match
      if(acceptOnMatch) {
	return Filter.ACCEPT;
      } else {
	return Filter.DENY;
      }
    }
  }
}


 

恩,过滤器符合要求了,余下的任务就是生成文件了。

创建一个FileAppender继承原来的FileAppender重写一下doAppend就可以了

public
  synchronized 
  void doAppend(LoggingEvent event) {
    if(closed) {
      LogLog.error("Attempted to append to closed appender named ["+name+"].");
      return;
    }
    
    if(!isAsSevereAsThreshold(event.getLevel())) {
      return;
    }

    Filter f = this.headFilter;
    
    Subject currentUser = SecurityUtils.getSubject(); // 获取到session中clientNo的值
	  Session session = currentUser.getSession();
	  if(null != session){
		  String clientCode = (String) session.getAttribute(Constants.SESSION_CLIENTNO);
		  if(!StringUtils.isEmpty(clientCode)){
			  FILTER_LOOP:
				    while(f != null) {
				    	if(f instanceof StringCatchFilter){
				    				  StringCatchFilter ff = (StringCatchFilter)f;
				    					  ff.setStringToMatch(clientCode);   // 动态设置参数拦截指定的clientNo下的登陆信息
				    			} 
				      switch(f.decide(event)) {
				      case Filter.DENY: return;
				      case Filter.ACCEPT: break FILTER_LOOP;
				      case Filter.NEUTRAL: f = f.getNext();
				      }
				    }
					try {
						this.setFile("../logs/"+clientCode+"/login.log",fileAppend,bufferedIO,bufferSize); // 动态设置拦截日志的输出路径
					} catch (IOException e) {
						e.printStackTrace();
					}
		  }
		  this.append(event); // 追加日志,包含登出error和登陆info
	  }
    
  }

拦截到session中的clientNo并决定输出到那个客户下的日志文件中
当然还需要配置下log4j.xml

    <!--分客户登陆日志-->
     <appender name="eachClientLoginAppender" class="com.lizp.util.FileAppender"> 
   <!-- <param name="file" value="../logs/login.log" /> -->    
        <param name="encoding" value="UTF-8" />  
        <param name="append" value="true" /> 
        <layout class="org.apache.log4j.PatternLayout">  
         	<param name="ConversionPattern" value="%-5p %d{yyyy-MM-dd HH:mm:ss} %m  \n" />   
        </layout> 
        <filter class="com.lizp.util.StringCatchFilter">
        <!-- <param name="StringToMatch" value="A0000001" /> -->   
             <param name="AcceptOnMatch" value="false" />
        </filter>
    </appender> 


 然后就可以看到目录结构和生成日志了

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值