Spring Boot 入门(十一):集成 WebSocket, 实时显示系统日志
以前面的博客为基础,最近一篇为Spring Boot 入门(十):集成Redis哨兵模式,实现Mybatis二级缓存。本篇博客主要介绍了Spring Boot集成 Web Socket进行日志的推送,并实时显示在页面上。
1.导入jar包
第一个jar包是websocket的,第二个jar包是关于环形队列的jar包,本案例是通过本地队列存储日志。有条件的话,最好通过中间件存储(eg:redis,mq……)。通过本地队列存储日志会存在日志丢失的情况,且日志量太大,会把页面卡死。
<!--begin web socket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
<version>3.4.2</version>
</dependency>
<!--end web socket-->
2.增加监听器
(1).在logback中增加监听器
并根据logback编写相应的监听器ProcessLogFilter
@Service
public class ProcessLogFilter extends Filter<ILoggingEvent> { @Override
public FilterReply decide(ILoggingEvent event) {
LoggerMessage loggerMessage = new LoggerMessage(
event.getMessage()
, DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())),
event.getThreadName(),
event.getLoggerName(),
event.getLevel().levelStr
);
LoggerDisruptorQueue.publishEvent(loggerMessage);
return FilterReply.ACCEPT;
}
}
该监听器将监听的日志消息推送到本地消息队列中,然后页面通过 Web Socket 去此队列获取日志信息,从而在页面显示
(2).编写日志处理器
//进程日志事件内容载体
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoggerEvent {
private LoggerMessage log;
}
/**
* Content :进程日志事件工厂类
*/
public class LoggerEventFactory implements EventFactory<LoggerEvent> {
@Override
public LoggerEvent newInstance() {
return new LoggerEvent();
}
}
/**
* Content :进程日志事件处理器
*/
@Component
public class LoggerEventHandler implements EventHandler<LoggerEvent> { @Autowired
private SimpMessagingTemplate messagingTemplate; @Override
public void onEvent(LoggerEvent stringEvent, long l, boolean b) {
messagingTemplate.convertAndSend("/topic/pullLogger", stringEvent.getLog());
}
}
日志事件处理器的作用是监听本地环形队列中的消息,如果有消息,就会将这些消息推送到 Socket 管道中
(3).编写页面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>欢迎页</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<script src="plugins/jQuery/jquery-2.2.3.min.js"></script>
<script src="js/websocket/sockjs.min.js"></script>
<script src="js/websocket/stomp.min.js"></script>
</head>
<body>
<div class="panel panel-default">
<h1>jvm进程内的日志</h1>
<button onclick="openSocket()">开启日志</button>
<button onclick="closeSocket()">关闭日志</button>
<div id="log-container" style="height: 600px; overflow-y: scroll; background: #333; color: #aaa; padding: 10px;">
<div></div>
</div>
</div>
<script>
var stompClient = null;
$(document).ready(function () {
openSocket();
}); function openSocket() {
if (stompClient == null) {
var socket = new SockJS('http://localhost:8080/websocket?token=kl');
stompClient = Stomp.over(socket);
stompClient.connect({token: "kl"}, function (frame) {
stompClient.subscribe('/topic/pullLogger', function (event) {
var content = JSON.parse(event.body);
$("#log-container div").append("<font color='red'>" + content.timestamp + "</font>|<font color='highlight'>" + content.level + "</font> |<font color='green'>" + content.threadName + "</font>| <font color='boldMagenta'>" + content.className + "</font>|<font color='cyan'>" + content.body + "</font>").append("<br/>");
$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
}, {
token: "kltoen"
});
});
}
} function closeSocket() {
if (stompClient != null) {
stompClient.disconnect();
stompClient = null;
}
}
</script>
</body>
</html>
页面链接web Socket服务器,如果有消息,就能获取
(4).其他辅助类
环形本地队列类
package com.learn.hello.system.common.queue; import com.learn.hello.modules.entity.LoggerMessage;
import com.learn.hello.system.common.event.LoggerEvent;
import com.learn.hello.system.common.event.LoggerEventFactory;
import com.learn.hello.system.common.event.LoggerEventHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import java.util.concurrent.Executor;
import java.util.concurrent.Executors; /**
* Content :Disruptor 环形队列
*/
@Component
public class LoggerDisruptorQueue { private Executor executor = Executors.newCachedThreadPool(); // The factory for the event
private LoggerEventFactory factory = new LoggerEventFactory(); // Specify the size of the ring buffer, must be power of 2.
private int bufferSize = 2 * 1024; // Construct the Disruptor
private Disruptor<LoggerEvent> disruptor = new Disruptor<>(factory, bufferSize, executor);
; private static RingBuffer<LoggerEvent> ringBuffer; @Autowired
LoggerDisruptorQueue(LoggerEventHandler eventHandler) {
disruptor.handleEventsWith(eventHandler);
this.ringBuffer = disruptor.getRingBuffer();
disruptor.start();
} public static void publishEvent(LoggerMessage log) {
long sequence = ringBuffer.next(); // Grab the next sequence
try {
LoggerEvent event = ringBuffer.get(sequence); // Get the entry in the Disruptor
// for the sequence
event.setLog(log); // Fill with data
} finally {
ringBuffer.publish(sequence);
}
} }
消息实体类
package com.learn.hello.modules.entity; import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor; // 日志实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoggerMessage {
private String body;
private String timestamp;
private String threadName;
private String className;
private String level;
}
3.效果
页面中的颜色可以自行设置
.
Spring Boot 入门(十一):集成 WebSocket, 实时显示系统日志的更多相关文章
- Spring Boot 入门(十二):报表导出,对比poi、jxl和esayExcel的效率
本片博客是紧接着Spring Boot 入门(十一):集成 WebSocket, 实时显示系统日志写的 关于poi.jxl和esayExcel的介绍自行百度. jxl最多支持03版excel,所以单个 ...
- Spring boot入门(三):SpringBoot集成结合AdminLTE(Freemarker),利用generate自动生成代码,利用DataTable和PageHelper进行分页显示
关于SpringBoot和PageHelper,前篇博客已经介绍过Spring boot入门(二):Spring boot集成MySql,Mybatis和PageHelper插件,前篇博客大致讲述了S ...
- Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理
本文是接着上篇博客写的:Spring boot 入门(三):SpringBoot 集成结合 AdminLTE(Freemarker),利用 generate 自动生成代码,利用 DataTable 和 ...
- Spring boot入门(二):Spring boot集成MySql,Mybatis和PageHelper插件
上一篇文章,写了如何搭建一个简单的Spring boot项目,本篇是接着上一篇文章写得:Spring boot入门:快速搭建Spring boot项目(一),主要是spring boot集成mybat ...
- Spring Boot 入门(六):集成 treetable 和 zTree 实现树形图
本篇文章是接着Spring Boot 入门(五):集成 AOP 进行日志管理写的,主要集成了树形图,在部门列表或者权限列表中,树形图经常被用上.主要是根据相应的 API 凭借 html 字符串 1.t ...
- Spring Boot 入门(五):集成 AOP 进行日志管理
本篇文章是接着 Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理写的,按照前面几篇博客的教程,可以搭建一个简单的项目,主要包含了 Pagehelper+MyBatis 分页 ...
- Spring Boot 入门(七):集成 swagger2
本片文章是基于前一篇写的,<Spring Boot 入门(六):集成 treetable 和 zTree 实现树形图>,本篇主要介绍了spring boot集成swagger2.关于swa ...
- Spring Boot 入门(九):集成Quartz定时任务
本片文章续<Spring Boot 入门(八):集成RabbitMQ消息队列>,关于Quartz定时任务请参考<Quartz的基本使用之入门(2.3.0版本)> spring ...
- Spring Boot 入门(八):集成RabbitMQ消息队列
本片文章续<Spring Boot 入门(七):集成 swagger2>,关于RabbitMQ的介绍请参考<java基础(六):RabbitMQ 入门> 1.增加依赖 < ...
随机推荐
- Laravel 5.* 执行seeder命令出现错误的解决方法
最近在使用Laravel开发一个项目,测试中需要增加数据库基础数据动作,当第一次执行完`php artisan db:seed` 后,增加新的seeder文件时执行会报错.错误信息如下`[Reflec ...
- 2019-9-24-dotnet-remoting-使用事件
title author date CreateTime categories dotnet remoting 使用事件 lindexi 2019-09-24 15:39:26 +0800 2018- ...
- VisualStudio 断点调试详解
本文详细告诉大家 VisualStudio 断点调试的功能和使用方法,本文使用的是最新 VisualStudio2019 的功能,也许在你看到这篇博客的时候这个版本已经过时 本文将会按照从简单到复杂, ...
- 关于oppo和vivo这两年强势崛起的反思
先来谈谈配置吧(小白跳过) oppo产品线 r7 67522015年05月3g2320mAh r7 p 6795 6153g4100mAh r7s 616 67522015年10月4g 3070mAh ...
- Linux基础:Linux下常用命令
常用命令 shutdown 用来系统关机命令.shutdown指令可以关闭所有程序,并依用户的需要,进行重新开机或关机的动作. shutdown (选项)(参数) -c: 当执行"s ...
- Centos 7.5安装 Redis 5.0.0
1 我的环境 1.1 linux(腾讯云) CentOS Linux release 7.5.1804 (Core) 1.2 Redis Redis 5.0.0 2 下载 官网 官网下载地址 3 ...
- cocos2dx Quaternion 四元数(1/2)
这篇文章只是我学完四元数之后的一些理解,其实是对别人理解的理解,有些地方我理解但是没有写下来,如果真的想深入的学习四元数,建议从学习复数开始. 这个知识点需要几何想象的天赋和学习的耐心,缺一不可,慢慢 ...
- 后缀自动机&回文自动机学习笔记
在学了一天其实是边学边摆之后我终于大概$get$后缀自动机了,,,就很感动,于是时隔多年我终于决定再写篇学习笔记辽$QwQ$ $umm$和$FFT$学习笔记一样,这是一篇单纯的$gql$的知识总结博, ...
- $CF1063B\ Labyrinth$ $01$最短路/$01BFS$
\(Des\) 有一个网格图,上面的格子分为空地和障碍,障碍是不可以走的.现在从给定的起点出发开始到处乱走,最多可以往左走\(l\)次,往右走\(r\)次.求可能到达的点数. \(Sol\) 如果只限 ...
- $CF24D\ Broken Robot\ DP+$高斯消元
Luogu Description 你收到的礼物是一个非常聪明的机器人,行走在一块长方形的木板上.不幸的是,你知道它是坏的,表现得相当奇怪(随机).该板由n行和m列的单元格组成.机器人最初是在i行和j ...