[新增][定时任务]重新申请 ApiAccessLog、ApiErrorLog、JobLog 3个日志的定时清理

This commit is contained in:
j-sentinel 2023-10-02 19:18:36 +08:00
parent fdb10aeced
commit 2f0483ce9f
32 changed files with 238 additions and 369 deletions

View File

@ -1,12 +1,9 @@
package cn.iocoder.yudao.framework.quartz.config;
import cn.iocoder.yudao.framework.quartz.core.job.JobLogJobHandler;
import cn.iocoder.yudao.framework.quartz.core.job.LogJobProperties;
import cn.iocoder.yudao.framework.quartz.core.scheduler.SchedulerManager;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Scheduler;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
@ -18,7 +15,6 @@ import java.util.Optional;
@AutoConfiguration
@EnableScheduling // 开启 Spring 自带的定时任务
@Slf4j
@EnableConfigurationProperties(LogJobProperties.class)
public class YudaoQuartzAutoConfiguration {
@Bean
@ -30,10 +26,4 @@ public class YudaoQuartzAutoConfiguration {
return new SchedulerManager(scheduler.get());
}
// TODO @j-sentinel这个 job先拿到 infra biz 里面实现哈
@Bean
public JobLogJobHandler jobLogJobHandler(LogJobProperties logJobProperties){
return new JobLogJobHandler(logJobProperties);
}
}

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.framework.quartz.core.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.quartz.core.service.JobLogFrameworkService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
// TODO @j-sentinel名字和项目里其它保持统一可以叫 JobLogCleanJob不用带 handler
/**
* // TODO @j-sentinel要写下类注释噢就是这个类要干啥然后下面两个应该是 @author @since
* @Author: j-sentinel
* @Date: 2023/9/30 20:40
*/
@Slf4j
@AllArgsConstructor
public class JobLogJobHandler implements JobHandler {
private LogJobProperties logJobProperties;
public JobLogJobHandler(LogJobProperties logJobProperties) {
this.logJobProperties = logJobProperties;
}
@Resource
private JobLogFrameworkService jobLogFrameworkService;
@Override
public String execute(String param) throws Exception {
Integer integer = jobLogFrameworkService.timingJobCleanLog(logJobProperties.getJobCleanRetainDay());
log.info("定时执行清理定时任务日志数量({})个",integer);
return String.format("定时执行清理定时任务日志数量 %s 个", integer);
}
}

View File

@ -1,21 +0,0 @@
package cn.iocoder.yudao.framework.quartz.core.job;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
// TODO @j-sentinel这个配置类先暂时不做每个 Job 里面定一个静态类其实不是所有的变量都需要配置化因为它本身基本也不会改动
/**
* @Author: j-sentinel
* @Date: 2023/9/30 16:17
*/
@Data
@ConfigurationProperties(prefix = "yudao.clean-job")
public class LogJobProperties {
private int accessRetainDay = 7;
private int errorRetainDay = 8;
private int jobCleanRetainDay = 7;
}

View File

@ -40,11 +40,4 @@ public interface JobLogFrameworkService {
@NotNull(message = "结束时间不能为空") LocalDateTime endTime,
@NotNull(message = "运行时长不能为空") Integer duration,
boolean success, String result);
/**
* 清理 @param jobCleanRetainDay 天的访问日志
*
* @param jobCleanRetainDay 超过多少天就进行清理
*/
Integer timingJobCleanLog(Integer jobCleanRetainDay);
}

View File

@ -61,12 +61,6 @@
<artifactId>jsoup</artifactId>
</dependency>
<!-- Job 定时任务相关 -->
<!-- TODO @j-sentinel去掉这个依赖哈 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-job</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -1,14 +1,11 @@
package cn.iocoder.yudao.framework.apilog.config;
import cn.iocoder.yudao.framework.apilog.core.filter.ApiAccessLogFilter;
import cn.iocoder.yudao.framework.apilog.core.job.ApiAccessLogJobHandler;
import cn.iocoder.yudao.framework.apilog.core.job.ApiErrorLogJobHandler;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkServiceImpl;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkServiceImpl;
import cn.iocoder.yudao.framework.common.enums.WebFilterOrderEnum;
import cn.iocoder.yudao.framework.quartz.core.job.LogJobProperties;
import cn.iocoder.yudao.framework.web.config.WebProperties;
import cn.iocoder.yudao.framework.web.config.YudaoWebAutoConfiguration;
import cn.iocoder.yudao.module.infra.api.logger.ApiAccessLogApi;
@ -34,16 +31,6 @@ public class YudaoApiLogAutoConfiguration {
return new ApiErrorLogFrameworkServiceImpl(apiErrorLogApi);
}
@Bean
public ApiAccessLogJobHandler apiAccessLogJobHandler(LogJobProperties logJobProperties) {
return new ApiAccessLogJobHandler(logJobProperties);
}
@Bean
public ApiErrorLogJobHandler apiErrorLogJobHandler(LogJobProperties logJobProperties) {
return new ApiErrorLogJobHandler(logJobProperties);
}
/**
* 创建 ApiAccessLogFilter Bean记录 API 请求日志
*/

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.framework.apilog.core.job;
import cn.iocoder.yudao.framework.apilog.core.service.ApiAccessLogFrameworkService;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.quartz.core.job.LogJobProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
// TODO @j-sentinel JobLogJobHandler
/**
* @Author: j-sentinel
* @Date: 2023/9/30 16:13
*/
@Slf4j
@AllArgsConstructor
public class ApiAccessLogJobHandler implements JobHandler {
private LogJobProperties logJobProperties;
public ApiAccessLogJobHandler(LogJobProperties logJobProperties) {
this.logJobProperties = logJobProperties;
}
@Resource
private ApiAccessLogFrameworkService apiAccessLogFrameworkService;
@Override
public String execute(String param) throws Exception {
apiAccessLogFrameworkService.jobCleanAccessLog(logJobProperties.getAccessRetainDay());
return "";
}
}

View File

@ -1,35 +0,0 @@
package cn.iocoder.yudao.framework.apilog.core.job;
import cn.iocoder.yudao.framework.apilog.core.service.ApiErrorLogFrameworkService;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.quartz.core.job.LogJobProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import javax.annotation.Resource;
// TODO @j-sentinel JobLogJobHandler
/**
* @Author: j-sentinel
* @Date: 2023/9/30 16:13
*/
@Slf4j
@AllArgsConstructor
public class ApiErrorLogJobHandler implements JobHandler {
private LogJobProperties logJobProperties;
public ApiErrorLogJobHandler(LogJobProperties logJobProperties) {
this.logJobProperties = logJobProperties;
}
@Resource
private ApiErrorLogFrameworkService apiErrorLogFrameworkService;
@Override
public String execute(String param) throws Exception {
apiErrorLogFrameworkService.jobCleanErrorLog(logJobProperties.getErrorRetainDay());
return "";
}
}

View File

@ -13,11 +13,4 @@ public interface ApiAccessLogFrameworkService {
* @param apiAccessLog API 访问日志
*/
void createApiAccessLog(ApiAccessLog apiAccessLog);
/**
* 清理 @param accessLogJobDay 天的访问日志
*
* @param accessLogJobDay 超过多少天就进行清理
*/
void jobCleanAccessLog(Integer accessLogJobDay);
}

View File

@ -25,9 +25,4 @@ public class ApiAccessLogFrameworkServiceImpl implements ApiAccessLogFrameworkSe
apiAccessLogApi.createApiAccessLog(reqDTO);
}
@Override
public void jobCleanAccessLog(Integer accessLogJobDay) {
apiAccessLogApi.jobCleanAccessLog(accessLogJobDay);
}
}

View File

@ -13,11 +13,4 @@ public interface ApiErrorLogFrameworkService {
* @param apiErrorLog API 错误日志
*/
void createApiErrorLog(ApiErrorLog apiErrorLog);
/**
* 清理 @param errorLogJobDay 天的访问日志
*
* @param errorLogJobDay 超过多少天就进行清理
*/
void jobCleanErrorLog(Integer errorLogJobDay);
}

View File

@ -25,9 +25,4 @@ public class ApiErrorLogFrameworkServiceImpl implements ApiErrorLogFrameworkServ
apiErrorLogApi.createApiErrorLog(reqDTO);
}
@Override
public void jobCleanErrorLog(Integer errorLogJobDay) {
apiErrorLogApi.jobCleanErrorLog(errorLogJobDay);
}
}

View File

@ -18,12 +18,4 @@ public interface ApiAccessLogApi {
*/
void createApiAccessLog(@Valid ApiAccessLogCreateReqDTO createDTO);
// TODO @j-sentinel这个我们先提供接口在 API而是 infra 模块自己清理先哈
/**
* 清理 @param accessLogJobDay 天的访问日志
*
* @param accessLogJobDay 超过多少天就进行清理
*/
void jobCleanAccessLog(Integer accessLogJobDay);
}

View File

@ -18,12 +18,4 @@ public interface ApiErrorLogApi {
*/
void createApiErrorLog(@Valid ApiErrorLogCreateReqDTO createDTO);
// TODO @j-sentinel这个我们先提供接口在 API而是 infra 模块自己清理先哈
/**
* 清理 @param errorLogJobDay 天的访问日志
*
* @param errorLogJobDay 超过多少天就进行清理
*/
void jobCleanErrorLog(Integer errorLogJobDay);
}

View File

@ -24,9 +24,4 @@ public class ApiAccessLogApiImpl implements ApiAccessLogApi {
apiAccessLogService.createApiAccessLog(createDTO);
}
@Override
public void jobCleanAccessLog(Integer accessLogJobDay) {
apiAccessLogService.jobCleanAccessLog(accessLogJobDay);
}
}

View File

@ -24,9 +24,4 @@ public class ApiErrorLogApiImpl implements ApiErrorLogApi {
apiErrorLogService.createApiErrorLog(createDTO);
}
@Override
public void jobCleanErrorLog(Integer errorLogJobDay) {
apiErrorLogService.jobCleanErrorLog(errorLogJobDay);
}
}

View File

@ -6,9 +6,12 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.Date;
import java.util.List;
/**
@ -41,12 +44,19 @@ public interface JobLogMapper extends BaseMapperX<JobLogDO> {
);
}
// TODO @j-sentinel一般来说我们 mapper 只提供 crud 的操作所以这个方法的命名建议是 deleteByCreateTimeLt
// 然后参数是 (crateTime, count) service 传入
// 这里为什么有 lt 这个其实是延续 spring data method 描述的命名习惯lt 表示小于
// 另外timingJobCleanLog 的具体 sql 这么写性能是比较差的可以直接 delete * from job_log where create_time < xxx order by id limit 100;
Integer timingJobCleanLog(@Param("jobCleanRetainDay") Integer jobCleanRetainDay);
// TODO @j-serntineloptimize table infra_job_log 就可以啦
/**
* 目前物理删除只能通过mybatis-plus的注解实现 or mybatis的xml实现
* 如果写xml的话就需要多写一个映射类
*
* @param jobCleanRetainDay 时间限制
* @param deleteLimit 删除次数的限制
* @return
*/
@Delete("DELETE FROM infra_job_log WHERE create_time < #{jobCleanRetainDay} LIMIT #{deleteLimit}")
Integer deleteByCreateTimeLt(@Param("jobCleanRetainDay") Date jobCleanRetainDay,@Param("deleteLimit")Integer deleteLimit);
@Update("ALTER TABLE infra_job_log FORCE")
void optimizeTable();
}

View File

@ -6,9 +6,12 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apiaccesslog.ApiAccessLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiAccessLogDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.Date;
import java.util.List;
/**
@ -45,8 +48,17 @@ public interface ApiAccessLogMapper extends BaseMapperX<ApiAccessLogDO> {
);
}
// TODO @j-sentinel JobLogMapper 的一些优化点
Integer jobCleanAccessLog(@Param("accessLogJobDay") Integer accessLogJobDay);
/**
* 目前物理删除只能通过mybatis-plus的注解实现 or mybatis的xml实现
* 如果写xml的话就需要多写一个映射类
*
* @param accessLogExceedDay 时间限制
* @param deleteLimit 删除次数的限制
* @return
*/
@Delete("DELETE FROM infra_api_access_log WHERE create_time < #{accessLogExceedDay} LIMIT #{deleteLimit}")
Integer deleteByCreateTimeLt(@Param("accessLogExceedDay") Date accessLogExceedDay,@Param("deleteLimit")Integer deleteLimit);
@Update("ALTER TABLE infra_api_access_log FORCE")
void optimizeTable();
}

View File

@ -6,9 +6,12 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.logger.vo.apierrorlog.ApiErrorLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.logger.ApiErrorLogDO;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import java.util.Date;
import java.util.List;
/**
@ -43,8 +46,17 @@ public interface ApiErrorLogMapper extends BaseMapperX<ApiErrorLogDO> {
);
}
// TODO @j-sentinel JobLogMapper 的一些优化点
Integer jobCleanErrorLog(@Param("errorLogJobDay") Integer errorLogJobDay);
/**
* 目前物理删除只能通过mybatis-plus的注解实现 or mybatis的xml实现
* 如果写xml的话就需要多写一个映射类
*
* @param errorLogExceedDay 时间限制
* @param deleteLimit 删除次数的限制
* @return
*/
@Delete("DELETE FROM infra_api_error_log WHERE create_time < #{errorLogExceedDay} LIMIT #{deleteLimit}")
Integer deleteByCreateTimeLt(@Param("errorLogExceedDay") Date errorLogExceedDay,@Param("deleteLimit")Integer deleteLimit);
@Update("ALTER TABLE infra_api_error_log FORCE")
void optimizeTable();
}

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.infra.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 定时 物理 删除访问日志的 Job
*
* @author: j-sentinel
*/
@Slf4j
@Component
public class AccessLogCleanRecordJob implements JobHandler {
@Resource
private ApiAccessLogService apiAccessLogService;
/**
* 清理超过7天的日志
*/
private static final Integer JOB_CLEAN_RETAIN_DAY = 7;
/**
* 每次删除间隔的条数如果值太高可能会造成数据库的宕机
*/
private static final Integer DELETE_LIMIT = 100;
@Override
@TenantIgnore
public String execute(String param) throws Exception {
Integer integer = apiAccessLogService.jobCleanAccessLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
log.info("定时执行清理访问日志数量({})个", integer);
return String.format("定时执行清理错误日志数量 %s 个", integer);
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.yudao.module.infra.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.infra.service.logger.ApiAccessLogService;
import cn.iocoder.yudao.module.infra.service.logger.ApiErrorLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 定时 物理 删除错误日志的 Job
*
* @author: j-sentinel
*/
@Slf4j
@Component
public class ErrorLogCleanRecordJob implements JobHandler {
@Resource
private ApiErrorLogService apiErrorLogService;
/**
* 清理超过7天的日志
*/
private static final Integer JOB_CLEAN_RETAIN_DAY = 7;
/**
* 每次删除间隔的条数如果值太高可能会造成数据库的宕机
*/
private static final Integer DELETE_LIMIT = 100;
@Override
@TenantIgnore
public String execute(String param) throws Exception {
Integer integer = apiErrorLogService.jobCleanErrorLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
log.info("定时执行清理错误日志数量({})个",integer);
return String.format("定时执行清理错误日志数量 %s 个", integer);
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.infra.job;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.infra.service.job.JobLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 定时 物理 删除任务日志的 Job
*
* @author: j-sentinel
*/
@Slf4j
@Component
public class JobCleanRecordJob implements JobHandler {
@Resource
private JobLogService jobLogService;
/**
* 清理超过14天的日志
*/
private static final Integer JOB_CLEAN_RETAIN_DAY = 14;
/**
* 每次删除间隔的条数如果值太高可能会造成数据库的宕机
*/
private static final Integer DELETE_LIMIT = 100;
@Override
@TenantIgnore
public String execute(String param) throws Exception {
Integer integer = jobLogService.timingJobCleanLog(JOB_CLEAN_RETAIN_DAY,DELETE_LIMIT);
log.info("定时执行清理定时任务日志数量({})个",integer);
return String.format("定时执行清理定时任务日志数量 %s 个", integer);
}
}

View File

@ -48,4 +48,11 @@ public interface JobLogService extends JobLogFrameworkService {
*/
List<JobLogDO> getJobLogList(JobLogExportReqVO exportReqVO);
/**
* 清理 @param jobCleanRetainDay 天的访问日志
*
* @param jobLogExceedDay 超过多少天就进行清理
* @param deleteLimit 清理的间隔条数
*/
Integer timingJobCleanLog(Integer jobLogExceedDay,Integer deleteLimit);
}

View File

@ -1,6 +1,8 @@
package cn.iocoder.yudao.module.infra.service.job;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogExportReqVO;
import cn.iocoder.yudao.module.infra.controller.admin.job.vo.log.JobLogPageReqVO;
import cn.iocoder.yudao.module.infra.dal.dataobject.job.JobLogDO;
@ -14,6 +16,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
@ -26,8 +29,6 @@ import java.util.List;
@Slf4j
public class JobLogServiceImpl implements JobLogService {
private static final Integer DELETE_LIMIT = 1;
@Resource
private JobLogMapper jobLogMapper;
@ -52,20 +53,25 @@ public class JobLogServiceImpl implements JobLogService {
}
}
// TODO @j-sentinel这个 job也可以忽略租户哈可以直接使用 @TenantIgnore 注解
@Override
public Integer timingJobCleanLog(Integer jobCleanRetainDay) {
Integer result = null;
public Integer timingJobCleanLog(Integer jobLogExceedDay,Integer deleteLimit) {
Integer result;
int count = 0;
// TODO @j-sentinel一般我们在写逻辑时尽量避免用 while true 这种死循环而是 for (int i = 0; i < Short.MAX) 类似这种避免里面真的发生一些意外的情况无限执行
// 然后 for 里面可以有个 if count < 100 未到达删除的预期条数说明已经到底可以 break
while (result == null || DELETE_LIMIT.equals(result)){
result = jobLogMapper.timingJobCleanLog(jobCleanRetainDay);
Date currentDate = DateUtil.date();
// 计算过期日期正数向未来偏移负数向历史偏移
Date expireDate = DateUtil.offsetDay(currentDate, -jobLogExceedDay);
for (int i = 0; i < Short.MAX_VALUE; i++) {
result = jobLogMapper.deleteByCreateTimeLt(expireDate,deleteLimit);
count += result;
if (result < deleteLimit) {
// 达到删除预期条数
break;
}
}
if(count > 0){
// ALTER TABLE...FORCE 会导致表重建发生,这会根据主键索引对表空间中的物理页进行排序
// 它将行压缩到页面上并消除可用空间同时确保数据处于主键查找的最佳顺序
// 优化表语句官方文档https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html
jobLogMapper.optimizeTable();
}
return count;
@ -91,5 +97,4 @@ public class JobLogServiceImpl implements JobLogService {
return jobLogMapper.selectList(exportReqVO);
}
// TODO @小吉祥每天 0 点的时候清理超过 14 天的日志
}

View File

@ -41,7 +41,8 @@ public interface ApiAccessLogService {
/**
* 清理 @param accessLogJobDay 天的访问日志
*
* @param accessLogJobDay 超过多少天就进行清理
* @param accessLogExceedDay 超过多少天就进行清理
* @param deleteLimit 清理的间隔条数
*/
void jobCleanAccessLog(Integer accessLogJobDay);
Integer jobCleanAccessLog(Integer accessLogExceedDay,Integer deleteLimit);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiAccessLogCreateReqDTO;
@ -13,6 +14,7 @@ import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
/**
@ -25,8 +27,6 @@ import java.util.List;
@Validated
public class ApiAccessLogServiceImpl implements ApiAccessLogService {
private static final Integer DELETE_LIMIT = 100;
@Resource
private ApiAccessLogMapper apiAccessLogMapper;
@ -47,22 +47,27 @@ public class ApiAccessLogServiceImpl implements ApiAccessLogService {
}
@Override
// TODO j-sentinel类似 JobLogServiceImpl 的建议
public void jobCleanAccessLog(Integer accessLogJobDay) {
TenantUtils.executeIgnore(() -> {
Integer result = null;
int count = 0;
while (result == null || DELETE_LIMIT.equals(result)) {
result = apiAccessLogMapper.jobCleanAccessLog(accessLogJobDay);
count += result;
public Integer jobCleanAccessLog(Integer accessLogExceedDay,Integer deleteLimit) {
Integer result;
int count = 0;
Date currentDate = DateUtil.date();
// 计算过期日期正数向未来偏移负数向历史偏移
Date expireDate = DateUtil.offsetDay(currentDate, -accessLogExceedDay);
for (int i = 0; i < Short.MAX_VALUE; i++) {
result = apiAccessLogMapper.deleteByCreateTimeLt(expireDate,deleteLimit);
count += result;
if (result < deleteLimit) {
// 达到删除预期条数
break;
}
if (count > 0) {
// ALTER TABLE...FORCE 会导致表重建发生,这会根据主键索引对表空间中的物理页进行排序
// 它将行压缩到页面上并消除可用空间同时确保数据处于主键查找的最佳顺序
apiAccessLogMapper.optimizeTable();
}
log.info("定时执行清理访问日志数量({})个", count);
});
}
if(count > 0){
// ALTER TABLE...FORCE 会导致表重建发生,这会根据主键索引对表空间中的物理页进行排序
// 它将行压缩到页面上并消除可用空间同时确保数据处于主键查找的最佳顺序
// 优化表语句官方文档https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html
apiAccessLogMapper.optimizeTable();
}
return count;
}
}

View File

@ -50,7 +50,8 @@ public interface ApiErrorLogService {
/**
* 清理 @param errorLogJobDay 天的访问日志
*
* @param errorLogJobDay 超过多少天就进行清理
* @param errorLogExceedDay 超过多少天就进行清理
* @param deleteLimit 清理的间隔条数
*/
void jobCleanErrorLog(Integer errorLogJobDay);
Integer jobCleanErrorLog(Integer errorLogExceedDay,Integer deleteLimit);
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.infra.service.logger;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.infra.api.logger.dto.ApiErrorLogCreateReqDTO;
@ -15,6 +16,7 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -31,8 +33,6 @@ import static cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants.API_ERROR_L
@Validated
public class ApiErrorLogServiceImpl implements ApiErrorLogService {
private static final Integer DELETE_LIMIT = 100;
@Resource
private ApiErrorLogMapper apiErrorLogMapper;
@ -68,22 +68,27 @@ public class ApiErrorLogServiceImpl implements ApiErrorLogService {
}
@Override
// TODO j-sentinel类似 JobLogServiceImpl 的建议
public void jobCleanErrorLog(Integer errorLogJobDay) {
TenantUtils.executeIgnore(() -> {
Integer result = null;
int count = 0;
while (result == null || DELETE_LIMIT.equals(result)) {
result = apiErrorLogMapper.jobCleanErrorLog(errorLogJobDay);
count += result;
public Integer jobCleanErrorLog(Integer errorLogExceedDay,Integer deleteLimit) {
Integer result;
int count = 0;
Date currentDate = DateUtil.date();
// 计算过期日期正数向未来偏移负数向历史偏移
Date expireDate = DateUtil.offsetDay(currentDate, -errorLogExceedDay);
for (int i = 0; i < Short.MAX_VALUE; i++) {
result = apiErrorLogMapper.deleteByCreateTimeLt(expireDate,deleteLimit);
count += result;
if (result < deleteLimit) {
// 达到删除预期条数
break;
}
if (count > 0) {
// ALTER TABLE...FORCE 会导致表重建发生,这会根据主键索引对表空间中的物理页进行排序
// 它将行压缩到页面上并消除可用空间同时确保数据处于主键查找的最佳顺序
apiErrorLogMapper.optimizeTable();
}
log.info("定时执行清理错误日志数量({})个",count);
});
}
if(count > 0){
// ALTER TABLE...FORCE 会导致表重建发生,这会根据主键索引对表空间中的物理页进行排序
// 它将行压缩到页面上并消除可用空间同时确保数据处于主键查找的最佳顺序
// 优化表语句官方文档https://dev.mysql.com/doc/refman/8.0/en/optimize-table.html
apiErrorLogMapper.optimizeTable();
}
return count;
}
}

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiAccessLogMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<delete id="jobCleanAccessLog" parameterType="integer">
DELETE FROM infra_api_access_log
WHERE id IN (
SELECT * FROM (
SELECT id FROM infra_api_access_log
WHERE create_time &lt; DATE_SUB(CURDATE(), INTERVAL #{accessLogJobDay} DAY)
ORDER BY id ASC LIMIT 100
) AS a
)
</delete>
<select id="optimizeTable">
ALTER TABLE infra_job_log FORCE
/*
ALTER TABLE infra_job_log ENGINE = INNODB,
ALGORITHM = INPLACE,
LOCK = NONE
*/
</select>
</mapper>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.logger.ApiErrorLogMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<delete id="jobCleanErrorLog" parameterType="integer">
DELETE FROM infra_api_error_log
WHERE id IN (
SELECT * FROM (
SELECT id FROM infra_api_error_log
WHERE create_time &lt; DATE_SUB(CURDATE(), INTERVAL #{errorLogJobDay} DAY)
ORDER BY id ASC LIMIT 100
) AS a
)
</delete>
<select id="optimizeTable">
ALTER TABLE infra_api_error_log FORCE
/*
ALTER TABLE infra_api_error_log ENGINE = INNODB,
ALGORITHM = INPLACE,
LOCK = NONE
*/
</select>
</mapper>

View File

@ -1,32 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.infra.dal.mysql.job.JobLogMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
<delete id="timingJobCleanLog" parameterType="integer">
DELETE FROM infra_job_log
WHERE id IN (
SELECT * FROM (
SELECT id FROM infra_job_log
WHERE create_time &lt; DATE_SUB(CURDATE(), INTERVAL #{jobCleanRetainDay} DAY)
ORDER BY id ASC LIMIT 100
) AS a
)
</delete>
<select id="optimizeTable">
ALTER TABLE infra_job_log FORCE
/*
ALTER TABLE infra_job_log ENGINE = INNODB,
ALGORITHM = INPLACE,
LOCK = NONE
*/
</select>
</mapper>

View File

@ -213,10 +213,6 @@ yudao:
error-code: # 错误码相关配置项
enable: false
demo: false # 关闭演示模式
clean-job:
access-retain-day: 7
error-retain-day: 8
job-clean-retain-day: 8
justauth:
enabled: true