在“基于log4j的消息流的实现之一消息获取”中获取日志消息的部分,修改如下:

import org.apache.commons.collections.map.HashedMap;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import java.util.ArrayDeque;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; /**
* AdapterAppender requires the layout as "%X - %m%n", and the message will be stored by identifier.
* getMessageQueueByKey can be used to get the message by identifier
* */
public class AdapterAppender extends AppenderSkeleton {
private static final Logger LOG = LoggerFactory.getLogger(AdapterAppender.class);
//to store message got from log4j by key
private static ConcurrentHashMap<String, ArrayDeque<String>> messageHM = new ConcurrentHashMap<>();
//to store the first time the message got by key
private Map<String,Long> messageTimestamp = new HashedMap();
//last time we do the remove method
private long lastCheckTimestamp = System.currentTimeMillis();
//will do the remove by one minute
private final int checkInterval = 60000;
//messages which has lived more than 10 minute will be removed
private final int liveDuration = 600000; /**
* format the log message as <identifier - information>, store the <identifier,information>
*
* @param loggingEvent
* log message sent from log4j rootLogger
* */
@Override
protected void append(LoggingEvent loggingEvent) {
String message = this.layout.format(loggingEvent);
if (message.contains("-")) {
String key = message.substring(0, message.indexOf("-") - 1).trim();
String value = message.substring(message.indexOf("-") + 1).trim();
if (messageHM.containsKey(key)) {
messageHM.get(key).add(value);
} else {
ArrayDeque<String> ad = new ArrayDeque<>(32);
ad.add(value);
messageHM.put(key, ad);
messageTimestamp.put(key,System.currentTimeMillis());
}
}else {
LOG.warn("Receive a wrong format message which does not have a '-' in it:{}",message);
} //won't do the remove too frequently,will do it by the checkInterval
long currentTimestamp = System.currentTimeMillis();
if(currentTimestamp - this.lastCheckTimestamp > this.checkInterval){
removeOldMessage(currentTimestamp);
this.lastCheckTimestamp = currentTimestamp;
} } /**
* Remove the message which lives more than the liveDuration
*
* @param currentTime
* the check time
* */
private void removeOldMessage(long currentTime){
for(String key : messageTimestamp.keySet()){
long messageCreateTime = messageTimestamp.get(key);
if(currentTime - messageCreateTime > this.liveDuration){
if(messageHM.containsKey(key)){
messageHM.remove(key);
LOG.info("Remove message for {}",key);
}
messageTimestamp.remove(key);
} }
} /**
* return the message got by this appender until now
* @param key
* identifier which will exists in the log message
* @return message returned when key is found, null returned when key is not found
* */
public static ArrayDeque<String> getMessageQueueByKey(String key) {
if (messageHM.containsKey(key) == false) {
return null;
}
ArrayDeque<String> ad = messageHM.get(key);
messageHM.remove(key);
return ad;
} @Override
public void close() { } /**
* the layout should be "%X - %m%n"
* @param
* @return
* */
@Override
public boolean requiresLayout() {
return true;
}
}

对外保留了一个static方法 getMessageQueueByKey,供获取消息。

注意看到,这个方法里,获取消息后,消息会被删掉,另外在removeOldMessage这个方法,也是为了删除过期的数据,避免日志过大,导致内存出问题。

如下的类,会去获取消息:

 import java.util.ArrayDeque;
import java.util.concurrent.ConcurrentLinkedQueue; /**
* LogGetter is supposed to be executed in a thread. It get message by the key and store it in the clq which
* is got in the construction method.User can get message by clq.poll().
*
* */
public class LogGetter extends Thread {
//identifier to get message
private String logKey;
//signal to stop the method run
private boolean isStop = false;
//a object to transfer message between LogGetter and the caller
private ConcurrentLinkedQueue<String> concurrentLinkedQueue; /**
* private construction prevents from wrong use of it.
*/
private LogGetter() {
} /**
* @param key
* identifier to get message
* @param clq
* a ConcurrentLinkedQueue<String> object to transfer message between LogGetter and the caller
* */
public LogGetter(String key, ConcurrentLinkedQueue<String> clq) {
this.logKey = key;
this.concurrentLinkedQueue = clq;
}
/**
* set the signal to
* */
public void setStop(boolean stop) {
isStop = stop;
} /**
* get message from AdapterAppender by key and store it in clq
*/
@Override
public void run() {
while (!isStop) { ArrayDeque<String> al = AdapterAppender.getMessageQueueByKey(this.logKey);
if (null == al) { } else {
for (String str : al) {
this.concurrentLinkedQueue.add(str);
}
} try {
Thread.sleep(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}

这个类会循环获取消息,放在queue里。

实际使用的片段如下:

/**
* send back the message keyed by mdcValue with responseObserver when execute future
*
* @param future
* a future which is already executed
* @param mdcValue
* a value will be set into the MDC
* @param responseObserver
* a observer which will send back message
* **/
private void sendFutureLog(Future future,
String mdcValue,
StreamObserver<AgentResultReply> responseObserver){ ConcurrentLinkedQueue<String> messageQ = new ConcurrentLinkedQueue<>();
LogGetter lg = new LogGetter(mdcValue, messageQ);
this.executorService.submit(lg); String returnMessage;
AgentResultReply agentResultReply; while (!future.isDone()) {
while (messageQ.size() > 0) {
returnMessage = responseJson.getResponseJson(ResponseJson.MessageType.INFO,
messageQ.poll());
agentResultReply = AgentResultReply.newBuilder().setMessage(returnMessage).build();
responseObserver.onNext(agentResultReply);
}
try {
Thread.sleep(50);
} catch (InterruptedException ie) {
LOG.error("Exception happened in sendFutureLog:{}",ie.getMessage());
ie.printStackTrace();
}
} lg.setStop(true);
}

基于log4j的消息流的实现之二消息传递的更多相关文章

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

    需求: 目前的程序中都是基于log4j来实现日志的管理,想要获取日志中的一部分消息,展示给用户. 约束: 由于程序中除了自己开发的代码,还会有层层依赖的第三方jar中的日志输出.需要展示给用户的消息, ...

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

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

  3. Android 基于Netty的消息推送方案之对象的传递(四)

    在上一篇文章中<Android 基于Netty的消息推送方案之字符串的接收和发送(三)>我们介绍了Netty的字符串传递,我们知道了Netty的消息传递都是基于流,通过ChannelBuf ...

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

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

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

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

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

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

  7. Knative 实战:基于 Kafka 实现消息推送

    作者 | 元毅 阿里云智能事业群高级开发工程师 导读:当前在 Knative 中已经提供了对 Kafka 事件源的支持,那么如何基于 Kafka 实现消息推送呢?本文作者将以阿里云 Kafka 产品为 ...

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

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

  9. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

随机推荐

  1. JavaScript实现快速排序(Quicksort)

    目前,最常见的排序算法大概有七八种,其中"快速排序"(Quicksort)使用得最广泛,速度也较快.它是图灵奖得主 东尼·霍尔(C. A. R. Hoare)于1960时提出来的. ...

  2. 【前行&赛时总结】◇第4站&赛时9◇ CF Round 513 Div1+Div2

    ◇第4站&赛时9◇ CF Round 513 Div1+Div2 第一次在CF里涨Rating QWQ 深感不易……作blog以记之 ( ̄▽ ̄)" +Codeforces 的门为你打 ...

  3. MySQL备份恢复之mysqldump

      Preface       The day before yesterday,there's a motif about the lock procedure when backing up My ...

  4. JetBrains PyCharm 2017.3注册码

    JetBrains PyCharm 2017.3注册码 (1)在激活界面的License server输入:http://idea.liyang.io:或者:点击help→Register→Licen ...

  5. SQL优化之语句优化

    昨天与大家分享了SQL优化中的索引优化,今天给大家聊一下,在开发过程中高质量的代码也是会带来优化的 网上关于SQL优化的教程很多,但是比较杂乱.整理了一下,写出来跟大家分享一下,其中有错误和不足的地方 ...

  6. centos 7 关闭IPtables

    systemctl status iptables.service systemctl stopiptables.service

  7. dotnet core 项目

    项目 常用命令 我们使用dotnet core 命令行来创建项目及进行编译,发布等,比较常用的dotnet core 命令 如下: dotnet new [arguments] [options] 创 ...

  8. R语言学习笔记(一):mode, class, typeof的区别

    要了解这三个函数的区别,先了解numeric, double与integer. 在r中浮点数有两个名字叫numeric与double. double是指它的类型(type)名字,numeric是指它的 ...

  9. Java——equals方法---18.10.18

    一.equals方法定义 public boolean equals(Object obj)方法 //提供对象是否“相等”的逻辑 二.”equals“和“==”的区别 1.“==”比较的是两个变量本身 ...

  10. 初步学习pg_control文件之七

    接前文 初步学习pg_control文件之六  看   pg_control_version 以PostgreSQL9.1.1为了,其HISTORY文件中有如下的内容: Release Release ...