拓展Log4j基本尝试.md

8 篇文章 0 订阅

上周老大让我拓展下apache的log4j,让其可以把日志内容当做事件,发送到消息队列当中,然后有专门的事件处理来订阅消息,同时事件处理程序和socket关联在一块。客户端通过socket请求日志信息,请求参数构成规则,来决定是否通过socket连接发送日志到客户端。

现在我们把焦点放在“如何在打印日志的时候发消息”,至于事件处理程序暂且不表。
这是一条基本日志信息:
2017-09-05 22:59:00 DEBUG [org.apache.activemq.util.ThreadPoolUtils] Forcing shutdown of ExecutorService: java.util.concurr
我最开始的想法是,将日志内容分为分为4部分:日期,级别,所属类,日志内容。用这4个内容作为规则判断。创建一个Log类:


public class Log implements  Serializable{

	protected Date date;//log日期

	protected Level level;//log的级别

	protected String clazz;//log所属的类全称

	protected Object message;//log的内容

那么如何在打印日志的时候,获取到日志的这4个部分呢?我说一下我的思考过程。最开始打算包装Logger,在日志打印的最外层发送log事件;后来又尝试从打印的日志结果截取log对象发送;这些想法都比较蠢,没有从根本解决问题。昨天了解了log4j的执行流程,还有配置文件的规则和作用,找到了一种非常简单有效的实现方式,直达问题的本质。

###一.简单的包装Logger类,在最外层发送log事件


public class NewLogger extends Logger {
    private Logger logger;

    public NewLogger(Logger logger){
        super(logger.getName());
        this.logger = logger;
    }

    public static NewLogger getNewLogger(Class clazz){
        Logger log = getLogger(clazz);
        //TODO 可能还要检查NewLogger对象是否存在,存在就获取
        return new NewLogger(log);
    }

    @Override
    public void trace(Object message) {
        logger.trace(message);

        sendLogEvent("TRACE", message);
    }
    @Override
    public void debug(Object message){
        logger.debug(message);
        sendLogEvent("DEBUG", message);
    }

    @Override
    public void info(Object message) {
        logger.info(message);
        sendLogEvent("INFO", message);
    }

    @Override
    public void warn(Object message) {
        logger.warn(message);
        sendLogEvent("WARN", message);
    }

    @Override
    public void error(Object message) {
        logger.error(message);
        sendLogEvent("ERROR", message);
    }

    @Override
    public void fatal(Object message) {
        logger.fatal(message);
        sendLogEvent("FATAL", message);
    }

    /**
     * 载入发事件的动作
     *
     */
    protected void sendLogEvent(String level, Object message) {
        String className = logger.getName();
        Level level_ = Level.toLevel(level);
        Log log = new Log(new Date(),level_,className,message);
        //发送事件
     //sendEvent(log);
    }

这是最基本的思路,但是有明显的缺陷。第一,用NewLog构建的对象才能发消息,其他如框架,组件,库等使用Logger,或LoggerFactory的地方任然无法发送事件;第二NewLog是使用Logger对象完成日志的处理,Logger对象可以保证唯一性,同一个class多次构建Logger对象(Logger.getLogger(this.getClass());),也只会生成一个Logger对象,但是NewLogger还需要自己做校验,比较麻烦;第三,时间不准,上面的处理中是打印log之后,new了一个date对象作为时间,虽然有毫秒级的误差,但是终究不是正确的。

二、监听控制台Appender,得到一行行日志信息,将其格式化

看一下log4j.properties配置


log4j.rootLogger=debug, logFile, stdout
log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender 
log4j.appender.logFile.DatePattern='.'yyyy-MM-dd 
log4j.appender.logFile.File=C://log/spring.log 
log4j.appender.logFile.layout=org.apache.log4j.PatternLayout 
log4j.appender.logFile.layout.ConversionPattern=%d - %m%n 
log4j.appender.logFile.Append=true

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %p [%c] %m%n

我们获取stdout的Appender,监听它的输出,从管道中读出来


public void getLogInfo(){
    Logger root = LogManager.getRootLogger();
    if(root==null)    return ;
    // 获取子记录器的输出源
    Appender appender = root.getAppender("stdout");
    // 定义一个未连接的输入流管道
    PipedReader reader = new PipedReader();
    // 定义一个已连接的输出流管理,并连接到reader
    Writer writer = null;
    try {
        writer = new PipedWriter(reader);
    } catch (IOException e) {
        e.printStackTrace();
    }
    // 设置 appender 输出流
    ((WriterAppender) appender).setWriter(writer);
    Scanner scanner = new Scanner(reader);
    while ( scanner.hasNextLine()) {
        try {
            //睡眠
       Thread.sleep(100);
            String line = scanner.nextLine();
            System.out.println("[+]================"+line);
            //TODO 格式化line得到Log对象
         ;
        } catch (Exception ex) {
            //异常信息不作处理
        }
    }
}

这是一种本末倒置的做法,强烈不推荐。

这篇文章就到这里,下篇我会将一种聪明的做法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值