From 6ee610f4ccea6907817efd97a0fa9d6b3952919f Mon Sep 17 00:00:00 2001 From: zlzw <583819556@qq.com> Date: Thu, 5 Dec 2024 10:36:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8A=A0=E4=BA=86=E6=97=A5=E5=BF=97=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- pom.xml | 15 +++ .../java/com/yutou/BilibiliApplication.java | 27 ++-- .../yutou/biliapi/net/WebSocketServer.java | 26 ++-- .../yutou/bilibili/Tools/ApplicationInit.java | 10 +- .../bilibili/services/SystemService.java | 4 +- .../common/okhttp/HttpLoggingInterceptor.java | 5 +- .../yutou/common/utils/DynamicLogFile.java | 123 ++++++++++++++++++ src/main/java/com/yutou/common/utils/Log.java | 9 ++ src/main/resources/application.properties | 1 + src/main/resources/log4j2.xml | 37 ++++++ 11 files changed, 227 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/yutou/common/utils/DynamicLogFile.java create mode 100644 src/main/resources/log4j2.xml diff --git a/.gitignore b/.gitignore index 39d4fa8..5d1a946 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,5 @@ build/ ### dir ### /live/ /databases/ -/cache/ \ No newline at end of file +/cache/ +/logs/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 38ff572..7417af9 100644 --- a/pom.xml +++ b/pom.xml @@ -144,6 +144,21 @@ selenium-java 4.26.0 + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + diff --git a/src/main/java/com/yutou/BilibiliApplication.java b/src/main/java/com/yutou/BilibiliApplication.java index c4b977c..e298260 100644 --- a/src/main/java/com/yutou/BilibiliApplication.java +++ b/src/main/java/com/yutou/BilibiliApplication.java @@ -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 追加关键词检测|加了 } diff --git a/src/main/java/com/yutou/biliapi/net/WebSocketServer.java b/src/main/java/com/yutou/biliapi/net/WebSocketServer.java index af32d2e..a2de8f3 100644 --- a/src/main/java/com/yutou/biliapi/net/WebSocketServer.java +++ b/src/main/java/com/yutou/biliapi/net/WebSocketServer.java @@ -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 roomMap; private final List 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()); diff --git a/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java b/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java index de4b3d9..5befe8a 100644 --- a/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java +++ b/src/main/java/com/yutou/bilibili/Tools/ApplicationInit.java @@ -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(); } diff --git a/src/main/java/com/yutou/bilibili/services/SystemService.java b/src/main/java/com/yutou/bilibili/services/SystemService.java index b4db522..59f59e4 100644 --- a/src/main/java/com/yutou/bilibili/services/SystemService.java +++ b/src/main/java/com/yutou/bilibili/services/SystemService.java @@ -81,7 +81,9 @@ public class SystemService { } public void stop() { - scheduled.cancel(true); + if(scheduled!=null) { + scheduled.cancel(true); + } videoService.stopAll(); } diff --git a/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java b/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java index ca0f922..edae618 100644 --- a/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java +++ b/src/main/java/com/yutou/common/okhttp/HttpLoggingInterceptor.java @@ -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); } diff --git a/src/main/java/com/yutou/common/utils/DynamicLogFile.java b/src/main/java/com/yutou/common/utils/DynamicLogFile.java new file mode 100644 index 0000000..578dc17 --- /dev/null +++ b/src/main/java/com/yutou/common/utils/DynamicLogFile.java @@ -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 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 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(); + } + +} diff --git a/src/main/java/com/yutou/common/utils/Log.java b/src/main/java/com/yutou/common/utils/Log.java index dab9d16..ca2be38 100644 --- a/src/main/java/com/yutou/common/utils/Log.java +++ b/src/main/java/com/yutou/common/utils/Log.java @@ -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; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index dc92337..80d9582 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,5 @@ server.port=8880 +logging.config=classpath:log4j2.xml logging.file.path=./logs logging.level.com.log.controller = trace # 启用Hibernate SQL日志 diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 0000000..08e385d --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + %d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} %-5p [%thread] (%F:%L) : %m%n%throwable + + + + + + + + + + + + + + + + + + + + +