扩展log4j系列[二]动态、分文件记log
来源:互联网 发布:一个人做淘宝 心酸 编辑:程序博客网 时间:2024/06/05 16:30
一。背景分析
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的nameorg.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.创建appenderRollingFileAppender 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???