加了日志系统
This commit is contained in:
parent
1803ef845c
commit
6ee610f4cc
3
.gitignore
vendored
3
.gitignore
vendored
@ -35,4 +35,5 @@ build/
|
||||
### dir ###
|
||||
/live/
|
||||
/databases/
|
||||
/cache/
|
||||
/cache/
|
||||
/logs/
|
15
pom.xml
15
pom.xml
@ -144,6 +144,21 @@
|
||||
<artifactId>selenium-java</artifactId>
|
||||
<version>4.26.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-log4j2</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -1,29 +1,32 @@
|
||||
package com.yutou;
|
||||
|
||||
import com.yutou.common.okhttp.HttpLoggingInterceptor;
|
||||
import com.yutou.common.utils.ConfigTools;
|
||||
import com.yutou.common.utils.Log;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication()
|
||||
public class BilibiliApplication {
|
||||
|
||||
public static String version = "0.8.4";
|
||||
public static String version = "0.9";
|
||||
|
||||
public static void main(String[] args) {
|
||||
HttpLoggingInterceptor.setLog(false);
|
||||
Log.i("启动版本", version);
|
||||
HttpLoggingInterceptor.setLog(ConfigTools.load(ConfigTools.CONFIG, "HttpLog", Boolean.class, false));
|
||||
SpringApplication.run(BilibiliApplication.class, args);
|
||||
}
|
||||
//TODO 优化 1 手动中断录制后,没有时间戳问题需要解决,看是提示转码还是有什么其他解决方案 | 改成了通过q来退出
|
||||
//TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成
|
||||
//TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码
|
||||
//TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播) | 换成饼状图
|
||||
//TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题.
|
||||
//TODO 测试 1 需要测试网络中断下,弹幕重连机制
|
||||
//TODO 测试 2 在导出jar包后再测试完整的录制功能
|
||||
//TODO 测试 3 需要确认项目的内存占用情况
|
||||
//TODO 开发 1 完成用户列表的所有功能,包括移出用户和筛选ck和登陆扫码二维码的优化
|
||||
//TODO 优化 2 创建nfo文件看看要不要改成录制后生成,或者触发打包指令再生成|改了
|
||||
//TODO 优化 3 录制完成前应该也允许查看礼物信息和SC以及弹幕,未停止录制改成从开始时间到当前时间的弹幕和礼物信息,已停止录制则询问是否转码|改了
|
||||
//TODO 优化 4 视频页面礼物的图标,有数据计算错误以及单项猛增的话导致其他项目无法查看的问题(可参考泛式死亡笔记录播) | 换成饼状图 | 改了
|
||||
//TODO 修复 1 开播时有概率连续触发创建nfo和记录视频到数据宽度问题. | 改了
|
||||
//TODO 测试 1 需要测试网络中断下,弹幕重连机制|好像没问题
|
||||
//TODO 测试 2 在导出jar包后再测试完整的录制功能|没问题
|
||||
//TODO 测试 3 需要确认项目的内存占用情况|好像还行
|
||||
//TODO 开发 1 完成用户列表的所有功能,包括移出用户和筛选ck和登陆扫码二维码的优化|改了
|
||||
//TODO 开发 2 数据中心
|
||||
//TODO 开发 3 视频页面打包导出视频和弹幕
|
||||
//TODO 开发 4 弹幕随开播时间录制
|
||||
//TODO 开发 5 追加关键词检测
|
||||
//TODO 开发 4 弹幕随开播时间录制|有了
|
||||
//TODO 开发 5 追加关键词检测|加了
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import com.yutou.biliapi.bean.websocket.WebSocketBody;
|
||||
import com.yutou.biliapi.bean.websocket.WebSocketHeader;
|
||||
import com.yutou.biliapi.bean.websocket.live.WSData;
|
||||
import com.yutou.biliapi.databases.BiliBiliLoginDatabase;
|
||||
import com.yutou.biliapi.databases.BiliLiveDatabase;
|
||||
import com.yutou.biliapi.utils.BytesUtils;
|
||||
import com.yutou.bilibili.services.LiveDatabasesService;
|
||||
import com.yutou.bilibili.services.LiveService;
|
||||
@ -45,7 +44,6 @@ import java.util.concurrent.TimeUnit;
|
||||
@Service
|
||||
public class WebSocketServer {
|
||||
ThreadPoolExecutor executor;
|
||||
private static WebSocketServer instance;
|
||||
Map<LiveRoomConfig, DanmuTask> roomMap;
|
||||
private final List<String> userStopList = new ArrayList<>();//手动停止列表
|
||||
@Resource
|
||||
@ -164,15 +162,17 @@ public class WebSocketServer {
|
||||
private final LiveRoomConfig roomConfig;
|
||||
private final HeartbeatTask heartbeatTask;
|
||||
private final boolean isUser;
|
||||
private final String logTag;
|
||||
|
||||
public WebSocketClientTh(URI serverUri, LiveRoomConfig roomId, boolean isUser) {
|
||||
super(serverUri);
|
||||
Log.i("WebSocketClientTh.WebSocketClientTh : " + serverUri);
|
||||
logTag = "WebSocket-" + roomId.getRoomId();
|
||||
Log.getDynamicLogger(logTag).info("WebSocketClientTh.WebSocketClientTh = {}", serverUri);
|
||||
this.isUser = isUser;
|
||||
this.roomConfig = roomId;
|
||||
Brotli4jLoader.ensureAvailability();
|
||||
heartbeatTask = new HeartbeatTask();
|
||||
addHeader("User-Agent", ConfigTools.getUserAgent());
|
||||
heartbeatTask = new HeartbeatTask();
|
||||
connect();
|
||||
}
|
||||
|
||||
@ -182,7 +182,7 @@ public class WebSocketServer {
|
||||
heartbeatTask.setSocket(this);
|
||||
heartbeatTask.sendInitAuthData();
|
||||
new Timer().schedule(heartbeatTask, 1000, 30000);
|
||||
Log.i("WebSocketClientTh.onOpen", roomConfig.getRoomId());
|
||||
Log.getDynamicLogger(logTag).info("WebSocketClientTh.onOpen,{}", roomConfig.getRoomId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -199,7 +199,7 @@ public class WebSocketServer {
|
||||
|
||||
@Override
|
||||
public void onClose(int i, String s, boolean b) {
|
||||
Log.e("WebSocketClientTh.onClose", "i = " + i + ", s = " + s + ", b = " + b, roomConfig.getRoomId(), heartbeatTask.socket.isOpen());
|
||||
Log.getDynamicLogger(logTag).error("WebSocketClientTh.onClose. {},{},{}", "i = " + i + ", s = " + s + ", b = " + b, roomConfig.getRoomId(), heartbeatTask.socket.isOpen());
|
||||
roomMap.remove(roomConfig);
|
||||
heartbeatTask.cancel();
|
||||
if (i == 1006) {
|
||||
@ -211,7 +211,7 @@ public class WebSocketServer {
|
||||
|
||||
@Override
|
||||
public void onError(Exception e) {
|
||||
Log.i("WebSocketClientTh.onError", roomConfig.getRoomId());
|
||||
Log.getDynamicLogger(logTag).info("WebSocketClientTh.onError,{}", roomConfig.getRoomId());
|
||||
Log.e(e);
|
||||
roomMap.remove(roomConfig);
|
||||
heartbeatTask.cancel();
|
||||
@ -239,7 +239,7 @@ public class WebSocketServer {
|
||||
}
|
||||
|
||||
private void danmu(byte[] bytes) {
|
||||
//Log.i("未压缩:" + new String(bytes));
|
||||
Log.getDynamicLogger(logTag).info("未压缩:{}", new String(bytes));
|
||||
}
|
||||
|
||||
private void unzipDanmu(byte[] bytes, boolean useHeader) {
|
||||
@ -248,16 +248,14 @@ public class WebSocketServer {
|
||||
DirectDecompress directDecompress = Decoder.decompress(bytes);
|
||||
if (directDecompress.getResultStatus() == DecoderJNI.Status.DONE) {
|
||||
WebSocketBody body = new WebSocketBody(directDecompress.getDecompressedData());
|
||||
// Log.i("协议:" + useHeader + " 命令数:" + body.getBodyList().size());
|
||||
Log.getDynamicLogger(logTag).info("协议:{},命令数:{}", useHeader, +body.getBodyList().size());
|
||||
for (JSONObject json : body.getBodyList()) {
|
||||
WSData parse = WSData.parse(json);
|
||||
liveDatabasesService.getLiveDatabase(roomConfig.getRoomId()).addSource(parse);
|
||||
// Log.i("解压:" + parse);
|
||||
Log.getDynamicLogger(logTag).info("解压:{}", parse);
|
||||
}
|
||||
// Log.i();
|
||||
// Log.i();
|
||||
} else {
|
||||
Log.e(new RuntimeException("解压失败"));
|
||||
Log.getDynamicLogger(logTag).error(new RuntimeException("解压失败"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(e);
|
||||
@ -295,10 +293,10 @@ public class WebSocketServer {
|
||||
json.put("uid", 0);
|
||||
}
|
||||
LoginCookieDatabaseBean cookie = BiliBiliLoginDatabase.getInstance().getCookie(roomConfig.getLoginUid());
|
||||
Log.d("cookie:", cookie, "RoomId:" + roomConfig);
|
||||
try {
|
||||
json.put("roomid", new BigInteger(roomConfig.getRoomId()));
|
||||
json.put("protover", 3);
|
||||
// json.put("buvid3", BiliUserUtils.getBuvid(roomConfig.isLogin() ? BiliBiliLoginDatabase.getInstance().getCookie(roomConfig.getRoomId()) : null));
|
||||
json.put("platform", "web");
|
||||
json.put("type", 2);
|
||||
json.put("key", roomConfig.getLiveInfo().getToken());
|
||||
|
@ -1,13 +1,17 @@
|
||||
package com.yutou.bilibili.Tools;
|
||||
|
||||
import com.yutou.biliapi.bean.live.LiveRoomInfo;
|
||||
import com.yutou.bilibili.services.SystemService;
|
||||
import com.yutou.common.utils.DynamicLogFile;
|
||||
import com.yutou.common.utils.Log;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* 服务启动后执行
|
||||
@ -16,11 +20,11 @@ import java.util.logging.Logger;
|
||||
public class ApplicationInit implements ApplicationRunner {
|
||||
@Resource
|
||||
SystemService systemConfigService;
|
||||
Logger logger = LogManager.getLogger(ApplicationInit.class);
|
||||
|
||||
@Override
|
||||
public void run(ApplicationArguments args) throws Exception {
|
||||
Logger logger = Logger.getLogger("ApplicationInit");
|
||||
logger.log(Level.INFO, "服务启动后执行");
|
||||
logger.info("服务启动后执行");
|
||||
systemConfigService.start();
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,9 @@ public class SystemService {
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
scheduled.cancel(true);
|
||||
if(scheduled!=null) {
|
||||
scheduled.cancel(true);
|
||||
}
|
||||
videoService.stopAll();
|
||||
}
|
||||
|
||||
|
@ -8,13 +8,14 @@ import okio.Buffer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class HttpLoggingInterceptor implements Interceptor {
|
||||
private static final String TAG = "HttpLogging";
|
||||
|
||||
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||
private static final Charset UTF8 = StandardCharsets.UTF_8;
|
||||
|
||||
private volatile Level printLevel = Level.BODY;
|
||||
private java.util.logging.Level colorLevel;
|
||||
@ -51,7 +52,7 @@ public class HttpLoggingInterceptor implements Interceptor {
|
||||
private void log(String message) {
|
||||
//logger.log(colorLevel, message);
|
||||
if (prLog) {
|
||||
Log.i(TAG, message);
|
||||
Log.getDynamicLogger(TAG).info(message);
|
||||
}
|
||||
//Log.e(TAG,message);
|
||||
}
|
||||
|
123
src/main/java/com/yutou/common/utils/DynamicLogFile.java
Normal file
123
src/main/java/com/yutou/common/utils/DynamicLogFile.java
Normal file
@ -0,0 +1,123 @@
|
||||
package com.yutou.common.utils;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.yutou.bilibili.Tools.DateFormatUtils;
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.LoggerContext;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.core.appender.rolling.*;
|
||||
import org.apache.logging.log4j.core.config.Configuration;
|
||||
import org.apache.logging.log4j.core.appender.RollingFileAppender;
|
||||
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class DynamicLogFile {
|
||||
// 创建一个缓存,用于存储Logger对象,最大容量为1000,过期时间为10分钟
|
||||
static Cache<String, Logger> cache = CacheBuilder.newBuilder()
|
||||
.maximumSize(1000)
|
||||
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||
.removalListener(it -> {
|
||||
if (it.wasEvicted()) {
|
||||
if (it.getKey() != null) {
|
||||
String loggerName = (String) it.getKey();
|
||||
remove(loggerName, true);
|
||||
}
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
// 根据loggerName获取Logger对象,如果缓存中不存在,则创建一个新的Logger对象并放入缓存
|
||||
public static Logger getLogger(String loggerName) {
|
||||
try {
|
||||
return cache.get(loggerName, () -> {
|
||||
configureLogger(loggerName);
|
||||
return LogManager.getLogger(loggerName);
|
||||
});
|
||||
} catch (ExecutionException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// 配置Logger对象
|
||||
private static void configureLogger(String loggerName) {
|
||||
|
||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||
Configuration config = context.getConfiguration();
|
||||
|
||||
// 创建日志格式
|
||||
Layout<String> layout = PatternLayout.newBuilder()
|
||||
.withPattern("%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %-5p [%thread] (%F:%L) : %m%n")
|
||||
.build();
|
||||
|
||||
// 创建时间触发策略
|
||||
TimeBasedTriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder()
|
||||
.build();
|
||||
|
||||
// 创建文件大小触发策略
|
||||
SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy("100 MB");
|
||||
|
||||
// 创建组合触发策略
|
||||
CompositeTriggeringPolicy triggeringPolicy = CompositeTriggeringPolicy.createPolicy(timePolicy, sizePolicy);
|
||||
|
||||
|
||||
// 创建滚动文件Appender
|
||||
RollingFileAppender appender = RollingFileAppender.newBuilder()
|
||||
.setName(loggerName)
|
||||
.withFileName("logs" + "/" + DateFormatUtils.getInstance().format(new Date(), "yyyy-MM-dd") + "/" + loggerName + ".log")
|
||||
.withFilePattern("logs" + "/" + "%d{yyyy-MM-dd}" + "/" + loggerName + "-%i.log.gz")
|
||||
.setLayout(layout)
|
||||
.setImmediateFlush(true)
|
||||
.withAppend(true)
|
||||
.setIgnoreExceptions(false)
|
||||
.withPolicy(triggeringPolicy)
|
||||
.build();
|
||||
|
||||
appender.start();
|
||||
config.addAppender(appender);
|
||||
|
||||
// 获取Logger对象
|
||||
org.apache.logging.log4j.core.Logger coreLogger = context.getLogger(loggerName);
|
||||
if (coreLogger == null) {
|
||||
throw new IllegalStateException("Logger with name " + loggerName + " does not exist.");
|
||||
}
|
||||
|
||||
// 将Appender添加到Logger对象中
|
||||
coreLogger.addAppender(appender);
|
||||
coreLogger.setLevel(Level.ALL);
|
||||
coreLogger.setAdditive(false);
|
||||
|
||||
// 更新Logger对象
|
||||
context.updateLoggers();
|
||||
|
||||
}
|
||||
|
||||
// 移除Logger对象
|
||||
public static void remove(String loggerName) {
|
||||
remove(loggerName, false);
|
||||
}
|
||||
|
||||
// 私有方法,移除Logger对象,isAuto参数用于判断是否是自动移除
|
||||
private static void remove(String loggerName, boolean isAuto) {
|
||||
if (!isAuto) {
|
||||
cache.invalidate(loggerName);
|
||||
}
|
||||
LoggerContext context = (LoggerContext) LogManager.getContext(false);
|
||||
Configuration config = context.getConfiguration();
|
||||
org.apache.logging.log4j.core.Logger coreLogger = context.getLogger(loggerName);
|
||||
Appender appender = config.getAppender(loggerName);
|
||||
if (appender != null) {
|
||||
appender.stop();
|
||||
coreLogger.removeAppender(appender);
|
||||
}
|
||||
config.getAppenders().remove(loggerName);
|
||||
context.updateLoggers();
|
||||
}
|
||||
|
||||
}
|
@ -2,6 +2,7 @@ package com.yutou.common.utils;
|
||||
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.util.StackLocatorUtil;
|
||||
|
||||
|
||||
@ -11,6 +12,14 @@ public class Log {
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
public static Logger getDynamicLogger(String loggerName) {
|
||||
return DynamicLogFile.getLogger(loggerName);
|
||||
}
|
||||
|
||||
public static void removeDynamicLogger(String loggerName) {
|
||||
DynamicLogFile.remove(loggerName);
|
||||
}
|
||||
|
||||
public static void i(Object... log) {
|
||||
if (!((boolean) ConfigTools.load(ConfigTools.CONFIG, "logcat"))) {
|
||||
return;
|
||||
|
@ -1,4 +1,5 @@
|
||||
server.port=8880
|
||||
logging.config=classpath:log4j2.xml
|
||||
logging.file.path=./logs
|
||||
logging.level.com.log.controller = trace
|
||||
# 启用Hibernate SQL日志
|
||||
|
37
src/main/resources/log4j2.xml
Normal file
37
src/main/resources/log4j2.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration status="WARN">
|
||||
<Appenders>
|
||||
<!-- 控制台输出 -->
|
||||
<Console name="ConsoleAppender" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5p [%thread] (%F:%L) : %m%n%throwable"/>
|
||||
</Console>
|
||||
|
||||
<!-- 动态路由日志文件 -->
|
||||
<Routing name="RoutingAppender">
|
||||
<Routes pattern="$${date:yyyy-MM-dd}">
|
||||
<Route>
|
||||
<RollingFile name="Rolling-${date:yyyy-MM-dd}" fileName="logs/${date:yyyy-MM-dd}/system.log"
|
||||
filePattern="logs/%d{yyyy-MM-dd}/system-%i.log.gz">
|
||||
<PatternLayout>
|
||||
<pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %-5p [%thread] (%F:%L) : %m%n%throwable</pattern>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
<SizeBasedTriggeringPolicy size="1024 MB"/>
|
||||
</Policies>
|
||||
</RollingFile>
|
||||
</Route>
|
||||
</Routes>
|
||||
</Routing>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<!-- 根日志记录器 -->
|
||||
<Root level="info">
|
||||
<AppenderRef ref="ConsoleAppender"/>
|
||||
<AppenderRef ref="RoutingAppender"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user