自动清理配置.

This commit is contained in:
lijiahang
2024-06-25 10:42:32 +08:00
parent b08d75be62
commit f0a122d862
20 changed files with 318 additions and 121 deletions

View File

@@ -0,0 +1,22 @@
package com.orion.visor.module.asset.define.config;
import com.orion.visor.framework.common.entity.AutoClearConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 批量执行日志自动清理配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/24 15:01
*/
@Data
@Component
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "app.auto-clear.exec-log")
public class AppExecLogAutoClearConfig extends AutoClearConfig {
}

View File

@@ -21,20 +21,8 @@ public class AppExecLogConfig {
*/
private Boolean appendAnsi;
/**
* 自动清理执行文件
*/
private Boolean autoClear;
/**
* 保留周期 (天)
*/
private Integer keepPeriod;
public AppExecLogConfig() {
this.appendAnsi = true;
this.autoClear = true;
this.keepPeriod = 30;
}
}

View File

@@ -0,0 +1,22 @@
package com.orion.visor.module.asset.define.config;
import com.orion.visor.framework.common.entity.AutoClearConfig;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 主机连接日志自动清理配置
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/6/24 15:01
*/
@Data
@Component
@EqualsAndHashCode(callSuper = true)
@ConfigurationProperties(prefix = "app.auto-clear.host-connect-log")
public class AppHostConnectLogAutoClearConfig extends AutoClearConfig {
}

View File

@@ -7,6 +7,7 @@ import lombok.*;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 批量执行日志 查询请求对象
@@ -54,4 +55,11 @@ public class ExecLogQueryRequest extends PageRequest {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date[] startTimeRange;
@Schema(description = "创建时间 <=")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeLe;
@Schema(description = "状态")
private List<String> statusList;
}

View File

@@ -56,4 +56,11 @@ public class HostConnectLogQueryRequest extends PageRequest {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date[] startTimeRange;
@Schema(description = "创建时间 <=")
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTimeLe;
@Schema(description = "状态")
private List<String> statusList;
}

View File

@@ -1,8 +1,11 @@
package com.orion.visor.module.asset.enums;
import com.orion.lang.utils.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
/**
* 批量执行状态
*
@@ -36,6 +39,8 @@ public enum ExecStatusEnum {
;
public static final List<String> FINISH_STATUS_LIST = Lists.of(COMPLETED.name(), FAILED.name());
private final boolean closeable;
public static ExecStatusEnum of(String status) {

View File

@@ -1,5 +1,9 @@
package com.orion.visor.module.asset.enums;
import com.orion.lang.utils.collect.Lists;
import java.util.List;
/**
* 主机连接状态
*
@@ -31,6 +35,8 @@ public enum HostConnectStatusEnum {
;
public static final List<String> FINISH_STATUS_LIST = Lists.of(COMPLETE.name(), FAILED.name(), FORCE_OFFLINE.name());
public static HostConnectStatusEnum of(String type) {
if (type == null) {
return null;

View File

@@ -13,6 +13,7 @@ import com.orion.visor.framework.common.enums.BooleanBit;
import com.orion.visor.framework.websocket.core.utils.WebSockets;
import com.orion.visor.module.asset.dao.HostDAO;
import com.orion.visor.module.asset.define.operator.HostTerminalOperatorType;
import com.orion.visor.module.asset.entity.domain.HostConnectLogDO;
import com.orion.visor.module.asset.entity.domain.HostDO;
import com.orion.visor.module.asset.entity.dto.HostTerminalConnectDTO;
import com.orion.visor.module.asset.entity.request.host.HostConnectLogCreateRequest;
@@ -95,9 +96,9 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
log.error("TerminalCheckHandler-handle exception userId: {}, hostId: {}, sessionId: {}", userId, hostId, sessionId, e);
}
// 记录主机日志
Long logId = this.saveHostLog(channel, userId, host, startTime, ex, sessionId, connectType);
HostConnectLogDO connectLog = this.saveHostLog(channel, userId, host, startTime, ex, sessionId, connectType);
if (connect != null) {
connect.setLogId(logId);
connect.setLogId(connectLog.getId());
}
// 响应检查结果
this.send(channel,
@@ -170,15 +171,15 @@ public class TerminalCheckHandler extends AbstractTerminalHandler<TerminalCheckR
* @param ex ex
* @param sessionId sessionId
* @param connectType connectType
* @return logId
* @return connectLog
*/
private Long saveHostLog(WebSocketSession channel,
Long userId,
HostDO host,
long startTime,
Exception ex,
String sessionId,
HostConnectTypeEnum connectType) {
private HostConnectLogDO saveHostLog(WebSocketSession channel,
Long userId,
HostDO host,
long startTime,
Exception ex,
String sessionId,
HostConnectTypeEnum connectType) {
Long hostId = host.getId();
String hostName = host.getName();
String username = WebSockets.getAttr(channel, ExtraFieldConst.USERNAME);

View File

@@ -71,6 +71,14 @@ public interface ExecLogService {
*/
Integer deleteExecLogByIdList(List<Long> idList, String source);
/**
* 批量删除批量执行日志
*
* @param idList idList
* @return effect
*/
Integer deleteExecLogByIdList(List<Long> idList);
/**
* 查询批量执行日志数量
*
@@ -128,4 +136,11 @@ public interface ExecLogService {
*/
void downloadLogFile(Long id, String source, HttpServletResponse response);
/**
* 异步删除日志文件
*
* @param idList idList
*/
void asyncDeleteLogFiles(List<Long> idList);
}

View File

@@ -1,6 +1,7 @@
package com.orion.visor.module.asset.service;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.visor.module.asset.entity.domain.HostConnectLogDO;
import com.orion.visor.module.asset.entity.request.host.HostConnectLogCreateRequest;
import com.orion.visor.module.asset.entity.request.host.HostConnectLogQueryRequest;
import com.orion.visor.module.asset.entity.vo.HostConnectLogVO;
@@ -25,9 +26,9 @@ public interface HostConnectLogService {
*
* @param type type
* @param request request
* @return id
* @return record
*/
Long create(HostConnectTypeEnum type, HostConnectLogCreateRequest request);
HostConnectLogDO create(HostConnectTypeEnum type, HostConnectLogCreateRequest request);
/**
* 分页查询主机连接日志

View File

@@ -11,11 +11,13 @@ import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Lists;
import com.orion.lang.utils.io.Files1;
import com.orion.lang.utils.io.Streams;
import com.orion.spring.SpringHolder;
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.visor.framework.common.annotation.Keep;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.constant.PathConst;
import com.orion.visor.framework.common.constant.FileConst;
import com.orion.visor.framework.common.enums.EndpointDefine;
import com.orion.visor.framework.common.file.FileClient;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.redis.core.utils.RedisStrings;
@@ -46,11 +48,13 @@ import com.orion.visor.module.asset.service.ExecLogService;
import com.orion.visor.module.asset.service.HostConfigService;
import com.orion.web.servlet.web.Servlets;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;
@@ -173,20 +177,7 @@ public class ExecLogServiceImpl implements ExecLogService {
@Override
@Transactional(rollbackFor = Exception.class)
public Integer deleteExecLogById(Long id, String source) {
log.info("ExecLogService-deleteExecLogById id: {}", id);
// 检查数据是否存在
ExecLogDO record = execLogDAO.selectByIdSource(id, source);
Valid.notNull(record, ErrorMessage.DATA_ABSENT);
// 中断命令执行
this.interruptTask(Lists.singleton(id));
// 删除执行日志
int effect = execLogDAO.deleteById(id);
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(Lists.singleton(id));
log.info("ExecLogService-deleteExecLogById id: {}, effect: {}", id, effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
return effect;
return this.deleteExecLogByIdList(Lists.singleton(id), source);
}
@Override
@@ -201,15 +192,28 @@ public class ExecLogServiceImpl implements ExecLogService {
.count()
.intValue();
Valid.isTrue(idList.size() == count, ErrorMessage.DATA_MODIFIED);
// 删除
return this.deleteExecLogByIdList(idList);
}
@Override
public Integer deleteExecLogByIdList(List<Long> idList) {
log.info("ExecLogService-deleteExecLogByIdList start: {}", idList);
if (Lists.isEmpty(idList)) {
OperatorLogs.add(OperatorLogs.COUNT, Const.N_0);
return Const.N_0;
}
// 中断命令执行
this.interruptTask(idList);
// 删除执行日志
int effect = execLogDAO.deleteBatchIds(idList);
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(idList);
log.info("ExecLogService-deleteExecLogByIdList effect: {}", effect);
log.info("ExecLogService-deleteExecLogByIdList end effect: {}", effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
// 异步删除文件
SpringHolder.getBean(ExecLogService.class).asyncDeleteLogFiles(idList);
return effect;
}
@@ -229,19 +233,8 @@ public class ExecLogServiceImpl implements ExecLogService {
.stream()
.map(ExecLogDO::getId)
.collect(Collectors.toList());
int effect = 0;
if (!idList.isEmpty()) {
// 中断命令执行
this.interruptTask(idList);
// 删除执行日志
effect = execLogDAO.delete(wrapper);
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(idList);
}
log.info("ExecLogService.clearExecLog finish {}", effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
return effect;
// 删除
return this.deleteExecLogByIdList(idList);
}
@Override
@@ -428,19 +421,35 @@ public class ExecLogServiceImpl implements ExecLogService {
} catch (Exception e) {
log.error("ExecLogService.downloadLogFile error id: {}", id, e);
Streams.close(in);
String errorMessage = ErrorMessage.FILE_READ_ERROR;
String errorMessage = ErrorMessage.FILE_READ_ERROR_CLEAR;
if (e instanceof InvalidArgumentException) {
errorMessage = e.getMessage();
}
// 响应错误信息
try {
Servlets.transfer(response, Strings.bytes(errorMessage), PathConst.ERROR_LOG);
Servlets.transfer(response, Strings.bytes(errorMessage), FileConst.ERROR_LOG);
} catch (Exception ex) {
log.error("ExecLogService.downloadLogFile transfer-error id: {}", id, ex);
}
}
}
@Override
@Async("asyncExecutor")
public void asyncDeleteLogFiles(List<Long> idList) {
if (Lists.isEmpty(idList)) {
return;
}
// 删除
idList.stream()
.map(s -> EndpointDefine.EXEC_LOG.format(s, Const.EMPTY))
.map(logsFileClient::getReturnPath)
.map(logsFileClient::getAbsolutePath)
.map(Files1::getParentPath)
.map(File::new)
.forEach(Files1::delete);
}
/**
* 构建查询 wrapper
*
@@ -457,8 +466,10 @@ public class ExecLogServiceImpl implements ExecLogService {
.like(ExecLogDO::getDescription, request.getDescription())
.like(ExecLogDO::getCommand, request.getCommand())
.eq(ExecLogDO::getStatus, request.getStatus())
.in(ExecLogDO::getStatus, request.getStatusList())
.ge(ExecLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 0))
.le(ExecLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 1))
.le(ExecLogDO::getCreateTime, request.getCreateTimeLe())
.orderByDesc(ExecLogDO::getId);
}

View File

@@ -2,13 +2,13 @@ package com.orion.visor.module.asset.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.constant.Const;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.lang.utils.Arrays1;
import com.orion.lang.utils.Valid;
import com.orion.lang.utils.collect.Lists;
import com.orion.visor.framework.biz.operator.log.core.utils.OperatorLogs;
import com.orion.visor.framework.common.constant.Const;
import com.orion.visor.framework.common.constant.ErrorMessage;
import com.orion.visor.framework.common.utils.Valid;
import com.orion.visor.framework.security.core.utils.SecurityUtils;
import com.orion.visor.module.asset.convert.HostConnectLogConvert;
import com.orion.visor.module.asset.dao.HostConnectLogDAO;
@@ -52,7 +52,7 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
private HostTerminalManager hostTerminalManager;
@Override
public Long create(HostConnectTypeEnum type, HostConnectLogCreateRequest request) {
public HostConnectLogDO create(HostConnectTypeEnum type, HostConnectLogCreateRequest request) {
HostConnectLogDO record = HostConnectLogConvert.MAPPER.to(request);
record.setType(type.name());
String status = request.getStatus();
@@ -64,7 +64,7 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
record.setEndTime(new Date());
}
hostConnectLogDAO.insert(record);
return record.getId();
return record;
}
@Override
@@ -169,6 +169,11 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
@Override
public Integer deleteHostConnectLog(List<Long> idList) {
log.info("HostConnectLogService.deleteHostConnectLog start {}", JSON.toJSONString(idList));
if (Lists.isEmpty(idList)) {
OperatorLogs.add(OperatorLogs.COUNT, Const.N_0);
return Const.N_0;
}
// 删除
int effect = hostConnectLogDAO.deleteBatchIds(idList);
log.info("HostConnectLogService.deleteHostConnectLog finish {}", effect);
// 设置日志参数
@@ -184,13 +189,21 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
@Override
public Integer clearHostConnectLog(HostConnectLogQueryRequest request) {
log.info("HostConnectLogService.clearHostConnectLog start {}", JSON.toJSONString(request));
// 查询
LambdaQueryWrapper<HostConnectLogDO> wrapper = this.buildQueryWrapper(request)
.select(HostConnectLogDO::getId);
List<HostConnectLogDO> list = hostConnectLogDAO.selectList(wrapper);
if (list.isEmpty()) {
log.info("HostConnectLogService.clearHostConnectLog empty");
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, Const.N_0);
return Const.N_0;
}
// 删除
LambdaQueryWrapper<HostConnectLogDO> wrapper = this.buildQueryWrapper(request);
int effect = hostConnectLogDAO.delete(wrapper);
log.info("HostConnectLogService.clearHostConnectLog finish {}", effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
return effect;
List<Long> idList = list.stream()
.map(HostConnectLogDO::getId)
.collect(Collectors.toList());
return this.deleteHostConnectLog(idList);
}
@Override
@@ -229,8 +242,10 @@ public class HostConnectLogServiceImpl implements HostConnectLogService {
.eq(HostConnectLogDO::getType, request.getType())
.like(HostConnectLogDO::getToken, request.getToken())
.eq(HostConnectLogDO::getStatus, request.getStatus())
.in(HostConnectLogDO::getStatus, request.getStatusList())
.ge(HostConnectLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 0))
.le(HostConnectLogDO::getStartTime, Arrays1.getIfPresent(request.getStartTimeRange(), 1))
.le(HostConnectLogDO::getCreateTime, request.getCreateTimeLe())
.orderByDesc(HostConnectLogDO::getId);
}

View File

@@ -1,22 +1,18 @@
package com.orion.visor.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.visor.framework.common.annotation.Keep;
import com.orion.visor.framework.common.file.FileClient;
import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.asset.dao.ExecHostLogDAO;
import com.orion.visor.module.asset.define.config.AppExecLogConfig;
import com.orion.visor.module.asset.entity.domain.ExecHostLogDO;
import com.orion.visor.module.asset.define.config.AppExecLogAutoClearConfig;
import com.orion.visor.module.asset.entity.request.exec.ExecLogQueryRequest;
import com.orion.visor.module.asset.enums.ExecStatusEnum;
import com.orion.visor.module.asset.service.ExecLogService;
import lombok.extern.slf4j.Slf4j;
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;
import java.util.Date;
/**
* 执行日志文件自动清理
@@ -27,23 +23,19 @@ import java.util.List;
*/
@Slf4j
@Component
@ConditionalOnProperty(value = "app.exec-log.auto-clear", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(value = "app.auto-clear.exec-log.enabled", havingValue = "true")
public class ExecLogFileAutoClearTask {
/**
* 分布式锁名称
*/
private static final String LOCK_KEY = "clear:elf:lock";
private static final String LOCK_KEY = "clear:exl:lock";
@Resource
private AppExecLogConfig appExecLogConfig;
@Keep
@Resource
private FileClient logsFileClient;
private AppExecLogAutoClearConfig appExecLogAutoClearConfig;
@Resource
private ExecHostLogDAO execHostLogDAO;
private ExecLogService execLogService;
/**
* 清理
@@ -52,45 +44,23 @@ public class ExecLogFileAutoClearTask {
public void clear() {
log.info("ExecLogFileAutoClearTask.clear start");
// 获取锁并执行
LockerUtils.tryLock(LOCK_KEY, this::doClearFile);
LockerUtils.tryLock(LOCK_KEY, this::doClear);
log.info("ExecLogFileAutoClearTask.clear finish");
}
/**
* 执行清理文件
* 执行清理
*/
private void doClearFile() {
private void doClear() {
// 删除的时间区间
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);
Date createLessEq = Dates.stream()
.subDay(appExecLogAutoClearConfig.getKeepPeriod())
.date();
// 清理
ExecLogQueryRequest request = new ExecLogQueryRequest();
request.setCreateTimeLe(createLessEq);
request.setStatusList(ExecStatusEnum.FINISH_STATUS_LIST);
execLogService.clearExecLog(request);
}
}

View File

@@ -0,0 +1,66 @@
package com.orion.visor.module.asset.task;
import com.orion.lang.utils.time.Dates;
import com.orion.visor.framework.common.utils.LockerUtils;
import com.orion.visor.module.asset.define.config.AppHostConnectLogAutoClearConfig;
import com.orion.visor.module.asset.entity.request.host.HostConnectLogQueryRequest;
import com.orion.visor.module.asset.enums.HostConnectStatusEnum;
import com.orion.visor.module.asset.service.HostConnectLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Date;
/**
* 主机连接日志自动清理
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/4/24 23:50
*/
@Slf4j
@Component
@ConditionalOnProperty(value = "app.auto-clear.host-connect-log.enabled", havingValue = "true")
public class HostConnectLogAutoClearTask {
/**
* 分布式锁名称
*/
private static final String LOCK_KEY = "clear:hcl:lock";
@Resource
private AppHostConnectLogAutoClearConfig appHostConnectLogAutoClearConfig;
@Resource
private HostConnectLogService hostConnectLogService;
/**
* 清理
*/
@Scheduled(cron = "0 10 3 * * ?")
public void clear() {
log.info("HostConnectLogAutoClearTask.clear start");
// 获取锁并执行
LockerUtils.tryLock(LOCK_KEY, this::doClear);
log.info("HostConnectLogAutoClearTask.clear finish");
}
/**
* 执行清理
*/
private void doClear() {
// 删除的时间区间
Date createLessEq = Dates.stream()
.subDay(appHostConnectLogAutoClearConfig.getKeepPeriod())
.date();
// 清理
HostConnectLogQueryRequest request = new HostConnectLogQueryRequest();
request.setCreateTimeLe(createLessEq);
request.setStatusList(HostConnectStatusEnum.FINISH_STATUS_LIST);
hostConnectLogService.clearHostConnectLog(request);
}
}

View File

@@ -19,6 +19,11 @@
"name": "app.auto-clear.exec-log",
"type": "com.orion.visor.module.asset.define.config.AppExecLogAutoClearConfig",
"sourceType": "com.orion.visor.module.asset.define.config.AppExecLogAutoClearConfig"
},
{
"name": "app.auto-clear.host-connect-log",
"type": "com.orion.visor.module.asset.define.config.AppHostConnectLogAutoClearConfig",
"sourceType": "com.orion.visor.module.asset.define.config.AppHostConnectLogAutoClearConfig"
}
],
"properties": [
@@ -61,12 +66,22 @@
{
"name": "app.auto-clear.exec-log.enabled",
"type": "java.lang.Boolean",
"description": "开启 批量执行日志文件自动清理."
"description": "开启 批量执行日志自动清理."
},
{
"name": "app.auto-clear.exec-log.keep-period",
"type": "java.lang.Integer",
"description": "批量执行日志文件自动清理 保留周期 (天)."
"description": "批量执行日志自动清理 保留周期 (天)."
},
{
"name": "app.auto-clear.host-connect-log.enabled",
"type": "java.lang.Boolean",
"description": "开启 主机连接日志自动清理."
},
{
"name": "app.auto-clear.host-connect-log.keep-period",
"type": "java.lang.Integer",
"description": "主机连接日志自动清理 保留周期 (天)."
}
]
}