支持服务端日志传入前端
parent
376f14733e
commit
effb705f99
18
pom.xml
18
pom.xml
|
@ -107,6 +107,12 @@
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
|
@ -353,6 +359,18 @@
|
||||||
<version>1.18.30</version>
|
<version>1.18.30</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!--LogViewer-->
|
||||||
|
<!-- <dependency>-->
|
||||||
|
<!-- <groupId>io.github.sevdokimov.logviewer</groupId>-->
|
||||||
|
<!-- <artifactId>log-generator</artifactId>-->
|
||||||
|
<!-- <version>1.0.10</version>-->
|
||||||
|
<!-- </dependency>-->
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.github.sevdokimov.logviewer</groupId>
|
||||||
|
<artifactId>log-viewer-spring-boot</artifactId>
|
||||||
|
<version>1.0.10</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package com.genersoft.iot.vmp.conf.webLog;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import javax.websocket.*;
|
||||||
|
import javax.websocket.server.ServerEndpoint;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
@ServerEndpoint(value = "/channel/log")
|
||||||
|
@Slf4j
|
||||||
|
public class LogChannel {
|
||||||
|
|
||||||
|
public static final ConcurrentMap<String, LogChannel> CHANNELS = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private Session session;
|
||||||
|
|
||||||
|
@OnMessage(maxMessageSize = 1) // MaxMessage 1 byte
|
||||||
|
public void onMessage(String message) {
|
||||||
|
|
||||||
|
log.debug("Recv Message: {}", message);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.session.close(new CloseReason(CloseReason.CloseCodes.TOO_BIG, "此节点不接收任何客户端信息"));
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("[Web-Log] 连接关闭失败: id={}, err={}", this.session.getId(), e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnOpen
|
||||||
|
public void onOpen(Session session, EndpointConfig endpointConfig) {
|
||||||
|
this.session = session;
|
||||||
|
this.session.setMaxIdleTimeout(0);
|
||||||
|
CHANNELS.put(this.session.getId(), this);
|
||||||
|
|
||||||
|
log.info("[Web-Log] 连接已建立: id={}", this.session.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnClose
|
||||||
|
public void onClose(CloseReason closeReason) {
|
||||||
|
|
||||||
|
log.info("[Web-Log] 连接已断开: id={}, err={}", this.session.getId(), closeReason);
|
||||||
|
|
||||||
|
CHANNELS.remove(this.session.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@OnError
|
||||||
|
public void onError(Throwable throwable) throws IOException {
|
||||||
|
log.info("[Web-Log] 连接错误: id={}, err= ", this.session.getId(), throwable);
|
||||||
|
this.session.close(new CloseReason(CloseReason.CloseCodes.UNEXPECTED_CONDITION, throwable.getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Push messages to all clients
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
*/
|
||||||
|
public static void push(String message) {
|
||||||
|
CHANNELS.values().stream().forEach(endpoint -> {
|
||||||
|
if (endpoint.session.isOpen()) {
|
||||||
|
endpoint.session.getAsyncRemote().sendText(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.genersoft.iot.vmp.conf.webLog;
|
||||||
|
|
||||||
|
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
|
||||||
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
|
import ch.qos.logback.core.AppenderBase;
|
||||||
|
import com.genersoft.iot.vmp.utils.DateUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class WebSocketAppender extends AppenderBase<ILoggingEvent> {
|
||||||
|
|
||||||
|
private PatternLayoutEncoder encoder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void append(ILoggingEvent loggingEvent) {
|
||||||
|
byte[] data = this.encoder.encode(loggingEvent);
|
||||||
|
// Push to client.
|
||||||
|
LogChannel.push(DateUtil.timestampMsTo_yyyy_MM_dd_HH_mm_ss(loggingEvent.getTimeStamp()) + " " + loggingEvent.getFormattedMessage());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.genersoft.iot.vmp.conf.websocket;
|
||||||
|
|
||||||
|
import com.genersoft.iot.vmp.conf.webLog.LogChannel;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class WebSocketConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServerEndpointExporter serverEndpointExporter(){
|
||||||
|
ServerEndpointExporter endpointExporter = new ServerEndpointExporter();
|
||||||
|
|
||||||
|
endpointExporter.setAnnotatedEndpointClasses(LogChannel.class);
|
||||||
|
|
||||||
|
return endpointExporter;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,14 @@
|
||||||
</filter>
|
</filter>
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
|
<!-- WebSocket -->
|
||||||
|
<appender name="websocket" class="com.genersoft.iot.vmp.conf.webLog.WebSocketAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>${FILE_LOG_PATTERN}</pattern>
|
||||||
|
<charset>UTF-8</charset>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
<!-- 按照每天生成日志文件 DEBUG以上级别的日志,仅用于测试环境,正式环境为info级别以上的日志-->
|
<!-- 按照每天生成日志文件 DEBUG以上级别的日志,仅用于测试环境,正式环境为info级别以上的日志-->
|
||||||
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||||
|
|
||||||
|
@ -88,6 +96,7 @@
|
||||||
<!-- 日志输出级别 -->
|
<!-- 日志输出级别 -->
|
||||||
<root level="INFO">
|
<root level="INFO">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
|
<appender-ref ref="websocket" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
<logger name="com.genersoft.iot.vmp" level="info" additivity="true">
|
<logger name="com.genersoft.iot.vmp" level="info" additivity="true">
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<div id="log" style="width: 100%">
|
||||||
|
<el-container v-loading="loading" >
|
||||||
|
<el-aside width="400px" >
|
||||||
|
</el-aside>
|
||||||
|
<el-main style="padding: 5px;">
|
||||||
|
</el-main>
|
||||||
|
</el-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// import uiHeader from '../layout/UiHeader.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'log',
|
||||||
|
components: {},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
console.log('created');
|
||||||
|
this.initData();
|
||||||
|
},
|
||||||
|
destroyed() {},
|
||||||
|
methods: {
|
||||||
|
initData: function () {
|
||||||
|
console.log('initData');
|
||||||
|
const websocket = new WebSocket("ws://localhost:18080/channel/log");
|
||||||
|
websocket.onclose = e => {
|
||||||
|
console.log(`conn closed: code=${e.code}, reason=${e.reason}, wasClean=${e.wasClean}`)
|
||||||
|
}
|
||||||
|
websocket.onmessage = e => {
|
||||||
|
console.log(e.data);
|
||||||
|
}
|
||||||
|
websocket.onerror = e => {
|
||||||
|
console.log(`conn err`)
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
|
websocket.onopen = e => {
|
||||||
|
console.log(`conn open: ${e}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.videoList {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-item {
|
||||||
|
position: relative;
|
||||||
|
width: 15rem;
|
||||||
|
height: 10rem;
|
||||||
|
margin-right: 1rem;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-item-img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-item-img:after {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
width: 3rem;
|
||||||
|
height: 3rem;
|
||||||
|
background-image: url("../assets/loading.png");
|
||||||
|
background-size: cover;
|
||||||
|
background-color: #000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video-item-title {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
color: #000000;
|
||||||
|
background-color: #ffffff;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
padding: 0.3rem;
|
||||||
|
width: 14.4rem;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -25,6 +25,7 @@ import wasmPlayer from '../components/common/jessibuca.vue'
|
||||||
import rtcPlayer from '../components/dialog/rtcPlayer.vue'
|
import rtcPlayer from '../components/dialog/rtcPlayer.vue'
|
||||||
import region from '../components/region.vue'
|
import region from '../components/region.vue'
|
||||||
import group from '../components/group.vue'
|
import group from '../components/group.vue'
|
||||||
|
import log from '../components/log.vue'
|
||||||
|
|
||||||
const originalPush = VueRouter.prototype.push
|
const originalPush = VueRouter.prototype.push
|
||||||
VueRouter.prototype.push = function push(location) {
|
VueRouter.prototype.push = function push(location) {
|
||||||
|
@ -142,8 +143,11 @@ export default new VueRouter({
|
||||||
path: '/channel/group',
|
path: '/channel/group',
|
||||||
name: 'group',
|
name: 'group',
|
||||||
component: group,
|
component: group,
|
||||||
}
|
},
|
||||||
,
|
{
|
||||||
|
path: '/log',
|
||||||
|
component: log,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue