✨ 执行日志文件自动清理.
This commit is contained in:
@@ -5,16 +5,19 @@
|
||||
|
||||
## v1.0.6
|
||||
|
||||
`2024-05-` `release`
|
||||
`2024-04-26` `release`
|
||||
|
||||
* 🐞 修复 终端页签关闭后不会自动切换
|
||||
* 🩰 修改 命令执行日志 UI 修改
|
||||
* 🌈 新增 命令执行模板配置默认主机
|
||||
* 🌈 新增 主机终端书签路径
|
||||
* 🌈 新增 命令日志添加状态信息 `app.exec-log.append-status`
|
||||
* 🌈 新增 定时删除命令日志文件 `app.exec-log.auto-clear`
|
||||
* 🔨 优化 通用分组模型添加 `userId`
|
||||
* 🔨 优化 退出登录不重定向
|
||||
* 🔨 优化 动态设置页面标题
|
||||
* 🔨 优化 终端断开后回车重连
|
||||
* 🔨 优化 自动删除未使用的命令片段分组
|
||||
|
||||
## v1.0.5
|
||||
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
数据库的数据都采用了逻辑删除, 可以将已删除的数据中的 `deleted` 字段改为 `0`
|
||||
如果不知道数据是哪一条, 可以查询用户操作日志, 点击 `参数` 寻找操作的id
|
||||
|
||||
> ##### 2. 是否支持维护 Windows 主机?
|
||||
|
||||
支持, 但是 Windows 的 ssh 命令兼容性不好, 一切需要执行ssh命令的地方都不友好
|
||||
|
||||
> ##### 3. 执行命令时为什么会找不到环境变量?
|
||||
> ##### 2. 执行命令时为什么会找不到环境变量?
|
||||
|
||||
可以在执行命令的第一行设置 `source /etc/profile` 来加载环境变量
|
||||
|
||||
> ##### 4. 命令中途执行失败如何设置中断执行?
|
||||
> ##### 3. 命令中途执行失败如何设置中断执行?
|
||||
|
||||
可以在执行命令的第一行设置 `set -e`
|
||||
作用是: 当执行出现意料之外的情况时, 立即退出
|
||||
|
||||
> ##### 5. 在调度任务、批量执行 命令执行成功的依据是什么?
|
||||
> ##### 4. 在调度任务、批量执行 命令执行成功的依据是什么?
|
||||
|
||||
是获取命令的 `exitcode` 判断是否为 `0` 如果非0则代表命令执行失败
|
||||
同理, 在命令的最后一行设置 `exit 1` 结果将会是失败, 可以用此来中断后续流程
|
||||
|
||||
> ##### 5. 调度任务、批量执行 的日志文件中如何只保存原始输出?
|
||||
|
||||
修改 application.yaml `app.exec-log.append-status` 为 false
|
||||
|
||||
> ##### 6. 为什么使用秘钥认证还是无法连接机器?
|
||||
|
||||
```
|
||||
|
||||
@@ -177,6 +177,14 @@ app:
|
||||
upload-present-backup: true
|
||||
# 备份文件名称
|
||||
backup-file-name: bk_${fileName}_${timestamp}
|
||||
# 执行日志
|
||||
exec-log:
|
||||
# 是否拼接执行状态
|
||||
append-status: true
|
||||
# 自动清理执行文件
|
||||
auto-clear: true
|
||||
# 保留周期
|
||||
keep-period: 0
|
||||
|
||||
# orion framework config
|
||||
orion:
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.orion.ops.module.asset.define.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 应用执行日志配置
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/4/25 13:36
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "app.exec-log")
|
||||
public class AppExecLogConfig {
|
||||
|
||||
/**
|
||||
* 是否拼接执行状态
|
||||
*/
|
||||
private Boolean appendStatus;
|
||||
|
||||
/**
|
||||
* 自动清理执行文件
|
||||
*/
|
||||
private Boolean autoClear;
|
||||
|
||||
/**
|
||||
* 保留周期 (天)
|
||||
*/
|
||||
private Integer keepPeriod;
|
||||
|
||||
public AppExecLogConfig() {
|
||||
this.appendStatus = true;
|
||||
this.autoClear = true;
|
||||
this.keepPeriod = 90;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package com.orion.ops.module.asset.task;
|
||||
|
||||
import com.orion.lang.utils.Strings;
|
||||
import com.orion.lang.utils.io.Files1;
|
||||
import com.orion.lang.utils.time.Dates;
|
||||
import com.orion.ops.framework.common.file.FileClient;
|
||||
import com.orion.ops.module.asset.dao.ExecHostLogDAO;
|
||||
import com.orion.ops.module.asset.define.config.AppExecLogConfig;
|
||||
import com.orion.ops.module.asset.entity.domain.ExecHostLogDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.api.RLock;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 执行日志文件自动清理
|
||||
*
|
||||
* @author Jiahang Li
|
||||
* @version 1.0.0
|
||||
* @since 2024/4/24 23:50
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@ConditionalOnProperty(value = "app.exec-log.auto-clear", havingValue = "true")
|
||||
public class ExecLogFileAutoClearTask {
|
||||
|
||||
/**
|
||||
* 分布式锁名称
|
||||
*/
|
||||
private static final String LOCK_KEY = "clear:elf:lock";
|
||||
|
||||
@Resource
|
||||
private AppExecLogConfig appExecLogConfig;
|
||||
|
||||
@Resource
|
||||
private RedissonClient redissonClient;
|
||||
|
||||
@Resource
|
||||
private FileClient logsFileClient;
|
||||
|
||||
@Resource
|
||||
private ExecHostLogDAO execHostLogDAO;
|
||||
|
||||
/**
|
||||
* 清理
|
||||
*/
|
||||
// @Scheduled(cron = "0 0 3 * * ?")
|
||||
@Scheduled(fixedRate = 20000)
|
||||
public void clear() {
|
||||
log.info("ExecLogFileAutoClearTask.clear start");
|
||||
// 获取锁
|
||||
RLock lock = redissonClient.getLock(LOCK_KEY);
|
||||
// 未获取到直接返回
|
||||
if (!lock.tryLock()) {
|
||||
log.info("ExecLogFileAutoClearTask.clear locked end");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 清理
|
||||
this.doClearFile();
|
||||
log.info("ExecLogFileAutoClearTask.clear finish");
|
||||
} catch (Exception e) {
|
||||
log.error("ExecLogFileAutoClearTask.clear error", e);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行清理文件
|
||||
*/
|
||||
private void doClearFile() {
|
||||
// 删除的时间区间
|
||||
String maxPeriod = Dates.stream()
|
||||
.subDay(appExecLogConfig.getKeepPeriod())
|
||||
.format();
|
||||
// 获取需要删除的最大id
|
||||
ExecHostLogDO hostLog = execHostLogDAO.of()
|
||||
.createWrapper()
|
||||
.select(ExecHostLogDO::getLogId, ExecHostLogDO::getLogPath)
|
||||
.lt(ExecHostLogDO::getCreateTime, maxPeriod)
|
||||
.orderByDesc(ExecHostLogDO::getId)
|
||||
.then()
|
||||
.getOne();
|
||||
if (hostLog == null) {
|
||||
return;
|
||||
}
|
||||
// 获取执行日志根目录
|
||||
String hostLogPath = logsFileClient.getAbsolutePath(hostLog.getLogPath());
|
||||
String execLogPath = Files1.getParentPath(hostLogPath);
|
||||
String parentPath = Files1.getParentPath(execLogPath);
|
||||
// 获取需要删除的文件
|
||||
List<File> files = Files1.listFilesFilter(parentPath, s -> {
|
||||
if (!Strings.isInteger(s.getName())) {
|
||||
return false;
|
||||
}
|
||||
return Long.parseLong(s.getName()) <= hostLog.getLogId();
|
||||
}, false, true);
|
||||
if (files.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
// 删除日志文件
|
||||
files.forEach(Files1::delete);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,11 @@
|
||||
"name": "app.sftp",
|
||||
"type": "com.orion.ops.module.asset.define.config.AppSftpConfig",
|
||||
"sourceType": "com.orion.ops.module.asset.define.config.AppSftpConfig"
|
||||
},
|
||||
{
|
||||
"name": "app.exec-log",
|
||||
"type": "com.orion.ops.module.asset.define.config.AppExecLogConfig",
|
||||
"sourceType": "com.orion.ops.module.asset.define.config.AppExecLogConfig"
|
||||
}
|
||||
],
|
||||
"properties": [
|
||||
@@ -41,6 +46,24 @@
|
||||
"type": "java.lang.String",
|
||||
"description": "备份文件名称.",
|
||||
"defaultValue": "bk_${fileName}_${timestamp}"
|
||||
},
|
||||
{
|
||||
"name": "app.exec-log.append-status",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "是否拼接执行状态.",
|
||||
"defaultValue": "true"
|
||||
},
|
||||
{
|
||||
"name": "app.exec-log.auto-clear",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "自动清理执行文件.",
|
||||
"defaultValue": "true"
|
||||
},
|
||||
{
|
||||
"name": "app.exec-log.keep-period",
|
||||
"type": "java.lang.Integer",
|
||||
"description": "保留周期 (天)",
|
||||
"defaultValue": "90"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user