Procházet zdrojové kódy

日志清理功能

xueli.xue před 8 roky
rodič
revize
00cd63c4ad

+ 3 - 3
README.md Zobrazit soubor

@@ -813,15 +813,15 @@ Tips: 历史版本(V1.3.x)目前已经Release至稳定版本, 进入维护阶段
813 813
 - 3、执行器,server启动、销毁和注册逻辑调整;
814 814
 - 4、JettyServer关闭逻辑优化,修复执行器无法正常关闭导致端口占用和频繁打印c3p0日志的问题;
815 815
 - 5、JobHandler中开启子线程时,支持子线程输出执行日志并通过Rolling查看。
816
+- 6、任务日志清理功能;
816 817
 
817 818
 #### TODO LIST
818 819
 - 1、任务并行触发处理规则:单机串行队列(默认)、单机并行、串行忽略、单机覆盖;
819 820
 - 2、任务权限管理;
820 821
 - 3、调度失败重试机制;
821 822
 - 4、执行器与数据库解耦,只需配置调度中心集群地址即可(与当前通过JDBC注册自动发现方式,相冲突,待考虑);
822
-- 5、任务日志定期清理功能,支持设置日志上限;
823
-- 6、任务分片:一个任务被拆分成N个独立的任务单元,然后由分布式部署的执行器分别执行某一个或几个分片单元;
824
-- 7、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;
823
+- 5、任务分片:一个任务被拆分成N个独立的任务单元,然后由分布式部署的执行器分别执行某一个或几个分片单元;
824
+- 6、任务分片路由:分片采用一致性Hash算法计算出尽量稳定的分片顺序,即使注册机器存在波动也不会引起分批分片顺序大的波动;
825 825
 
826 826
 
827 827
 ## 七、其他

+ 33 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java Zobrazit soubor

@@ -167,4 +167,37 @@ public class JobLogController {
167 167
 			return new ReturnT<String>(500, runResult.getMsg());
168 168
 		}
169 169
 	}
170
+
171
+	@RequestMapping("/clearLog")
172
+	@ResponseBody
173
+	public ReturnT<String> clearLog(int jobGroup, int jobId, int type){
174
+
175
+		Date clearBeforeTime = null;
176
+		int clearBeforeNum = 0;
177
+		if (type == 1) {
178
+			clearBeforeTime = DateUtils.addMonths(new Date(), -1);	// 清理一个月之前日志数据
179
+		} else if (type == 2) {
180
+			clearBeforeTime = DateUtils.addMonths(new Date(), -3);	// 清理三个月之前日志数据
181
+		} else if (type == 3) {
182
+			clearBeforeTime = DateUtils.addMonths(new Date(), -6);	// 清理六个月之前日志数据
183
+		} else if (type == 4) {
184
+			clearBeforeTime = DateUtils.addYears(new Date(), -1);	// 清理一年之前日志数据
185
+		} else if (type == 5) {
186
+			clearBeforeNum = 1000;		// 清理一千条以前日志数据
187
+		} else if (type == 6) {
188
+			clearBeforeNum = 10000;		// 清理一万条以前日志数据
189
+		} else if (type == 7) {
190
+			clearBeforeNum = 30000;		// 清理三万条以前日志数据
191
+		} else if (type == 8) {
192
+			clearBeforeNum = 100000;	// 清理十万条以前日志数据
193
+		} else if (type == 9) {
194
+			clearBeforeNum = 0;			// 清理所用日志数据
195
+		} else {
196
+			return new ReturnT<String>(ReturnT.FAIL_CODE, "清理类型参数异常");
197
+		}
198
+
199
+		xxlJobLogDao.clearLog(jobGroup, jobId, clearBeforeTime, clearBeforeNum);
200
+		return ReturnT.SUCCESS;
201
+	}
202
+
170 203
 }

+ 2 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/dao/IXxlJobLogDao.java Zobrazit soubor

@@ -29,4 +29,6 @@ public interface IXxlJobLogDao {
29 29
 
30 30
 	public List<Map<String, Object>> triggerCountByDay(Date from, Date to, int handleCode);
31 31
 
32
+	public int clearLog(int jobGroup, int jobId, Date clearBeforeTime, int clearBeforeNum);
33
+
32 34
 }

+ 10 - 0
xxl-job-admin/src/main/java/com/xxl/job/admin/dao/impl/XxlJobLogDaoImpl.java Zobrazit soubor

@@ -92,4 +92,14 @@ public class XxlJobLogDaoImpl implements IXxlJobLogDao {
92 92
 		return sqlSessionTemplate.selectList("XxlJobLogMapper.triggerCountByDay", params);
93 93
 	}
94 94
 
95
+	@Override
96
+	public int clearLog(int jobGroup, int jobId, Date clearBeforeTime, int clearBeforeNum) {
97
+		Map<String, Object> params = new HashMap<String, Object>();
98
+		params.put("jobGroup", jobGroup);
99
+		params.put("jobId", jobId);
100
+		params.put("clearBeforeTime", clearBeforeTime);
101
+		params.put("clearBeforeNum", clearBeforeNum);
102
+		return sqlSessionTemplate.delete("XxlJobLogMapper.clearLog", params);
103
+	}
104
+
95 105
 }

+ 32 - 0
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml Zobrazit soubor

@@ -147,5 +147,37 @@
147 147
 		</if>
148 148
         GROUP BY triggerDay;
149 149
     </select>
150
+
151
+	<delete id="clearLog" parameterType="java.util.Map" >
152
+		delete from XXL_JOB_QRTZ_TRIGGER_LOG
153
+		<trim prefix="WHERE" prefixOverrides="AND | OR" >
154
+			<if test="jobGroup gt 0">
155
+				AND job_group = #{jobGroup}
156
+			</if>
157
+			<if test="jobId gt 0">
158
+				AND job_id = #{jobId}
159
+			</if>
160
+			<if test="clearBeforeTime != null">
161
+				AND trigger_time <![CDATA[ <= ]]> #{clearBeforeTime}
162
+			</if>
163
+			<if test="clearBeforeNum gt 0">
164
+				AND id NOT in(
165
+					SELECT id FROM(
166
+						SELECT id FROM XXL_JOB_QRTZ_TRIGGER_LOG AS t
167
+						<trim prefix="WHERE" prefixOverrides="AND | OR" >
168
+							<if test="jobGroup gt 0">
169
+								AND t.job_group = #{jobGroup}
170
+							</if>
171
+							<if test="jobId gt 0">
172
+								AND t.job_id = #{jobId}
173
+							</if>
174
+						</trim>
175
+						ORDER BY t.trigger_time desc
176
+						LIMIT 0, #{clearBeforeNum}
177
+					) t1
178
+				)
179
+			</if>
180
+		</trim>
181
+	</delete>
150 182
 	
151 183
 </mapper>

+ 3 - 0
xxl-job-admin/src/main/webapp/WEB-INF/template/common/common.macro.ftl Zobrazit soubor

@@ -45,6 +45,9 @@
45 45
     <#-- jquery cookie -->
46 46
 	<script src="${request.contextPath}/static/plugins/jquery/jquery.cookie.js"></script>
47 47
 
48
+	<#-- layer -->
49
+	<script src="${request.contextPath}/static/plugins/layer/layer.js"></script>
50
+
48 51
 	<#-- common -->
49 52
     <script src="${request.contextPath}/static/js/xxl.alert.1.js"></script>
50 53
     <script src="${request.contextPath}/static/js/common.1.js"></script>

+ 64 - 6
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/joblog.index.ftl Zobrazit soubor

@@ -36,7 +36,7 @@
36 36
  					<div class="input-group">
37 37
 	                	<span class="input-group-addon">执行器</span>
38 38
                 		<select class="form-control" id="jobGroup"  paramVal="<#if jobInfo?exists>${jobInfo.jobGroup}</#if>" >
39
-                            <option value="0" >请选择</option>
39
+                            <option value="0" >全部</option>
40 40
                 			<#list JobGroupList as group>
41 41
                 				<option value="${group.id}" >${group.title}</option>
42 42
                 			</#list>
@@ -47,7 +47,7 @@
47 47
 	              	<div class="input-group">
48 48
 	                	<span class="input-group-addon">任务</span>
49 49
                         <select class="form-control" id="jobId" paramVal="<#if jobInfo?exists>${jobInfo.id}</#if>" >
50
-                            <option value="0" >请选择</option>
50
+                            <option value="0" >全部</option>
51 51
 						</select>
52 52
 	              	</div>
53 53
 	            </div>
@@ -59,10 +59,13 @@
59 59
 	                	<input type="text" class="form-control" id="filterTime" readonly >
60 60
 	              	</div>
61 61
 	            </div>
62
-	            
63
-				
64
-	            <div class="col-xs-2">
65
-	            	<button class="btn btn-block btn-info" id="searchBtn">搜索</button>
62
+
63
+                <div class="col-xs-1">
64
+                    <button class="btn btn-block btn-info" id="searchBtn">搜索</button>
65
+                </div>
66
+
67
+	            <div class="col-xs-1">
68
+                    <button class="btn btn-block btn-nomal" id="clearLog">清理</button>
66 69
 	            </div>
67 70
           	</div>
68 71
 			
@@ -102,6 +105,61 @@
102 105
 	<@netCommon.commonFooter />
103 106
 </div>
104 107
 
108
+<!-- 日志清理.模态框 -->
109
+<div class="modal fade" id="clearLogModal" tabindex="-1" role="dialog"  aria-hidden="true">
110
+    <div class="modal-dialog">
111
+        <div class="modal-content">
112
+            <div class="modal-header">
113
+                <h4 class="modal-title" >日志清理</h4>
114
+            </div>
115
+            <div class="modal-body">
116
+                <form class="form-horizontal form" role="form" >
117
+                    <div class="form-group">
118
+                        <label class="col-sm-3 control-label"">执行器:</label>
119
+                        <div class="col-sm-9">
120
+                            <input type="text" class="form-control jobGroupText" readonly >
121
+							<input type="hidden" name="jobGroup" >
122
+						</div>
123
+                    </div>
124
+
125
+                    <div class="form-group">
126
+                        <label class="col-sm-3 control-label"">任务:</label>
127
+                        <div class="col-sm-9">
128
+                            <input type="text" class="form-control jobIdText" readonly >
129
+                            <input type="hidden" name="jobId" >
130
+						</div>
131
+                    </div>
132
+
133
+                    <div class="form-group">
134
+                        <label class="col-sm-3 control-label"">清理类型:</label>
135
+                        <div class="col-sm-9">
136
+                            <select class="form-control" name="type" >
137
+                                <option value="1" >清理一个月之前日志数据</option>
138
+                                <option value="2" >清理三个月之前日志数据</option>
139
+                                <option value="3" >清理六个月之前日志数据</option>
140
+                                <option value="4" >清理一年之前日志数据</option>
141
+                                <option value="5" >清理一千条以前日志数据</option>
142
+                                <option value="6" >清理一万条以前日志数据</option>
143
+                                <option value="7" >清理三万条以前日志数据</option>
144
+                                <option value="8" >清理十万条以前日志数据</option>
145
+                                <option value="9" >清理所用日志数据</option>
146
+                            </select>
147
+                        </div>
148
+                    </div>
149
+
150
+                    <hr>
151
+                    <div class="form-group">
152
+                        <div class="col-sm-offset-3 col-sm-6">
153
+                            <button type="button" class="btn btn-primary ok" >保存</button>
154
+                            <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
155
+                        </div>
156
+                    </div>
157
+                </form>
158
+            </div>
159
+        </div>
160
+    </div>
161
+</div>
162
+
105 163
 <@netCommon.commonScript />
106 164
 <!-- DataTables -->
107 165
 <script src="${request.contextPath}/static/adminlte/plugins/datatables/jquery.dataTables.min.js"></script>

+ 52 - 4
xxl-job-admin/src/main/webapp/static/js/joblog.index.1.js Zobrazit soubor

@@ -11,7 +11,7 @@ $(function() {
11 11
 			dataType : "json",
12 12
 			success : function(data){
13 13
 				if (data.code == 200) {
14
-					$("#jobId").html('<option value="0" >请选择</option>');
14
+					$("#jobId").html('<option value="0" >全部</option>');
15 15
 					$.each(data.content, function (n, value) {
16 16
                         $("#jobId").append('<option value="' + value.id + '" >' + value.jobDesc + '</option>');
17 17
                     });
@@ -153,7 +153,7 @@ $(function() {
153 153
 		                		if (row.triggerCode == 200){
154 154
 		                			var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">执行日志</a>';
155 155
 		                			if(row.handleCode == 0){
156
-		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'">终止任务</a>';
156
+		                				temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'" style="color: red;" >终止任务</a>';
157 157
 		                			}
158 158
 		                			return temp;
159 159
 		                		}
@@ -228,7 +228,10 @@ $(function() {
228 228
 		});
229 229
 		*/
230 230
 	});
231
-	
231
+
232
+	/**
233
+	 * 终止任务
234
+	 */
232 235
 	$('#joblog_list').on('click', '.logKill', function(){
233 236
 		var _id = $(this).attr('_id');
234 237
 		ComConfirm.show("确认主动终止任务?", function(){
@@ -248,5 +251,50 @@ $(function() {
248 251
 			});
249 252
 		});
250 253
 	});
251
-	
254
+
255
+	/**
256
+	 * 清理任务Log
257
+	 */
258
+	$('#clearLog').on('click', function(){
259
+
260
+		var jobGroup = $('#jobGroup').val();
261
+		var jobId = $('#jobId').val();
262
+
263
+		var jobGroupText = $("#jobGroup").find("option:selected").text();
264
+		var jobIdText = $("#jobId").find("option:selected").text();
265
+
266
+		$('#clearLogModal input[name=jobGroup]').val(jobGroup);
267
+		$('#clearLogModal input[name=jobId]').val(jobId);
268
+
269
+		$('#clearLogModal .jobGroupText').val(jobGroupText);
270
+		$('#clearLogModal .jobIdText').val(jobIdText);
271
+
272
+		$('#clearLogModal').modal('show');
273
+
274
+	});
275
+	$("#clearLogModal .ok").on('click', function(){
276
+		$.post(base_url + "/joblog/clearLog",  $("#clearLogModal .form").serialize(), function(data, status) {
277
+			if (data.code == "200") {
278
+				$('#clearLogModal').modal('hide');
279
+				layer.open({
280
+					title: '系统提示',
281
+					content: '日志清理成功',
282
+					icon: '1',
283
+					end: function(layero, index){
284
+						logTable.fnDraw();
285
+					}
286
+				});
287
+			} else {
288
+				layer.open({
289
+					title: '系统提示',
290
+					content: (data.msg || "日志清理失败"),
291
+					icon: '2'
292
+				});
293
+			}
294
+		});
295
+	});
296
+	$("#clearLogModal").on('hide.bs.modal', function () {
297
+		$("#clearLogModal .form")[0].reset();
298
+	});
299
+
252 300
 });

Diff nebyl zobrazen, protože je příliš veliký
+ 2 - 0
xxl-job-admin/src/main/webapp/static/plugins/layer/layer.js


+ 2 - 0
xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/layer.js Zobrazit soubor

@@ -0,0 +1,2 @@
1
+/*! layer mobile-v2.0.0 Web弹层组件 MIT License  http://layer.layui.com/mobile  By 贤心 */
2
+ ;!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);

Diff nebyl zobrazen, protože je příliš veliký
+ 1 - 0
xxl-job-admin/src/main/webapp/static/plugins/layer/mobile/need/layer.css


binární
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/icon-ext.png Zobrazit soubor


binární
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/icon.png Zobrazit soubor


Diff nebyl zobrazen, protože je příliš veliký
+ 1 - 0
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/layer.css


binární
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/loading-0.gif Zobrazit soubor


binární
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/loading-1.gif Zobrazit soubor


binární
xxl-job-admin/src/main/webapp/static/plugins/layer/skin/default/loading-2.gif Zobrazit soubor