需求:

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

约束:

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

方案:

第一步,增加新的logger

 log4j.rootLogger=INFO, console

 log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p %-20c %X{key} %x - %m%n log4j.logger.hermes=INFO, hermes
log4j.appender.hermes=org.apache.log4j.ConsoleAppender
log4j.appender.hermes.layout=org.apache.log4j.PatternLayout
log4j.appender.hermes.layout.ConversionPattern=%X{key} %x %m%n 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

 import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggingEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class AdapterAppender extends AppenderSkeleton {
@Override
protected void append(LoggingEvent loggingEvent) {
String message = this.layout.format(loggingEvent);
System.out.println("<<<<<<<<<<***********"+message+"***********>>>>>>>>>>");
} @Override
public void close() { } @Override
public boolean requiresLayout() {
return true;
}
}

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

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

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

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

 import java.io.IOException;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.io.Writer;
import java.util.Scanner; import org.apache.log4j.*; public class LogAppender extends Thread{ private PipedReader reader; public LogAppender(String appenderName) {
try {
Logger root = Logger.getLogger(appenderName);
// 获取子记录器的输出源
Appender appender = root.getAppender(appenderName);
// 定义一个未连接的输入流管道
reader = new PipedReader();
// 定义一个已连接的输出流管理,并连接到reader
Writer writer = new PipedWriter(reader);
// 设置 appender 输出流
((WriterAppender) appender).setWriter(writer);
}catch (IOException ioe){
ioe.printStackTrace();
}
} @Override
public void run() {
// 不间断地扫描输入流
Scanner scanner = new Scanner(reader);
// 将扫描到的字符流显示在指定的JLabel上
while (scanner.hasNextLine()) {
try {
String line = scanner.nextLine();
System.out.println("*****************************"+line);
//睡眠
Thread.sleep(100);
} catch (Exception ex) {
System.out.println("Exception from LogAppender:"+ex.getMessage());
}
}
}
}

对比上面的日志的配置,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/

基于log4j的消息流的实现之一消息获取的更多相关文章

  1. Storm概念学习系列之Stream消息流 和 Stream Grouping 消息流组

    不多说,直接上干货! Stream消息流是Storm中最关键的抽象,是一个没有边界的Tuple序列. Stream Grouping 消息流组是用来定义一个流如何分配到Tuple到Bolt. Stre ...

  2. Stream消息流 和 Stream Grouping 消息流组

  3. 基于log4j的消息流的实现之二消息传递

    在“基于log4j的消息流的实现之一消息获取”中获取日志消息的部分,修改如下: import org.apache.commons.collections.map.HashedMap; import ...

  4. [蓝牙] 6、基于nRF51822的蓝牙心率计工程消息流Log分析(详细)

    开机初始化Log Log编号 函数名   所在文件名 000001: main ..\main.c 000002: timers_init ..\main.c 000003: gpiote_init ...

  5. 开源一个自己造的轮子:基于图的任务流引擎GraphScheduleEngine

    GraphScheduleEngine是什么: GraphScheduleEngine是一个基于DAG图的任务流引擎,不同语言编写.运行于不同机器上的模块.程序,均可以通过订阅GraphSchedul ...

  6. BTARN 接收消息流以3A7为例

     1.RNIFReceive.aspx 页接收来自发起方的传入消息. (如果发起方是BizTalk则类似于:http://localhost/BTARNApp/RNIFSend.aspx?TPUrl ...

  7. 大数据平台消息流系统Kafka

    Kafka前世今生 随着大数据时代的到来,数据中蕴含的价值日益得到展现,仿佛一座待人挖掘的金矿,引来无数的掘金者.但随着数据量越来越大,如何实时准确地收集并分析如此大的数据成为摆在所有从业人员面前的难 ...

  8. IM系统-消息流化一些常见问题

    原创不易,求分享.求一键三连 之前说过IM系统的一些优化,但是在网络上传输数据对于数据的流化和反流化也是处理异常情况的重点环节,不处理好可能会出现一些消息发送成功,但是解析失败的情况,本文就带大家来一 ...

  9. 基于SQL Server 2008 Service Broker构建企业级消息系统

    注:这篇文章是为InfoQ 中文站而写,文章的地址是:http://www.infoq.com/cn/articles/enterprisemessage-sqlserver-servicebroke ...

随机推荐

  1. 选择客栈(noip2011 day1 t2)

    题目描述 丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从 1 到 nn n 编号.每家客栈都按照某一种色调进行装饰(总共 k 种,用整数 0 ~ k−1 表示),且每家客栈都设有一家咖啡店,每 ...

  2. [洛谷]P3704-数字表格

    [洛谷]P3704-数字表格 妙啊,这又是一道反演题,而且个人感觉比较高级 传送门 大意 在\(N\times M\)的数表\(a\)中,\(a_{i,j}\)表示f((i,j)),其中\((i,j) ...

  3. 新手学习ARM,对片内ram、SDRAM、NOR FLASH和NAND FLASH启动这几个概念的理解

    片内的ram用来存储启动代码,在2440初始化sdram之前,代码就在片内ram中运行.片内ram装载的是norflash中的内容,即u-boot. uboot放在norflash里,nandflas ...

  4. 抽象类实验:SIM卡抽象

    抽象SIM: package sim_package; public abstract class SIM { public abstract String giveNumber(); public ...

  5. JavaSE基础复习---Class类与反射机制

    ---恢复内容开始--- 目录: 1.java.lang.class类 2.Java中的反射机制 3.运行时与编译时概念 1. java.lang.class类 Java程序在运行时,Java运行时系 ...

  6. 当安装mongodb客户端出现了Failed to load list of databases

    在装mongodb最新版(4.1.5开发版)服务后,我用robo3t打开它的时候遇到了这个问题. 最直接的解决办法就是换一个mongodb版本,https://github.com/Studio3T/ ...

  7. JAVA学习一 对象数组

    对象数组 今天在写一个代码,才发现自己对于对象数组的理解是不够的,那么就讲讲自己现在的理解. 对于数组中的每一个元素都是一个针对对象的引用 他会指向你的具体的一个堆上的对象,它本身知识一个地址值,与其 ...

  8. c/c++容器操作

    C++中的容器大致可以分为两个大类:顺序容器和关联容器.顺序容器中包含有顺序容器适配器. 顺序容器:将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素.主要有vector.list.de ...

  9. Close Java Auto Update in Windows 7 and Later

    0. Environment Windows 7JDK 1.6.0_45 1. Steps 1) Enter "JRE/bin" 2) Run javacpl.exe as adm ...

  10. 使用PSSH批量操作Linux服务器

    简介 服务器多了,有一个问题就是如何批量快速操作多台服务器,在网上搜到了PSSH工具,试用了一下发现挺好用,推荐给大家. pssh是一个python编写的可以在多台服务器上执行命令的轻量级管理工具,同 ...