提交 00cd63c4 authored 作者: xueli.xue's avatar xueli.xue

日志清理功能

上级 882d7a43
......@@ -813,15 +813,15 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
- 3、执行器,server启动、销毁和注册逻辑调整;
- 4、JettyServer关闭逻辑优化,修复执行器无法正常关闭导致端口占用和频繁打印c3p0日志的问题;
- 5、JobHandler中开启子线程时,支持子线程输出执行日志并通过Rolling查看。
- 6、任务日志清理功能;
#### TODO LIST
- 1、任务并行触发处理规则:单机串行队列(默认)、单机并行、串行忽略、单机覆盖;
- 2、任务权限管理;
- 3、调度失败重试机制;
- 4、执行器与数据库解耦,只需配置调度中心集群地址即可(与当前通过JDBC注册自动发现方式,相冲突,待考虑);
- 5、任务日志定期清理功能,支持设置日志上限;
- 6、任务分片:一个任务被拆分成N个独立的任务单元,然后由分布式部署的执行器分别执行某一个或几个分片单元;
- 7、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;
- 5、任务分片:一个任务被拆分成N个独立的任务单元,然后由分布式部署的执行器分别执行某一个或几个分片单元;
- 6、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;
## 七、其他
......
......@@ -167,4 +167,37 @@ public class JobLogController {
return new ReturnT<String>(500, runResult.getMsg());
}
}
@RequestMapping("/clearLog")
@ResponseBody
public ReturnT<String> clearLog(int jobGroup, int jobId, int type){
Date clearBeforeTime = null;
int clearBeforeNum = 0;
if (type == 1) {
clearBeforeTime = DateUtils.addMonths(new Date(), -1); // 清理一个月之前日志数据
} else if (type == 2) {
clearBeforeTime = DateUtils.addMonths(new Date(), -3); // 清理三个月之前日志数据
} else if (type == 3) {
clearBeforeTime = DateUtils.addMonths(new Date(), -6); // 清理六个月之前日志数据
} else if (type == 4) {
clearBeforeTime = DateUtils.addYears(new Date(), -1); // 清理一年之前日志数据
} else if (type == 5) {
clearBeforeNum = 1000; // 清理一千条以前日志数据
} else if (type == 6) {
clearBeforeNum = 10000; // 清理一万条以前日志数据
} else if (type == 7) {
clearBeforeNum = 30000; // 清理三万条以前日志数据
} else if (type == 8) {
clearBeforeNum = 100000; // 清理十万条以前日志数据
} else if (type == 9) {
clearBeforeNum = 0; // 清理所用日志数据
} else {
return new ReturnT<String>(ReturnT.FAIL_CODE, "清理类型参数异常");
}
xxlJobLogDao.clearLog(jobGroup, jobId, clearBeforeTime, clearBeforeNum);
return ReturnT.SUCCESS;
}
}
......@@ -29,4 +29,6 @@ public interface IXxlJobLogDao {
public List<Map<String, Object>> triggerCountByDay(Date from, Date to, int handleCode);
public int clearLog(int jobGroup, int jobId, Date clearBeforeTime, int clearBeforeNum);
}
......@@ -92,4 +92,14 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
return sqlSessionTemplate.selectList("XxlJobLogMapper.triggerCountByDay", params);
}
@Override
public int clearLog(int jobGroup, int jobId, Date clearBeforeTime, int clearBeforeNum) {
Map<String, Object> params = new HashMap<String, Object>();
params.put("jobGroup", jobGroup);
params.put("jobId", jobId);
params.put("clearBeforeTime", clearBeforeTime);
params.put("clearBeforeNum", clearBeforeNum);
return sqlSessionTemplate.delete("XxlJobLogMapper.clearLog", params);
}
}
......@@ -147,5 +147,37 @@
</if>
GROUP BY triggerDay;
</select>
<delete id="clearLog" parameterType="java.util.Map" >
delete from XXL_JOB_QRTZ_TRIGGER_LOG
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="jobGroup gt 0">
AND job_group = #{jobGroup}
</if>
<if test="jobId gt 0">
AND job_id = #{jobId}
</if>
<if test="clearBeforeTime != null">
AND trigger_time <![CDATA[ <= ]]> #{clearBeforeTime}
</if>
<if test="clearBeforeNum gt 0">
AND id NOT in(
SELECT id FROM(
SELECT id FROM XXL_JOB_QRTZ_TRIGGER_LOG AS t
<trim prefix="WHERE" prefixOverrides="AND | OR" >
<if test="jobGroup gt 0">
AND t.job_group = #{jobGroup}
</if>
<if test="jobId gt 0">
AND t.job_id = #{jobId}
</if>
</trim>
ORDER BY t.trigger_time desc
LIMIT 0, #{clearBeforeNum}
) t1
)
</if>
</trim>
</delete>
</mapper>
\ No newline at end of file
......@@ -45,6 +45,9 @@
<#-- jquery cookie -->
<script src="${request.contextPath}/static/plugins/jquery/jquery.cookie.js"></script>
<#-- layer -->
<script src="${request.contextPath}/static/plugins/layer/layer.js"></script>
<#-- common -->
<script src="${request.contextPath}/static/js/xxl.alert.1.js"></script>
<script src="${request.contextPath}/static/js/common.1.js"></script>
......
......@@ -36,7 +36,7 @@
<div class="input-group">
<span class="input-group-addon">执行器</span>
<select class="form-control" id="jobGroup" paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
<option value="0" >请选择</option>
<option value="0" >全部</option>
<#list JobGroupList as group>
<option value="${group.id}" >${group.title}</option>
</#list>
......@@ -47,7 +47,7 @@
<div class="input-group">
<span class="input-group-addon">任务</span>
<select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>" >
<option value="0" >请选择</option>
<option value="0" >全部</option>
</select>
</div>
</div>
......@@ -59,10 +59,13 @@
<input type="text" class="form-control" id="filterTime" readonly >
</div>
</div>
<div class="col-xs-2">
<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
<div class="col-xs-1">
<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
</div>
<div class="col-xs-1">
<button class="btn btn-block btn-nomal" id="clearLog">清理</button>
</div>
</div>
......@@ -102,6 +105,61 @@
<@netCommon.commonFooter />
</div>
<!-- 日志清理.模态框 -->
<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title" >日志清理</h4>
</div>
<div class="modal-body">
<form class="form-horizontal form" role="form" >
<div class="form-group">
<label class="col-sm-3 control-label"">执行器:</label>
<div class="col-sm-9">
<input type="text" class="form-control jobGroupText" readonly >
<input type="hidden" name="jobGroup" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"">任务:</label>
<div class="col-sm-9">
<input type="text" class="form-control jobIdText" readonly >
<input type="hidden" name="jobId" >
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label"">清理类型:</label>
<div class="col-sm-9">
<select class="form-control" name="type" >
<option value="1" >清理一个月之前日志数据</option>
<option value="2" >清理三个月之前日志数据</option>
<option value="3" >清理六个月之前日志数据</option>
<option value="4" >清理一年之前日志数据</option>
<option value="5" >清理一千条以前日志数据</option>
<option value="6" >清理一万条以前日志数据</option>
<option value="7" >清理三万条以前日志数据</option>
<option value="8" >清理十万条以前日志数据</option>
<option value="9" >清理所用日志数据</option>
</select>
</div>
</div>
<hr>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6">
<button type="button" class="btn btn-primary ok" >保存</button>
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<@netCommon.commonScript />
<!-- DataTables -->
<script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>
......
......@@ -11,7 +11,7 @@ $(function() {
dataType : "json",
success : function(data){
if (data.code == 200) {
$("#jobId").html('<option value="0" >请选择</option>');
$("#jobId").html('<option value="0" >全部</option>');
$.each(data.content, function (n, value) {
$("#jobId").append('<option value="' + value.id + '" >' + value.jobDesc + '</option>');
});
......@@ -153,7 +153,7 @@ $(function() {
if (row.triggerCode == 200){
var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">执行日志</a>';
if(row.handleCode == 0){
temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'">终止任务</a>';
temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >终止任务</a>';
}
return temp;
}
......@@ -228,7 +228,10 @@ $(function() {
});
*/
});
/**
* 终止任务
*/
$('#joblog_list').on('click', '.logKill', function(){
var _id = $(this).attr('_id');
ComConfirm.show("确认主动终止任务?", function(){
......@@ -248,5 +251,50 @@ $(function() {
});
});
});
/**
* 清理任务Log
*/
$('#clearLog').on('click', function(){
var jobGroup = $('#jobGroup').val();
var jobId = $('#jobId').val();
var jobGroupText = $("#jobGroup").find("option:selected").text();
var jobIdText = $("#jobId").find("option:selected").text();
$('#clearLogModal input[name=jobGroup]').val(jobGroup);
$('#clearLogModal input[name=jobId]').val(jobId);
$('#clearLogModal .jobGroupText').val(jobGroupText);
$('#clearLogModal .jobIdText').val(jobIdText);
$('#clearLogModal').modal('show');
});
$("#clearLogModal .ok").on('click', function(){
$.post(base_url + "/joblog/clearLog", $("#clearLogModal .form").serialize(), function(data, status) {
if (data.code == "200") {
$('#clearLogModal').modal('hide');
layer.open({
title: '系统提示',
content: '日志清理成功',
icon: '1',
end: function(layero, index){
logTable.fnDraw();
}
});
} else {
layer.open({
title: '系统提示',
content: (data.msg || "日志清理失败"),
icon: '2'
});
}
});
});
$("#clearLogModal").on('hide.bs.modal', function () {
$("#clearLogModal .form")[0].reset();
});
});
/*! layer mobile-v2.0.0 Web弹层组件 MIT License http://layer.layui.com/mobile By 贤心 */
;!function(e){"use strict";var t=document,n="querySelectorAll",i="getElementsByClassName",a=function(e){return t[n](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var n in e)t[n]=e[n];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var r=0,o=["layui-m-layer"],c=function(e){var t=this;t.config=l.extend(e),t.view()};c.prototype.view=function(){var e=this,n=e.config,s=t.createElement("div");e.id=s.id=o[0]+r,s.setAttribute("class",o[0]+" "+o[0]+(n.type||0)),s.setAttribute("index",r);var l=function(){var e="object"==typeof n.title;return n.title?'<h3 style="'+(e?n.title[1]:"")+'">'+(e?n.title[0]:n.title)+"</h3>":""}(),c=function(){"string"==typeof n.btn&&(n.btn=[n.btn]);var e,t=(n.btn||[]).length;return 0!==t&&n.btn?(e='<span yes type="1">'+n.btn[0]+"</span>",2===t&&(e='<span no type="0">'+n.btn[1]+"</span>"+e),'<div class="layui-m-layerbtn">'+e+"</div>"):""}();if(n.fixed||(n.top=n.hasOwnProperty("top")?n.top:100,n.style=n.style||"",n.style+=" top:"+(t.body.scrollTop+n.top)+"px"),2===n.type&&(n.content='<i></i><i class="layui-m-layerload"></i><i></i><p>'+(n.content||"")+"</p>"),n.skin&&(n.anim="up"),"msg"===n.skin&&(n.shade=!1),s.innerHTML=(n.shade?"<div "+("string"==typeof n.shade?'style="'+n.shade+'"':"")+' class="layui-m-layershade"></div>':"")+'<div class="layui-m-layermain" '+(n.fixed?"":'style="position:static;"')+'><div class="layui-m-layersection"><div class="layui-m-layerchild '+(n.skin?"layui-m-layer-"+n.skin+" ":"")+(n.className?n.className:"")+" "+(n.anim?"layui-m-anim-"+n.anim:"")+'" '+(n.style?'style="'+n.style+'"':"")+">"+l+'<div class="layui-m-layercont">'+n.content+"</div>"+c+"</div></div></div>",!n.type||2===n.type){var d=t[i](o[0]+n.type),y=d.length;y>=1&&layer.close(d[0].getAttribute("index"))}document.body.appendChild(s);var u=e.elem=a("#"+e.id)[0];n.success&&n.success(u),e.index=r++,e.action(n,u)},c.prototype.action=function(e,t){var n=this;e.time&&(l.timer[n.index]=setTimeout(function(){layer.close(n.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),layer.close(n.index)):e.yes?e.yes(n.index):layer.close(n.index)};if(e.btn)for(var s=t[i]("layui-m-layerbtn")[0].children,r=s.length,o=0;o<r;o++)l.touch(s[o],a);if(e.shade&&e.shadeClose){var c=t[i]("layui-m-layershade")[0];l.touch(c,function(){layer.close(n.index,e.end)})}e.end&&(l.end[n.index]=e.end)},e.layer={v:"2.0",index:r,open:function(e){var t=new c(e||{});return t.index},close:function(e){var n=a("#"+o[0]+e)[0];n&&(n.innerHTML="",t.body.removeChild(n),clearTimeout(l.timer[e]),delete l.timer[e],"function"==typeof l.end[e]&&l.end[e](),delete l.end[e])},closeAll:function(){for(var e=t[i](o[0]),n=0,a=e.length;n<a;n++)layer.close(0|e[0].getAttribute("index"))}},"function"==typeof define?define(function(){return layer}):function(){var e=document.scripts,n=e[e.length-1],i=n.src,a=i.substring(0,i.lastIndexOf("/")+1);n.getAttribute("merge")||document.head.appendChild(function(){var e=t.createElement("link");return e.href=a+"need/layer.css?2.0",e.type="text/css",e.rel="styleSheet",e.id="layermcss",e}())}()}(window);
\ No newline at end of file
.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px}
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论