diff --git a/doc/XXL-JOB官方文档.md b/doc/XXL-JOB官方文档.md index 967bfffe..cf03f3eb 100644 --- a/doc/XXL-JOB官方文档.md +++ b/doc/XXL-JOB官方文档.md @@ -1112,6 +1112,7 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段 - 28、新增"任务ID"属性,移除"JobKey"属性,前者承担所有功能,方便后续增强任务依赖功能。 - 29、任务循环依赖问题修复,避免子任务与父任务重复导致的调度死循环; - 30、任务列表新增筛选条件 "任务描述",快速检索任务; +- 31、执行器新增配置项("xxl.job.executor.logretentiondays"):日志保存天数,执行器自动删除过期日志文件。限制配置最少保存3天,否则功能无效。 ### TODO LIST - 1、任务权限管理:执行器为粒度分配权限,核心操作校验权限; diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java b/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java index f58853c1..dcc96b7e 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/executor/XxlJobExecutor.java @@ -8,6 +8,7 @@ import com.xxl.job.core.handler.annotation.JobHandler; import com.xxl.job.core.log.XxlJobFileAppender; import com.xxl.job.core.rpc.netcom.NetComClientProxy; import com.xxl.job.core.rpc.netcom.NetComServerFactory; +import com.xxl.job.core.thread.JobLogFileCleanThread; import com.xxl.job.core.thread.JobThread; import com.xxl.job.core.util.NetUtil; import org.slf4j.Logger; @@ -34,6 +35,7 @@ public class XxlJobExecutor implements ApplicationContextAware { private String adminAddresses; private String accessToken; private String logPath; + private int logRetentionDays; public void setIp(String ip) { this.ip = ip; @@ -53,7 +55,9 @@ public class XxlJobExecutor implements ApplicationContextAware { public void setLogPath(String logPath) { this.logPath = logPath; } - + public void setLogRetentionDays(int logRetentionDays) { + this.logRetentionDays = logRetentionDays; + } // ---------------------- applicationContext ---------------------- private static ApplicationContext applicationContext; @@ -79,6 +83,9 @@ public class XxlJobExecutor implements ApplicationContextAware { // init executor-server initExecutorServer(port, ip, appName, accessToken); + + // init JobLogFileCleanThread + JobLogFileCleanThread.getInstance().start(logRetentionDays); } public void destroy(){ // destory JobThreadRepository @@ -91,6 +98,9 @@ public class XxlJobExecutor implements ApplicationContextAware { // destory executor-server stopExecutorServer(); + + // destory JobLogFileCleanThread + JobLogFileCleanThread.getInstance().toStop(); } diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java index 038eec44..ffa453c6 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/handler/impl/ScriptJobHandler.java @@ -40,8 +40,8 @@ public class ScriptJobHandler extends IJobHandler { String cmd = glueType.getCmd(); // make script file - String scriptFileName = XxlJobFileAppender.getLogPath() - .concat("/gluesource/") + String scriptFileName = XxlJobFileAppender.getGlueSrcPath() + .concat("/") .concat(String.valueOf(jobId)) .concat("_") .concat(String.valueOf(glueUpdatetime)) diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java index 0e9dcc23..b2c628a1 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/log/XxlJobFileAppender.java @@ -20,8 +20,21 @@ public class XxlJobFileAppender { public static final InheritableThreadLocal contextHolder = new InheritableThreadLocal(); - // log base path + /** + * log base path + * + * strut like: + * ---/ + * ---/gluesource/ + * ---/gluesource/10_1514171108000.js + * ---/gluesource/10_1514171108000.js + * ---/2017-12-25/ + * ---/2017-12-25/639.log + * ---/2017-12-25/821.log + * + */ private static String logBasePath = "/data/applogs/xxl-job/jobhandler"; + private static String glueSrcPath = logBasePath.concat("/gluesource"); public static void initLogPath(String logPath){ // init if (logPath!=null && logPath.trim().length()>0) { @@ -39,11 +52,14 @@ public class XxlJobFileAppender { if (!glueBaseDir.exists()) { glueBaseDir.mkdirs(); } + glueSrcPath = glueBaseDir.getPath(); } public static String getLogPath() { return logBasePath; } - + public static String getGlueSrcPath() { + return glueSrcPath; + } /** * log filename, like "logPath/yyyy-MM-dd/9999.log" diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java b/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java new file mode 100644 index 00000000..bae732b2 --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/thread/JobLogFileCleanThread.java @@ -0,0 +1,118 @@ +package com.xxl.job.core.thread; + +import com.xxl.job.core.log.XxlJobFileAppender; +import com.xxl.job.core.util.FileUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +/** + * job file clean thread + * + * @author xuxueli 2017-12-29 16:23:43 + */ +public class JobLogFileCleanThread extends Thread { + private static Logger logger = LoggerFactory.getLogger(JobLogFileCleanThread.class); + + private static JobLogFileCleanThread instance = new JobLogFileCleanThread(); + public static JobLogFileCleanThread getInstance(){ + return instance; + } + + private Thread localThread; + private volatile boolean toStop = false; + public void start(final long logRetentionDays){ + + // limit min value + if (logRetentionDays < 3 ) { + return; + } + + localThread = new Thread(new Runnable() { + @Override + public void run() { + while (!toStop) { + try { + // clean log dir, over logRetentionDays + File[] childDirs = new File(XxlJobFileAppender.getLogPath()).listFiles(); + if (childDirs!=null && childDirs.length>0) { + + // today + Calendar todayCal = Calendar.getInstance(); + todayCal.set(Calendar.HOUR_OF_DAY,0); + todayCal.set(Calendar.MINUTE,0); + todayCal.set(Calendar.SECOND,0); + todayCal.set(Calendar.MILLISECOND,0); + + Date todayDate = todayCal.getTime(); + + for (File childFile: childDirs) { + + // valid + if (!childFile.isDirectory()) { + continue; + } + if (childFile.getName().indexOf("-") == -1) { + continue; + } + + // file create date + Date logFileCreateDate = null; + try { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd"); + logFileCreateDate = simpleDateFormat.parse(childFile.getName()); + } catch (ParseException e) { + logger.error(e.getMessage(), e); + } + if (logFileCreateDate == null) { + continue; + } + + if ((todayDate.getTime()-logFileCreateDate.getTime()) >= logRetentionDays * (24 * 60 * 60 * 1000) ) { + FileUtil.deleteRecursively(childFile); + } + + } + } + + } catch (Exception e) { + logger.error(e.getMessage(), e); + } + + try { + TimeUnit.DAYS.sleep(1); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + logger.info(">>>>>>>>>>> xxl-job, executor JobLogFileCleanThread thread destory."); + + } + }); + localThread.setDaemon(true); + localThread.start(); + } + + public void toStop() { + toStop = true; + + if (localThread == null) { + return; + } + + // interrupt and wait + localThread.interrupt(); + try { + localThread.join(); + } catch (InterruptedException e) { + logger.error(e.getMessage(), e); + } + } + +} diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/util/FileUtil.java b/xxl-job-core/src/main/java/com/xxl/job/core/util/FileUtil.java new file mode 100644 index 00000000..e68cdcde --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/util/FileUtil.java @@ -0,0 +1,27 @@ +package com.xxl.job.core.util; + +import java.io.File; + +/** + * file tool + * + * @author xuxueli 2017-12-29 17:56:48 + */ +public class FileUtil { + + public static boolean deleteRecursively(File root) { + if (root != null && root.exists()) { + if (root.isDirectory()) { + File[] children = root.listFiles(); + if (children != null) { + for (File child : children) { + deleteRecursively(child); + } + } + } + return root.delete(); + } + return false; + } + +} diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml index e11e623d..41bf2351 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/applicationcontext-xxl-job.xml @@ -31,10 +31,12 @@ - - + + + + diff --git a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties index d8b57728..c30e613c 100644 --- a/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties +++ b/xxl-job-executor-samples/xxl-job-executor-sample-spring/src/main/resources/xxl-job-executor.properties @@ -6,8 +6,11 @@ xxl.job.executor.appname=xxl-job-executor-sample xxl.job.executor.ip= xxl.job.executor.port=9999 +### xxl-job, access token +xxl.job.accessToken= + ### xxl-job log path xxl.job.executor.logpath=/data/applogs/xxl-job/jobhandler +### xxl-job log retention days +xxl.job.executor.logretentiondays=-1 -### xxl-job, access token -xxl.job.accessToken= \ No newline at end of file