扩展log4j系列[二]动态、分文件记log

一。背景分析      

log4j 即便配置到炉火纯青,也无法回避大家面临的日志问题:

       1.单个文件无法装下足够的log。曾经在IDC繁忙时,一个10M的log文件只可以支撑不到2分钟, 最大滚10个的话,那么20分钟以前出现的bug就找不到日志了。

       2.都往一个地方记,不同模块的人记录内容不均,有的人一个操作打一屏log,有的人异常了都不记日志。。不好管理。

       3. 如此快速的日志滚动,通过tail -f 去观察简直就是一个悲剧。

 

二。具体实现

        这里提到的分文件记log,不是在log4j.properties里面一个个类的去指定输出到哪个文件。。这样每次修改、新增模块都需要改配置,而且不能动态的把一系列操作的日志轨迹串联起来。

 

       1.下面分析了一下log4j几个核心类的关系,注意我们调用得最多的Logger对象(Category这个类已经被子类Logger代替,并且不推荐使用)


 

它从根类继承了这么一个犀利的方法:addAppender , 我们可以在Logger实例化的时候,顺带给它加上自己定制的appender

 

  /**
     Add <code>newAppender</code> to the list of appenders of this
     Category instance.

     <p>If <code>newAppender</code> is already in the list of
     appenders, then it won't be added again.
  */
  synchronized
  public
  void addAppender(Appender newAppender) {
    if(aai == null) {
      aai = new AppenderAttachableImpl();
    }
    aai.addAppender(newAppender);
    repository.fireAddAppenderEvent(this, newAppender);
  }

 

 

 

       2.那么appender有什么好玩意呢?看起来真的很一般,但是它的子类FileAppender就 NB了,注意,有带fileName参数的构造器!!想把日志写到哪个文件,就看你是否会犀利的构造FileAppender了。

 

public class FileAppender extends WriterAppender {
  protected boolean bufferedIO = false;
  protected int bufferSize = 8*1024;

  FileAppender() {
  }


  public
  FileAppender(Layout layout, String filename, boolean append, boolean bufferedIO,
	       int bufferSize) throws IOException {
    this.layout = layout;
    this.setFile(filename, append, bufferedIO, bufferSize);
  }

   public
  FileAppender(Layout layout, String filename, boolean append)
                                                             throws IOException {
    this.layout = layout;
    this.setFile(filename, append, false, bufferSize);
  }

  public
  FileAppender(Layout layout, String filename) throws IOException {
    this(layout, filename, true);
  }

 

 

3.总结一下:

   看起来是这样:在logger第一次初始化的时候,添加我自己的fileappender,

 

public void logXXX(String busiModule, Object message) {
		String logName = "runtime."+busiModule; //log的name
		org.apache.log4j.Logger logger = Log4jFactory.getInstance(logName);
		if (logger.getAppender(logName) == null) {
			initMyAppender(logName, busiModule+".log",	logger);
		}

 

 

   

* 初始化方法里面,使用了带指定filename参数的Fileappender,赋予appender单独的文件。

 

	 * @param appenderName
	 * @param logFileName
	 * @param log
	 */
	private void initMyAppender(String appenderName, String logFileName,	org.apache.log4j.Logger  log) {
		try {

			//1.创建log文件目录
			File fileDir = new File(LogDir);
			if (!fileDir.exists()) {
				fileDir.mkdirs();
			}
			//2.创建appender
			RollingFileAppender fileAppender;
			PatternLayout patternLayout = new PatternLayout();
			patternLayout.setConversionPattern("%d{yyyy-MM-dd HH:mm:ss} %m%n");
			fileAppender = new RollingFileAppender(patternLayout, LogDir+logFileName);
			fileAppender.setMaxFileSize(maxFileSize);
			fileAppender.setMaxBackupIndex(maxBackupIndex);
			fileAppender.setName(appenderName);
			log.addAppender(fileAppender);
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

 

 

那么在使用的时候,除了记录的消息对象,还需要额外提供一个String字段的model,相同的model导致相同的logger对象,会记录在一个文件;不同的model参数会使得日志分开记录到各自文件。关于这个参数,通常有两种提供方案:

1.选择包名的某个单词,比如"item","deal"传入,这样就是分业务模块记录。

2.使用ThreadLoacl,将用户访问的session做model,这样就可以在一个文件中完整记录用户访问的所有轨迹。

以上两种方案的model则,还以进一步通过封装到接口中,使得调用者无需关心具体model值。

 

 

FAQ:

1.addApender,每个log那不是有多个appender了么?用文件记录岂不是会写多份,耗IO的。。

~~请大家关心一下log4j的这个属性additivity:(#log4j.additivity.runtime=false)

 

more???

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值