From b2d758be333e5df8a654e9e04473196d6ba0a4ef Mon Sep 17 00:00:00 2001
From: 2995840376 <2995840376@xiaomi.com>
Date: Tue, 27 Oct 2026 18:28:19 +0800
Subject: [PATCH] =?UTF-8?q?fix(F):=20=E6=97=A5=E5=BF=97=E8=BD=AE=E8=BD=AC?=
=?UTF-8?q?=E6=B2=BB=E7=90=86=20-=20=E7=BB=9F=E4=B8=80=20logback=20?=
=?UTF-8?q?=E9=85=8D=E7=BD=AE=20+=20journald=20=E9=99=90=E9=A2=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
问题根因:
- iot-device.out 涨到 613MB:systemd StandardOutput=append: 无任何轮转
- DEBUG 刷屏(单日 11521 条):logging.level.com.iot=DEBUG 使 MyBatis 每条 SQL 打印两遍
- 涂鸦 open-mq-sdk jar 自带 logback.xml 抢占日志配置(iot-data/rule/alarm 未声明 logging.config),
把日志写到 ./logs 相对目录且无总量上限
改动:
- 新增 backend/iot-common/src/main/resources/logback-spring.xml(4 服务共用唯一真相源):
RollingFileAppender 按日 + 50MB 双触发切分,保留 7 天,主日志总量上限 2GB,
错误日志单独一份(保留 30 天 / 512MB),并对涂鸦/MQTT/AMQP 等第三方 SDK 降噪
- 父 pom 增加 maven-resources-plugin,把该配置复制进各服务 BOOT-INF/classes
- 4 个服务 application.yml 统一声明 logging.config,并把 com.iot 级别收敛为 INFO
- 新增 backend/deploy/systemd/:4 个 unit 改为 StandardOutput=journal + 注入 LOG_DIR,
附 journald 限额(SystemMaxUse=1G / SystemMaxFileSize=50M / MaxRetentionSec=7day)
- deploy-all.bat 增加日志治理步骤(同步 unit + journald + 清理历史 .out)
生产验证:日志落到 /opt/iotsaas/logs/app/*.log,DEBUG 计数 0,历史 .out 已清理,
journal 776M 降到 552M,4 服务 active,9081/9083 文档返回 200
---
backend/deploy/systemd/iot-alarm.service | 21 +++++
backend/deploy/systemd/iot-data.service | 21 +++++
backend/deploy/systemd/iot-device.service | 23 +++++
backend/deploy/systemd/iot-rule.service | 21 +++++
backend/deploy/systemd/journald-iotsaas.conf | 8 ++
.../src/main/resources/application.yml | 7 +-
.../src/main/resources/logback-spring.xml | 88 +++++++++++++++++++
.../src/main/resources/application.yml | 7 +-
.../src/main/resources/application.yml | 10 +--
.../src/main/resources/logback-spring.xml | 15 ----
.../src/main/resources/application.yml | 7 +-
backend/pom.xml | 31 +++++++
deploy-all.bat | 28 ++++--
13 files changed, 254 insertions(+), 33 deletions(-)
create mode 100644 backend/deploy/systemd/iot-alarm.service
create mode 100644 backend/deploy/systemd/iot-data.service
create mode 100644 backend/deploy/systemd/iot-device.service
create mode 100644 backend/deploy/systemd/iot-rule.service
create mode 100644 backend/deploy/systemd/journald-iotsaas.conf
create mode 100644 backend/iot-common/src/main/resources/logback-spring.xml
delete mode 100644 backend/iot-device/src/main/resources/logback-spring.xml
diff --git a/backend/deploy/systemd/iot-alarm.service b/backend/deploy/systemd/iot-alarm.service
new file mode 100644
index 0000000..d3d8584
--- /dev/null
+++ b/backend/deploy/systemd/iot-alarm.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=IoT Alarm Service (9084)
+After=docker.service network.target
+Requires=docker.service
+
+[Service]
+Type=simple
+User=tonzou
+WorkingDirectory=/opt/iotsaas/backend/jars
+# 日志根目录:logback-spring.xml 中 ${LOG_DIR:-logs/app} 读取该环境变量
+Environment="LOG_DIR=/opt/iotsaas/logs/app"
+ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/iotsaas/backend/jars/iot-alarm-1.0.0.jar
+SuccessExitStatus=143
+Restart=on-failure
+RestartSec=10
+# 控制台输出交由 systemd journal(自带轮转与体积上限),不再写无轮转的 *.out
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
diff --git a/backend/deploy/systemd/iot-data.service b/backend/deploy/systemd/iot-data.service
new file mode 100644
index 0000000..b1e7481
--- /dev/null
+++ b/backend/deploy/systemd/iot-data.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=IoT Data Collection Service (9082)
+After=docker.service network.target
+Requires=docker.service
+
+[Service]
+Type=simple
+User=tonzou
+WorkingDirectory=/opt/iotsaas/backend/jars
+# 日志根目录:logback-spring.xml 中 ${LOG_DIR:-logs/app} 读取该环境变量
+Environment="LOG_DIR=/opt/iotsaas/logs/app"
+ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/iotsaas/backend/jars/iot-data-1.0.0.jar
+SuccessExitStatus=143
+Restart=on-failure
+RestartSec=10
+# 控制台输出交由 systemd journal(自带轮转与体积上限),不再写无轮转的 *.out
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
diff --git a/backend/deploy/systemd/iot-device.service b/backend/deploy/systemd/iot-device.service
new file mode 100644
index 0000000..5d1f24e
--- /dev/null
+++ b/backend/deploy/systemd/iot-device.service
@@ -0,0 +1,23 @@
+[Unit]
+Description=IoT Device Service (9081)
+After=docker.service network.target
+Requires=docker.service
+
+[Service]
+Type=simple
+User=tonzou
+WorkingDirectory=/opt/iotsaas/backend/jars
+# 日志根目录:logback-spring.xml 中 ${LOG_DIR:-logs/app} 读取该环境变量,
+# 滚动日志落到 /opt/iotsaas/logs/app/iot-device.log(按日+50MB 切分,保留 7 天)
+Environment="LOG_DIR=/opt/iotsaas/logs/app"
+ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/iotsaas/backend/jars/iot-device-1.0.0-exec.jar
+SuccessExitStatus=143
+Restart=on-failure
+RestartSec=10
+# 控制台输出交由 systemd journal(自带轮转与体积上限),
+# 不再写 append:*.out 这类无轮转文件(曾膨胀到 613MB)
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
diff --git a/backend/deploy/systemd/iot-rule.service b/backend/deploy/systemd/iot-rule.service
new file mode 100644
index 0000000..017f39b
--- /dev/null
+++ b/backend/deploy/systemd/iot-rule.service
@@ -0,0 +1,21 @@
+[Unit]
+Description=IoT Rule Engine Service (9083)
+After=docker.service network.target
+Requires=docker.service
+
+[Service]
+Type=simple
+User=tonzou
+WorkingDirectory=/opt/iotsaas/backend/jars
+# 日志根目录:logback-spring.xml 中 ${LOG_DIR:-logs/app} 读取该环境变量
+Environment="LOG_DIR=/opt/iotsaas/logs/app"
+ExecStart=/usr/bin/java -Xms256m -Xmx512m -jar /opt/iotsaas/backend/jars/iot-rule-1.0.0.jar
+SuccessExitStatus=143
+Restart=on-failure
+RestartSec=10
+# 控制台输出交由 systemd journal(自带轮转与体积上限),不再写无轮转的 *.out
+StandardOutput=journal
+StandardError=journal
+
+[Install]
+WantedBy=multi-user.target
diff --git a/backend/deploy/systemd/journald-iotsaas.conf b/backend/deploy/systemd/journald-iotsaas.conf
new file mode 100644
index 0000000..6c5585d
--- /dev/null
+++ b/backend/deploy/systemd/journald-iotsaas.conf
@@ -0,0 +1,8 @@
+[Journal]
+# iotsaas 日志治理:限制 journal 体积,避免 /var/log/journal 无限增长
+# (Ubuntu 默认 SystemMaxUse = 磁盘的 10%,本机 1.8T 盘即 180G,过大)
+Storage=persistent
+SystemMaxUse=1G
+SystemMaxFileSize=50M
+SystemMaxFileSec=1day
+MaxRetentionSec=7day
diff --git a/backend/iot-alarm/src/main/resources/application.yml b/backend/iot-alarm/src/main/resources/application.yml
index 92fe82f..c95b493 100644
--- a/backend/iot-alarm/src/main/resources/application.yml
+++ b/backend/iot-alarm/src/main/resources/application.yml
@@ -95,7 +95,10 @@ mybatis-plus:
# 日志配置
logging:
+ # 显式指定日志配置:涂鸦 open-mq-sdk jar 内自带 logback.xml 会被抢占,
+ # 强制使用统一配置(文件本体在 iot-common,构建时复制到本模块),含滚动切分与保留策略
+ config: classpath:logback-spring.xml
level:
root: INFO
- com.iot: DEBUG
- com.iot.alarm: DEBUG
+ com.iot: INFO
+ com.iot.alarm: INFO
diff --git a/backend/iot-common/src/main/resources/logback-spring.xml b/backend/iot-common/src/main/resources/logback-spring.xml
new file mode 100644
index 0000000..a8305fe
--- /dev/null
+++ b/backend/iot-common/src/main/resources/logback-spring.xml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${LOG_PATTERN}
+ UTF-8
+
+
+
+
+
+ ${LOG_FILE}
+
+ ${LOG_FILE_PATTERN}
+ 50MB
+ 7
+ 2GB
+ true
+
+
+ ${LOG_PATTERN}
+ UTF-8
+
+
+
+
+
+ ${ERR_FILE}
+
+ ERROR
+ ACCEPT
+ DENY
+
+
+ ${ERR_FILE_PATTERN}
+ 20MB
+ 30
+ 512MB
+ true
+
+
+ ${LOG_PATTERN}
+ UTF-8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/backend/iot-data/src/main/resources/application.yml b/backend/iot-data/src/main/resources/application.yml
index 4160093..ba9e15d 100644
--- a/backend/iot-data/src/main/resources/application.yml
+++ b/backend/iot-data/src/main/resources/application.yml
@@ -84,7 +84,10 @@ mybatis-plus:
# 日志配置
logging:
+ # 显式指定日志配置:涂鸦 open-mq-sdk jar 内自带 logback.xml 会被抢占,
+ # 强制使用统一配置(文件本体在 iot-common,构建时复制到本模块),含滚动切分与保留策略
+ config: classpath:logback-spring.xml
level:
root: INFO
- com.iot: DEBUG
- com.iot.data: DEBUG
+ com.iot: INFO
+ com.iot.data: INFO
diff --git a/backend/iot-device/src/main/resources/application.yml b/backend/iot-device/src/main/resources/application.yml
index 1933b17..33f0543 100644
--- a/backend/iot-device/src/main/resources/application.yml
+++ b/backend/iot-device/src/main/resources/application.yml
@@ -111,14 +111,14 @@ xxl:
logging:
# 显式指定日志配置:涂鸦 open-mq-sdk jar 内自带 logback.xml 会被标准 logback
# 自动初始化命中并抢占日志输出(控制台无日志、日志写入 ./logs/ 相对目录),
- # 这里强制使用本应用的 logback-spring.xml 覆盖之
+ # 这里强制使用本应用的 logback-spring.xml 覆盖之(文件本体在 iot-common,构建时复制到本模块)
config: classpath:logback-spring.xml
level:
root: INFO
- com.iot: DEBUG
- com.iot.device: DEBUG
- pattern:
- console: '%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{50} - %msg%n'
+ # 生产环境保持 INFO:MyBatis mapper 的 SQL 日志在 DEBUG 级别,
+ # 打开后每条 SQL 打印两次,单日可产生上万条日志并撑大日志文件
+ com.iot: INFO
+ com.iot.device: INFO
# Swagger配置
knife4j:
diff --git a/backend/iot-device/src/main/resources/logback-spring.xml b/backend/iot-device/src/main/resources/logback-spring.xml
deleted file mode 100644
index c33cf02..0000000
--- a/backend/iot-device/src/main/resources/logback-spring.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/backend/iot-rule/src/main/resources/application.yml b/backend/iot-rule/src/main/resources/application.yml
index c9cf3d8..3ef34c1 100644
--- a/backend/iot-rule/src/main/resources/application.yml
+++ b/backend/iot-rule/src/main/resources/application.yml
@@ -97,8 +97,11 @@ mybatis-plus:
# 日志配置
logging:
+ # 显式指定日志配置:涂鸦 open-mq-sdk jar 内自带 logback.xml 会被抢占,
+ # 强制使用统一配置(文件本体在 iot-common,构建时复制到本模块),含滚动切分与保留策略
+ config: classpath:logback-spring.xml
level:
root: INFO
- com.iot: DEBUG
- com.iot.rule: DEBUG
+ com.iot: INFO
+ com.iot.rule: INFO
org.drools: INFO
diff --git a/backend/pom.xml b/backend/pom.xml
index 02ef6e4..fb6a7b9 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -199,6 +199,37 @@
org.apache.maven.plugins
maven-compiler-plugin
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ copy-logback-config
+ process-resources
+
+ copy-resources
+
+
+ ${project.build.outputDirectory}
+ true
+
+
+ ${project.basedir}/../iot-common/src/main/resources
+
+ logback-spring.xml
+
+ false
+
+
+
+
+
+
diff --git a/deploy-all.bat b/deploy-all.bat
index 8ca3291..715e96f 100644
--- a/deploy-all.bat
+++ b/deploy-all.bat
@@ -25,7 +25,7 @@ set JAR_ALARM=iot-alarm-1.0.0.jar
:: ============ 1) 后端构建(含共享模块 iot-common) ============
cd /d %BACKEND_DIR%
echo ============================================
-echo [1/7] Maven 重新构建 4 个服务(含共享模块 iot-common)
+echo [1/8] Maven 重新构建 4 个服务(含共享模块 iot-common)
echo ============================================
call mvn clean package -pl iot-device,iot-data,iot-rule,iot-alarm -am -DskipTests
if %ERRORLEVEL% NEQ 0 ( echo [错误] 后端构建失败,已中止。 & pause & exit /b 1 )
@@ -33,7 +33,7 @@ echo [OK] 后端构建成功。
:: ============ 2) 上传 4 个 jar ============
echo ============================================
-echo [2/7] 上传 4 个 jar 到服务器 %SRV_JARS%
+echo [2/8] 上传 4 个 jar 到服务器 %SRV_JARS%
echo ============================================
tar cf - -C %BACKEND_DIR%\iot-device\target %JAR_DEV% -C %BACKEND_DIR%\iot-data\target %JAR_DATA% -C %BACKEND_DIR%\iot-rule\target %JAR_RULE% -C %BACKEND_DIR%\iot-alarm\target %JAR_ALARM% | %PLINK% %PLINK_OPTS% tar xf - -C %SRV_JARS%
if %ERRORLEVEL% NEQ 0 ( echo [错误] jar 上传失败。 & pause & exit /b 1 )
@@ -41,7 +41,7 @@ echo [OK] jar 上传完成。
:: ============ 2.5) 数据库迁移(Flyway 在本环境未启用,按 DB 内 tracking 表应用未执行的 V 迁移) ============
echo ============================================
-echo [3/7] 应用未执行的 SQL 迁移(%BACKEND_DIR%\sql\V*.sql,按 db_migrations_applied 去重)
+echo [3/8] 应用未执行的 SQL 迁移(%BACKEND_DIR%\sql\V*.sql,按 db_migrations_applied 去重)
echo ============================================
set MIG_DIR=%BACKEND_DIR%\sql
set CHK_FILE=%TEMP%\_mig_chk.txt
@@ -58,9 +58,23 @@ REM 应用未记录的 V 迁移(新增迁移文件会自动在此补跑,无
for /f "delims=" %%F in ('dir /b /on "%MIG_DIR%\V*.sql"') do call :mig_apply "%%F"
echo [OK] 迁移步骤完成。
+::: ============ 3.5) 日志治理:同步 systemd 单元 + journald 限额,清理无轮转的历史 .out ============
+echo ============================================
+echo [4/8] 同步 systemd 单元与 journald 限额(日志轮转治理),并清理历史无轮转 .out/.err
+echo ============================================
+%PLINK% %PLINK_OPTS% "rm -rf /tmp/iotsaas-units && mkdir -p /tmp/iotsaas-units"
+tar cf - -C %BACKEND_DIR%\deploy\systemd . | %PLINK% %PLINK_OPTS% tar xf - -C /tmp/iotsaas-units
+if %ERRORLEVEL% NEQ 0 ( echo [错误] systemd 单元上传失败。 & pause & exit /b 1 )
+%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' cp /tmp/iotsaas-units/iot-device.service /tmp/iotsaas-units/iot-data.service /tmp/iotsaas-units/iot-rule.service /tmp/iotsaas-units/iot-alarm.service /etc/systemd/system/ && echo 'Tonzou@888' | sudo -S -p '' mkdir -p /etc/systemd/journald.conf.d && echo 'Tonzou@888' | sudo -S -p '' cp /tmp/iotsaas-units/journald-iotsaas.conf /etc/systemd/journald.conf.d/iotsaas.conf"
+if %ERRORLEVEL% NEQ 0 ( echo [错误] systemd 单元安装失败。 & pause & exit /b 1 )
+%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl daemon-reload && echo 'Tonzou@888' | sudo -S -p '' systemctl restart systemd-journald"
+REM 清理历史无轮转的 .out/.err(内容已由 journal 与滚动日志文件接管),并准备滚动日志目录
+%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' rm -f /opt/iotsaas/logs/*.out /opt/iotsaas/logs/*.err && echo 'Tonzou@888' | sudo -S -p '' rm -rf /opt/iotsaas/backend/jars/logs && echo 'Tonzou@888' | sudo -S -p '' mkdir -p /opt/iotsaas/logs/app && echo 'Tonzou@888' | sudo -S -p '' chown -R tonzou:tonzou /opt/iotsaas/logs"
+echo [OK] systemd 单元与 journald 限额已同步,历史 .out 已清理。
+
:: ============ 3) 重启 4 个后端服务 ============
echo ============================================
-echo [4/7] 重启 4 个后端服务(systemd)
+echo [5/8] 重启 4 个后端服务(systemd)
echo ============================================
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl restart iot-device iot-data iot-rule iot-alarm" 2>nul
if %ERRORLEVEL% NEQ 0 ( echo [错误] 服务重启失败。 & pause & exit /b 1 )
@@ -69,7 +83,7 @@ echo [OK] 重启命令已下发。
:: ============ 4) 构建前端后台(admin) ============
cd /d %ADMIN_DIR%
echo ============================================
-echo [5/7] 构建前端后台(admin)— 跳过 vue-tsc 类型检查,直接 vite build
+echo [6/8] 构建前端后台(admin)— 跳过 vue-tsc 类型检查,直接 vite build
echo ============================================
where node >nul 2>nul || ( echo [错误] 未找到 node,请将其加入 PATH。 & pause & exit /b 1 )
call npx vite build
@@ -78,7 +92,7 @@ echo [OK] 前端构建成功(dist 已生成)。
:: ============ 5) 上传前端 dist(先清空旧文件再解包,避免残留旧 hash 资源) ============
echo ============================================
-echo [6/7] 上传前端 dist 到服务器 %SRV_DIST%
+echo [7/8] 上传前端 dist 到服务器 %SRV_DIST%
echo ============================================
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' rm -rf %SRV_DIST% && mkdir -p %SRV_DIST%"
if %ERRORLEVEL% NEQ 0 ( echo [错误] 清空远端 dist 失败。 & pause & exit /b 1 )
@@ -88,7 +102,7 @@ echo [OK] dist 上传完成。
:: ============ 6) 确认状态 ============
echo ============================================
-echo [7/7] 等待启动并确认服务状态
+echo [8/8] 等待启动并确认服务状态
echo ============================================
timeout /t 20 /nobreak >nul
%PLINK% %PLINK_OPTS% "echo 'Tonzou@888' | sudo -S -p '' systemctl is-active iot-device iot-data iot-rule iot-alarm" 2>nul