spring-boot推送实时日志到前端页面显示
简单的spring-boot工程这里就不做过多的讲解了,只叙述核心部分
首先导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
首先在项目的日志配置文件中新增/修改此节点配置
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!--encoder 默认配置为PatternLayoutEncoder-->
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<!--<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level --- [%thread] %logger Line:%-3L - %msg%n</pattern>-->
<charset>UTF-8</charset>
</encoder>
<!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
<filter class="com.xcloud.api.system.core.LogFilter"></filter>
</appender>
此节点配置主要是为了把控制台输出的日志交给我们自己的日志过滤器进行处理(此节点不要指定日志等级,记得<appender-ref ref="STDOUT" />)
接下来实现自己的日志过滤器
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.filter.Filter;
import ch.qos.logback.core.spi.FilterReply;
import com.xcloud.api.system.entity.LoggerMessage;
import org.springframework.stereotype.Service;
import java.text.DateFormat;
import java.util.Date;
/**
* Xcloud-Api By IDEA
* Created by LaoWang on 2018/8/25.
*/
@Service
public class LogFilter extends Filter<ILoggingEvent> {
@Override
public FilterReply decide(ILoggingEvent event) {
String exception = "";
IThrowableProxy iThrowableProxy1 = event.getThrowableProxy();
if(iThrowableProxy1!=null){
exception = "<span class='excehtext'>"+iThrowableProxy1.getClassName()+" "+iThrowableProxy1.getMessage()+"</span></br>";
for(int i=0; i<iThrowableProxy1.getStackTraceElementProxyArray().length;i++){
exception += "<span class='excetext'>"+iThrowableProxy1.getStackTraceElementProxyArray()[i].toString()+"</span></br>";
}
}
LoggerMessage loggerMessage = new LoggerMessage(
event.getMessage()
, DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())),
event.getThreadName(),
event.getLoggerName(),
event.getLevel().levelStr,
exception,
""
);
LoggerQueue.getInstance().push(loggerMessage);
return FilterReply.ACCEPT;
}
}
这部分代码网上大部分都是一样的,但是并没有对异常具体信息进行处理,所以这里我把具体异常信息日志也添加进去了
创建一个阻塞队列,作为日志系统输出的日志的一个临时载体
import com.xcloud.api.system.entity.LoggerMessage;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class LoggerQueue {
//队列大小
public static final int QUEUE_MAX_SIZE = 10000;
private static LoggerQueue alarmMessageQueue = new LoggerQueue();
//阻塞队列
private BlockingQueue blockingQueue = new LinkedBlockingQueue<>(QUEUE_MAX_SIZE);
private LoggerQueue() {
}
public static LoggerQueue getInstance() {
return alarmMessageQueue;
}
/**
* 消息入队
*
* @param log
* @return
*/
public boolean push(LoggerMessage log) {
return this.blockingQueue.add(log);//队列满了就抛出异常,不阻塞
}
/**
* 消息出队
*
* @return
*/
public LoggerMessage poll() {
LoggerMessage result = null;
try {
result = (LoggerMessage) this.blockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
return result;
}
}
创建一个日志实体(这里我使用了lombok,如果没用的话,请自行生成get,set和全参数构造方法)
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/**
* 日志消息实体
*/
@Getter
@Setter
@ToString
@AllArgsConstructor
public class LoggerMessage {
private String body;
private String timestamp;
private String threadName;
private String className;
private String level;
private String exception;
private String cause;
}
接下来配置WebSocket
import com.xcloud.api.system.core.LoggerQueue;
import com.xcloud.api.system.entity.LoggerMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import javax.annotation.PostConstruct;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Xcloud-Api By IDEA
* 配置WebSocket消息代理端点,即stomp服务端
* 为了连接安全,setAllowedOrigins设置的允许连接的源地址
* 如果在非这个配置的地址下发起连接会报403
* 进一步还可以使用addInterceptors设置拦截器,来做相关的鉴权操作
* Created by LaoWang on 2018/8/25.
*/
@Slf4j
@Configuration
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired
private SimpMessagingTemplate messagingTemplate;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket")
.setAllowedOrigins("*")
.withSockJS();
}
/**
* 推送日志到/topic/pullLogger
*/
@PostConstruct
public void pushLogger(){
ExecutorService executorService= Executors.newFixedThreadPool(2);
Runnable runnable=new Runnable() {
@Override
public void run() {
while (true) {
try {
LoggerMessage log = LoggerQueue.getInstance().poll();
if(log!=null){
if(messagingTemplate!=null)
messagingTemplate.convertAndSend("/topic/pullLogger",log);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
executorService.submit(runnable);
executorService.submit(runnable);
}
}
如果项目配置有拦截器获取其他权限控制的,请开放/websocket
前端页面:这里我使用了原生swagger+layer,请自行根据自己页面进行配置
配置一个按钮点击弹出layer弹窗,日志颜色,具体的一些样式可根据自己喜好选择
$(".log").click(function () {
//iframe层
layer.open({
type: 1,
title: '<span class="laytit">接口实时日志</span>',
shadeClose: false,
shade: 0.7,
maxmin: true,
area: ['80%', '70%'],
content: $("#logdiv").html(), //iframe的url
cancel: function(index){
closeSocket();
}
});
});
<!-- 日志实时推送业务处理 -->
var stompClient = null;
function openSocket() {
if (stompClient == null) {
if($("#log-container").find("span").length==0){
$("#log-container div").after("<span>通道连接成功,静默等待.....</span><img src='images/loading.gif'>");
}
var socket = new SockJS('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);
var leverhtml = '';
var className = '<span class="classnametext">' + content.className + '</span>';
switch (content.level) {
case 'INFO':
leverhtml = '<span class="infotext">' + content.level + '</span>';
break;
case 'DEBUG':
leverhtml = '<span class="debugtext">' + content.level + '</span>';
break;
case 'WARN':
leverhtml = '<span class="warntext">' + content.level + '</span>';
break;
case 'ERROR':
leverhtml = '<span class="errortext">' + content.level + '</span>';
break;
}
$("#log-container div").append("<p class='logp'>" + content.timestamp + " " + leverhtml + " --- [" + content.threadName + "] " + className + " :" + content.body + "</p>");
if (content.exception != "") {
$("#log-container div").append("<p class='logp'>" + content.exception + "</p>");
}
if (content.cause != "") {
$("#log-container div").append("<p class='logp'>" + content.cause + "</p>");
}
$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());
}, {
token: "kltoen"
});
});
}
}
function closeSocket() {
if (stompClient != null) {
stompClient.disconnect();
stompClient = null;
}
}
最后来一个效果图(图中日志等级动态配置将在下篇博客说明)有什么不对的地方欢迎大牛们评论!!!
转载于:https://blog.51cto.com/xiaok007/2294708
spring-boot推送实时日志到前端页面显示相关推荐
- Spring Boot中禁用缓存,修改前端页面实时生效
目录 理论 演示 理论 通过设计spring.thymeleaf.cache为false关闭存储功能! 编写好对应的html页面后,IDEA通过按Ctrl + F9编译页面,即可浏览修改后的前端页面. ...
- 使用SignalR从服务端主动推送警报日志到各种终端(桌面、移动、网页)
工作上有个业务,.Net Core WebAPI作为服务端,需要将运行过程中产生的日志分类,并实时推送到各种终端进行报警,终端有桌面(WPF).移动(Xamarin.Forms).网站(Angular ...
- RestAPI的进化之路,后端MVVM模式或许来临,通过观察者模式,后端收集前端的GET类请求,主动推送数据变更到前端
RestAPI的进化之路,后端MVVM模式或许来临,通过观察者模式,后端收集前端的GET类请求,主动推送数据变更到前端 最近几年,前端MVVM模式彻底变革了前端的开发模式,那这股火焰会烧到后端嘛? 我 ...
- java配置文件放置到jar外_java相关:Spring Boot 把配置文件和日志文件放到jar外部...
java相关:Spring Boot 把配置文件和日志文件放到jar外部 发布于 2020-3-6| 复制链接 如果不想使用默认的application.properties,而想将属性文件放到jar ...
- 实现织梦dedecms百度主动推送(实时)网页抓取
做百度推广的时候,如何让百度快速收录呢,下面提供了三种方式,今天我们主要讲的是第一种. 如何选择链接提交方式 1.主动推送:最为快速的提交方式,推荐您将站点当天新产出链接立即通过此方式推送给百度,以保 ...
- 音视频开发(22)---基于RTMP推送实时AAC+H264流(三)
基于RTMP推送实时AAC+H264流(三) https://blog.csdn.net/scnu20142005027/article/details/60623670 推送 流程:初始化.连接服务 ...
- 音视频开发(21)---基于RTMP推送实时AAC+H264流(二)
基于RTMP推送实时AAC+H264流(二) https://blog.csdn.net/scnu20142005027/article/details/57428107 编码 图像采用H264编码, ...
- 音视频开发(20)---基于RTMP推送实时AAC+H264流(一)
基于RTMP推送实时AAC+H264流(一) https://blog.csdn.net/scnu20142005027/article/details/56847293 从整体来看,推流端大概是这么 ...
- SpringBoot实战(十三):Spring Boot Admin 动态修改日志级别
强烈推荐一个大神的人工智能的教程:http://www.captainbed.net/zhanghan [前言] 之前关于线上输出日志一直有个困惑:如何可以动态调整的日志级别,来保证系统在正常运行时性 ...
- 百度php主动推送每天,百度主动推送(实时)制作 简单3步轻松完成
怎样才能使新更新的文章更快的被百度收录,是所有站长最头疼的事情之一,而百度在这一块问题上为了我们站点也算是煞费苦心,如若不然也不会提供了"链接提交"工具. 百度给出的链接提交方式有 ...
最新文章
- 11无监听程序_腾讯开心鼠英语 小程序实践与总结
- C语言实现boyer moore(博伊尔-摩尔搜索)算法(附完整源码)
- Hexo 双线部署到 Coding Pages 和 GitHub Pages 并实现全站 HTTPS
- Qt笔记——添加菜单图片/添加资源文件
- MySQL的CSV引擎应用实例解析
- 如何防止mysql数据库被勒索
- pythonturtle魔法阵_深圳Pythonlevel1
- 【重磅】世界上最可信、最权威的人工智能数据和洞察来源:2021年人工智能指数报告...
- 关于网络编程中MTU、TCP、UDP优化配置的一些总结
- 【Node学习】—Node.js中模块化开发的规范
- 大厂面试常问的机器学习,计算机视觉怎么学?详细指南来了!
- 重装64位WIN7之后再装KUBUNTU遇到的问题
- python中解释说明符号_python注释以什么符号开始
- arm linux 删除大量文件,ARM Linux根文件系统(Root Filesystem)的制作
- Linux 下制作虚拟软盘镜像
- 游戏策划笔记:工作感受感官引导
- 自己开发的天视通局域网电脑监控软件,需要的来下载
- 谷歌浏览器设置定位_谷歌浏览器手动设置位置信息
- 编译原理 实验3《算符优先分析法设计与实现》
- 高中计算机考试编程题,高中信息技术《算法及程序设计》试题.docx
热门文章
- python svm向量_支持向量机(SVM)及其Python实现
- 好莱坞法则_人工智能去好莱坞
- 数据库连接html文件路径,Python+Flash+MySQL+HTML链接数据库查询,pythonflaskmysqlhtml,连库...
- python:使用split以.划分句子、对列表进行切片
- java 去掉字符串最后几个字符_java-删除字符串的最后两个字符
- c#调用java的webservice方法,C# 调用 Java WebService | 思考的极致
- ajax 循环php数组,jQuery通过ajax请求php遍历json数组到table中的代码(推荐)
- wpf 导航按钮去掉_高德地图推出个性导航,你的私人订制导航是什么样的?
- spring cloud构建互联网分布式微服务云平台-服务提供与调用
- 大数据之Linux早课9.14