• 基于log4j的消息流的实现之一消息获取


    需求:

    目前的程序中都是基于log4j来实现日志的管理,想要获取日志中的一部分消息,展示给用户。

    约束:

    由于程序中除了自己开发的代码,还会有层层依赖的第三方jar中的日志输出。需要展示给用户的消息,也有部分包括在第三方的包中。不可能去修改第三方jar来获得消息,所以只能从Log4j本身的消息入手,获取log4j的消息来进行处理。

    方案:

    第一步,增加新的logger

     1 log4j.rootLogger=INFO, console
     2 
     3 log4j.appender.console=org.apache.log4j.ConsoleAppender
     4 log4j.appender.console.layout=org.apache.log4j.PatternLayout
     5 log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %-20c %X{key}  %x - %m%n
     6 
     7 log4j.logger.hermes=INFO, hermes
     8 log4j.appender.hermes=org.apache.log4j.ConsoleAppender
     9 log4j.appender.hermes.layout=org.apache.log4j.PatternLayout
    10 log4j.appender.hermes.layout.ConversionPattern=%X{key} %x  %m%n
    11 
    12 log4j.logger.org.apache.flink.yarn=INFO, hermes

    如上,第1行定义了一个全局的logger,这个没有疑义,所有的日志都会输出到这个logger。

    关键是第7行,又定义了一个叫hermes的logger,它有一个同名的appender叫hermes,简化了他的layout,只是拿出必须的输出日志即可。注意这里有一个%X{key}的配置项,这里是为了拿到MDC的值,好区分这条消息是哪个session打印出来的。

    第12行也很关键,将包org.apache.flink.yarn的日志都按照hermes是标准输出,这里是包名,当然也可以指定到具体的类名。

    如此这样,对于包org.apache.flink.yarn中的日志,会打印两份,一份是以console的形式输出,一份是以hermes的形式输出。

    当然,我们不希望在日志中见到两行实质上一样的内容,这就是第二步要做到事情。

    第二步:截取消息

    这里有两个方案:一个方案是自定义appender,获取消息;一个方案是获取指定的logger,获取消息。

    方案1:自定义appender

     1 import org.apache.log4j.AppenderSkeleton;
     2 import org.apache.log4j.LogManager;
     3 import org.apache.log4j.spi.LoggingEvent;
     4 import org.slf4j.Logger;
     5 import org.slf4j.LoggerFactory;
     6 
     7 public class AdapterAppender extends AppenderSkeleton {
     8     @Override
     9     protected void append(LoggingEvent loggingEvent) {
    10         String message = this.layout.format(loggingEvent);
    11         System.out.println("<<<<<<<<<<***********"+message+"***********>>>>>>>>>>");
    12     }
    13 
    14     @Override
    15     public void close() {
    16 
    17     }
    18 
    19     @Override
    20     public boolean requiresLayout() {
    21         return true;
    22     }
    23 }

    自定义appender还是很简单的,只要继承AppenderSkeleton即可。其中的append方法就可以拿到日志消息,标准化之后就可以拿来用了。

    当然,上面log4j的配置也就需要改下了:

    log4j.appender.hermes=cn.123.flink.log.AdapterAppender

    方案2:获取logger来获取消息

     1 import java.io.IOException;
     2 import java.io.PipedReader;
     3 import java.io.PipedWriter;
     4 import java.io.Writer;
     5 import java.util.Scanner;
     6 
     7 import org.apache.log4j.*;
     8 
     9 public class LogAppender extends Thread{
    10 
    11     private PipedReader reader;
    12 
    13     public LogAppender(String appenderName) {
    14         try {
    15             Logger root = Logger.getLogger(appenderName);
    16             // 获取子记录器的输出源
    17             Appender appender = root.getAppender(appenderName);
    18             // 定义一个未连接的输入流管道
    19             reader = new PipedReader();
    20             // 定义一个已连接的输出流管理,并连接到reader
    21             Writer writer = new PipedWriter(reader);
    22             // 设置 appender 输出流
    23             ((WriterAppender) appender).setWriter(writer);
    24         }catch (IOException ioe){
    25             ioe.printStackTrace();
    26         }
    27     }
    28 
    29     @Override
    30     public void run() {
    31         // 不间断地扫描输入流
    32         Scanner scanner = new Scanner(reader);
    33         // 将扫描到的字符流显示在指定的JLabel上
    34         while (scanner.hasNextLine()) {
    35             try {
    36                 String line = scanner.nextLine();
    37                 System.out.println("*****************************"+line);
    38                 //睡眠
    39                 Thread.sleep(100);
    40             } catch (Exception ex) {
    41                 System.out.println("Exception from LogAppender:"+ex.getMessage());
    42             }
    43         }
    44     }
    45 }

    对比上面的日志的配置,13行的构造函数就可以传入hermes来获取hermes这个logger。

    参考了下面的文档:

    http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html

    http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/MDC.html

    http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/NDC.html

    https://logging.apache.org/log4j/2.x/manual/thread-context.html

    http://yshjava.iteye.com/blog/1325036

    https://stackoverflow.com/questions/2763740/log4j-log-output-of-a-specific-class-to-a-specific-appender

    https://stackoverflow.com/questions/5549838/get-live-log4j-messages

    https://sysgears.com/articles/how-to-redirect-stdout-and-stderr-writing-to-a-log4j-appender/

  • 相关阅读:
    DotNET应用架构设计指南 安全 运行管理和通讯策略
    开放、主动、好学、谦虚
    粉丝经济
    选个大市场,组建最优秀的团队,拿到花不完的钱(转)
    一个人,可以看他的学识,他的气质,他的丰采,他的谈吐(转)
    Java基础—ClassLoader的理解(转)
    数据库置疑问题解决
    Android应用中使用百度地图API定位自己的位置(二)
    Hopcroft-Karp算法模版
    html表单提交的几种方法
  • 原文地址:https://www.cnblogs.com/029zz010buct/p/9449097.html
Copyright © 2020-2023  润新知