Kaynağa Gözat

支持执行器详细日志

xueli.xue 9 yıl önce
ebeveyn
işleme
3a4df20e73

+ 1 - 0
README.md

@@ -17,6 +17,7 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job
 	7、支持任务执行日志;
 	8、支持自定义参数;
 	9、支持任务失败次数超阈值邮件报警;
+	10、支持在线查看,执行器详细日志;
 
 # 新版本 V1.2.x,新特性
 	1、支持任务分组;

+ 41 - 0
xxl-job-admin/src/main/java/com/xxl/job/controller/JobLogController.java

@@ -16,8 +16,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import com.xxl.job.client.handler.HandlerRepository;
+import com.xxl.job.client.util.HttpUtil;
 import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
+import com.xxl.job.client.util.JacksonUtil;
 import com.xxl.job.core.constant.Constants.JobGroupEnum;
+import com.xxl.job.core.model.ReturnT;
 import com.xxl.job.core.model.XxlJobLog;
 import com.xxl.job.dao.IXxlJobLogDao;
 
@@ -88,4 +92,41 @@ public class JobLogController {
 		return callBack;
 	}
 	
+	@RequestMapping("/logDetail")
+	@ResponseBody
+	public ReturnT<String> logDetail(int id){
+		// base check
+		XxlJobLog log = xxlJobLogDao.load(id);
+		if (log == null) {
+			return new ReturnT<String>(500, "参数异常");
+		}
+		
+		// server address
+		@SuppressWarnings("unchecked")
+		Map<String, String> jobDataMap = JacksonUtil.readValue(log.getJobData(), Map.class);
+		String handler_address = jobDataMap.get(HandlerRepository.HANDLER_ADDRESS);
+		if (!handler_address.startsWith("http")){
+			handler_address = "http://" + handler_address + "/";
+		}
+		// trigger id, trigger time
+		Map<String, String> reqMap = new HashMap<String, String>();
+		reqMap.put(HandlerRepository.NAMESPACE, HandlerRepository.NameSpaceEnum.LOG.name());
+		reqMap.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(id));
+		reqMap.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(log.getTriggerTime().getTime()));
+		
+		RemoteCallBack callBack = HttpUtil.post(handler_address, reqMap);
+		if (HttpUtil.RemoteCallBack.SUCCESS.equals(callBack.getStatus())) {
+			return new ReturnT<String>(callBack.getMsg());
+		} else {
+			return new ReturnT<String>(500, callBack.getMsg());
+		}
+	}
+	
+	@RequestMapping("/logDetailPage")
+	public String logDetailPage(int id, Model model){
+		ReturnT<String> data = logDetail(id);
+		model.addAttribute("result", data);
+		return "joblog/logdetail";
+	}
+	
 }

+ 1 - 0
xxl-job-admin/src/main/java/com/xxl/job/service/job/RemoteHttpJobBean.java

@@ -55,6 +55,7 @@ public class RemoteHttpJobBean extends QuartzJobBean {
 		
 		// trigger request
 		HashMap<String, String> params = new HashMap<String, String>();
+		params.put(HandlerRepository.NAMESPACE, HandlerRepository.NameSpaceEnum.RUN.name());
 		params.put(HandlerRepository.TRIGGER_LOG_URL, PropertiesUtil.getString(HandlerRepository.TRIGGER_LOG_URL));
 		params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
 		params.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(System.currentTimeMillis()));

+ 1 - 1
xxl-job-admin/src/main/resources/mybatis-mapper/XxlJobLogMapper.xml

@@ -29,7 +29,7 @@
 		t.job_cron,
 		t.job_desc,
 		t.job_class,
-		t.job_desc,
+		t.job_data,
 		t.trigger_time,
 		t.trigger_status,
 		t.trigger_msg,

+ 1 - 1
xxl-job-admin/src/main/webapp/WEB-INF/template/jobinfo/index.ftl

@@ -67,8 +67,8 @@
 					            		<th name="id" >id</th>
 					                	<th name="jobGroup" >任务组</th>
 					                  	<th name="jobName" >任务名</th>
-					                  	<th name="jobCron" >Cron</th>
 					                  	<th name="jobDesc" >描述</th>
+					                  	<th name="jobCron" >Cron</th>
 					                  	<th name="jobClass" >JobBean</th>
 					                  	<th name="jobData" >任务数据</th>
 					                  	<th name="addTime" >新增时间</th>

+ 1 - 0
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/index.ftl

@@ -83,6 +83,7 @@
 					                  	<th name="handleTime" >执行时间</th>
 					                  	<th name="handleStatus" >执行结果</th>
 					                  	<th name="handleMsg" >执行日志</th>
+					                  	<th class="handleMsg" >操作</th>
 					                </tr>
 				                </thead>
 				                <tbody></tbody>

+ 7 - 0
xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/logdetail.ftl

@@ -0,0 +1,7 @@
+<body style="color:white;background-color:black;" >
+<pre>
+<br>
+<#if result.code == 200>${result.content}
+<#else>${result.msg}</#if>
+</pre>
+</body>

+ 10 - 11
xxl-job-admin/src/main/webapp/static/js/jobinfo.index.1.js

@@ -18,6 +18,7 @@ $(function() {
 	                { "data": 'id', "bSortable": false, "visible" : false},
 	                { 
 	                	"data": 'jobGroup', 
+	                	"visible" : false,
 	                	"render": function ( data, type, row ) {
 	            			var groupMenu = $("#jobGroup").find("option");
 	            			for ( var index in $("#jobGroup").find("option")) {
@@ -29,14 +30,18 @@ $(function() {
 	            		}
             		},
 	                { "data": 'jobName'},
+	                { "data": 'jobDesc', "visible" : true},
 	                { "data": 'jobCron', "visible" : true},
-	                { "data": 'jobDesc', "visible" : false},
-	                { "data": 'jobClass', "visible" : true},
+	                { "data": 'jobClass', "visible" : false},
 	                { 
 	                	"data": 'jobData',
 	                	"visible" : true,
 	                	"render": function ( data, type, row ) {
-	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
+	                		var _jobData = eval('(' + data + ')');	// row.jobData
+	                		var html = "<p title='" + data + "'>执行器:" + _jobData.handler_name +
+	                			"<br>执行参数:" + _jobData.handler_params + 
+	                			"<br>执行机器:" + _jobData.handler_address + "</p>";
+	                		return html;
 	                	}
 	                },
 	                { 
@@ -101,8 +106,8 @@ $(function() {
 	                							' handler_name="'+ jobDataMap.handler_name +'" '+
 	                							'>'+
 	                					pause_resume +
-										'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button>  '+
-										'<button class="btn btn-warning btn-xs update" type="button">编辑</button><br> '+
+										'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button>'+
+										'<button class="btn btn-warning btn-xs update" type="button">编辑</button><br>'+
 									  	'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
 									  		'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button> '+
 								  		'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</button>  '+
@@ -140,12 +145,6 @@ $(function() {
 		}
 	});
 	
-	// 日志弹框提示
-	$('#job_list').on('click', '.logTips', function(){
-		var msg = $(this).find('span').html();
-		ComAlertTec.show(msg);
-	});
-	
 	// 搜索按钮
 	$('#searchBtn').on('click', function(){
 		jobTable.fnDraw();

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

@@ -48,6 +48,7 @@ $(function() {
 	                { "data": 'id', "bSortable": false, "visible" : false},
 	                { 
 	                	"data": 'jobGroup', 
+	                	"visible" : false, 
 	                	"bSortable": false, 
 	                	"render": function ( data, type, row ) {
 	            			var groupMenu = $("#jobGroup").find("option");
@@ -65,9 +66,14 @@ $(function() {
 	                { "data": 'jobClass', "visible" : false},
 	                { 
 	                	"data": 'jobData',
-	                	"visible" : false,
+	                	"visible" : true,
 	                	"render": function ( data, type, row ) {
-	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
+	                		var _jobData = eval('(' + data + ')');	// row.jobData
+	                		var html = "<p title='" + data + "'>执行器:" + _jobData.handler_name +
+	                			"<br>执行参数:" + _jobData.handler_params + 
+	                			"<br>执行机器:" + _jobData.handler_address + "</p>";
+	                		
+	                		return data?'<a class="logMsg" href="javascript:;" >查看<span style="display:none;">'+ html +'</span></a>':"无";
 	                	}
 	                },
 	                { 
@@ -95,6 +101,15 @@ $(function() {
 	                	"render": function ( data, type, row ) {
 	                		return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
 	                	}
+	                },
+	                { "data": 'handleStatus' , "bSortable": false,
+	                	"render": function ( data, type, row ) {
+	                		var temp = '<a href="javascript:;" class="logDetail" _id="'+ row.id +'">查看日志</a>';
+	                		if(row.triggerStatus == 'SUCCESS' && !row.handleStatus){
+	                			//temp += '<br><a href="javascript:;" class="logKill" _id="'+ row.id +'">终止任务</a>';
+	                		}
+	                		return temp;
+	                	}
 	                }
 	            ],
 		"language" : {
@@ -123,17 +138,65 @@ $(function() {
 		}
 	});
 	
+	// 任务数据
+	$('#joblog_list').on('click', '.logMsg', function(){
+		var msg = $(this).find('span').html();
+		ComAlert.show(2, msg);
+	});
+	
 	// 日志弹框提示
 	$('#joblog_list').on('click', '.logTips', function(){
 		var msg = $(this).find('span').html();
 		ComAlertTec.show(msg);
 	});
 	
-	
-	
 	// 搜索按钮
 	$('#searchBtn').on('click', function(){
 		logTable.fnDraw();
 	});
 	
+	// 查看执行器详细执行日志
+	$('#joblog_list').on('click', '.logDetail', function(){
+		var _id = $(this).attr('_id');
+		
+		window.open(base_url + 'joblog/logDetailPage?id=' + _id);
+		return;
+		
+		/*
+		$.ajax({
+			type : 'POST',
+			url : base_url + 'joblog/logDetail',
+			data : {"id":_id},
+			dataType : "json",
+			success : function(data){
+				if (data.code == 200) {
+					ComAlertTec.show('<pre style="color: white;background-color: black;width2:'+ $(window).width()*2/3 +'px;" >'+ data.content +'</pre>');
+				} else {
+					ComAlertTec.show(data.msg);
+				}
+			},
+		});
+		*/
+	});
+	
+	$('#joblog_list').on('click', '.logKill', function(){
+		var _id = $(this).attr('_id');
+		ComConfirm.show("确认主动终止任务?", function(){
+			$.ajax({
+				type : 'POST',
+				url : base_url + 'joblog/ferrariJobKill',
+				data : {"id":_id},
+				dataType : "json",
+				success : function(data){
+					if (data.code == 200) {
+						ComAlert.show(1, '操作成功');
+						logTable.fnDraw();
+					} else {
+						ComAlert.show(2, data.msg);
+					}
+				},
+			});
+		});
+	});
+	
 });

+ 4 - 2
xxl-job-client-demo/src/main/java/com/xxl/job/service/handler/DemoJobHandler.java

@@ -1,6 +1,5 @@
 package com.xxl.job.service.handler;
 
-import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
 import org.slf4j.Logger;
@@ -25,7 +24,10 @@ public class DemoJobHandler extends IJobHandler {
 	@Override
 	public JobHandleStatus handle(String... params) throws Exception {
 		logger.info(" ... params:" + params);
-		TimeUnit.SECONDS.sleep(new Random().nextInt(5));
+		for (int i = 0; i < 10; i++) {
+			TimeUnit.SECONDS.sleep(1);
+			logger.info("handler run:{}", i);
+		}
 		return JobHandleStatus.SUCCESS;
 	}
 	

+ 0 - 10
xxl-job-client-demo/src/main/resources/log4j.properties

@@ -1,10 +0,0 @@
-log4j.rootLogger=info,console
-
-log4j.appender.console=org.apache.log4j.ConsoleAppender
-log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=%d - xxl-job-client-demo - %p [%c] - <%m>%n
-
-log4j.appender.logFile=org.apache.log4j.DailyRollingFileAppender
-log4j.appender.logFile.File=${catalina.base}/logs/xxl-job-client-demo.log
-log4j.appender.logFile.layout=org.apache.log4j.PatternLayout
-log4j.appender.logFile.layout.ConversionPattern=%d - xxl-job-client-demo - %p [%c] - <%m>%n

+ 41 - 0
xxl-job-client-demo/src/main/resources/log4j.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" threshold="null" debug="null">
+
+	<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+		<param name="Target" value="System.out" />
+		<layout class="org.apache.log4j.PatternLayout">
+			<param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%t]-[%M]-[%L]-[%p] %m%n" />
+		</layout>
+	</appender>
+	
+    <appender name="ROOT" class="org.apache.log4j.DailyRollingFileAppender">
+        <param name="file" value="/logs/xxl-job-client-demo.log"/>
+        <param name="append" value="true"/>
+        <param name="encoding" value="UTF-8"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
+        </layout>
+    </appender>
+    
+    <appender name="xxl-job" class="com.xxl.job.client.log.XxlJobFileAppender">
+        <param name="filePath" value="/logs/xxl-job/"/>
+        <param name="append" value="true"/>
+        <param name="encoding" value="UTF-8"/>
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="%-d{yyyy-MM-dd HH:mm:ss} [%c]-[%t]-[%M]-[%L]-[%p] %m%n"/>
+        </layout>
+    </appender>
+    
+    <logger name="com.xxl.job.service.handler" additivity="false">
+    	<level value="INFO" />
+        <appender-ref ref="xxl-job"/>
+    </logger>
+
+    <root>
+        <level value="INFO" />
+        <appender-ref ref="CONSOLE" />
+        <appender-ref ref="ROOT" />
+    </root>
+    
+</log4j:configuration>

+ 58 - 21
xxl-job-client/src/main/java/com/xxl/job/client/handler/HandlerRepository.java

@@ -1,5 +1,6 @@
 package com.xxl.job.client.handler;
 
+import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -7,6 +8,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
+import com.xxl.job.client.log.XxlJobFileAppender;
 import com.xxl.job.client.util.JacksonUtil;
 
 /**
@@ -16,6 +18,9 @@ import com.xxl.job.client.util.JacksonUtil;
 public class HandlerRepository {
 	private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
 	
+	public static final String NAMESPACE = "namespace";
+	public enum NameSpaceEnum{RUN, KILL, LOG}
+	
 	public static final String HANDLER_ADDRESS = "handler_address";
 	public static final String HANDLER_NAME = "handler_name";
 	public static final String HANDLER_PARAMS = "handler_params";
@@ -35,36 +40,68 @@ public class HandlerRepository {
 	}
 	
 	// handler push to queue
-	public static String pushHandleQueue(Map<String, String> _param) {
-		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue start, _param:{}", new Object[]{_param});
+	public static String service(Map<String, String> _param) {
+		logger.info(">>>>>>>>>>> xxl-job service start, _param:{}", new Object[]{_param});
 		
 		// callback
 		RemoteCallBack callback = new RemoteCallBack();
 		callback.setStatus(RemoteCallBack.FAIL);
-		
-		// encryption check
-		long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
-		if (System.currentTimeMillis() - timestamp > 60000) {
-			callback.setMsg("Timestamp check failed.");
+
+		// check namespace
+		String namespace = _param.get(HandlerRepository.NAMESPACE);
+		if (namespace==null || namespace.trim().length()==0) {
+			callback.setMsg("param[NAMESPACE] can not be null.");
 			return JacksonUtil.writeValueAsString(callback);
 		}
-				
-		// push data to queue
-		String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
-		if (handler_name!=null && handler_name.trim().length()>0) {
-			HandlerThread handlerThread = handlerTreadMap.get(handler_name);
-			if (handlerThread != null) {
-				handlerThread.pushData(_param);
-				callback.setStatus(RemoteCallBack.SUCCESS);
-			} else {
-				callback.setMsg("handler[" + handler_name + "] not found.");
+		
+		// parse namespace
+		if (namespace.equals(HandlerRepository.NameSpaceEnum.RUN.name())) {
+			// encryption check
+			long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
+			if (System.currentTimeMillis() - timestamp > 60000) {
+				callback.setMsg("Timestamp check failed.");
+				return JacksonUtil.writeValueAsString(callback);
+			}
+					
+			// push data to queue
+			String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
+			if (handler_name!=null && handler_name.trim().length()>0) {
+				HandlerThread handlerThread = handlerTreadMap.get(handler_name);
+				if (handlerThread != null) {
+					handlerThread.pushData(_param);
+					callback.setStatus(RemoteCallBack.SUCCESS);
+				} else {
+					callback.setMsg("handler[" + handler_name + "] not found.");
+				}
+			}else{
+				callback.setMsg("param[HANDLER_NAME] can not be null.");
+			}
+			
+		} else if (namespace.equals(HandlerRepository.NameSpaceEnum.LOG.name())) {
+			String trigger_log_id = _param.get(HandlerRepository.TRIGGER_LOG_ID);
+			String trigger_timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP);
+			if (trigger_log_id==null || trigger_timestamp==null) {
+				callback.setMsg("trigger_log_id | trigger_timestamp can not be null.");
+				return JacksonUtil.writeValueAsString(callback);
+			}
+			int logId = -1;
+			Date triggerDate = null;
+			try {
+				logId = Integer.valueOf(trigger_log_id);
+				triggerDate = new Date(Long.valueOf(trigger_timestamp));
+			} catch (Exception e) {
+			}
+			if (logId<=0 || triggerDate==null) {
+				callback.setMsg("trigger_log_id | trigger_timestamp is not parsed valid.");
+				return JacksonUtil.writeValueAsString(callback);
 			}
-		}else{
-			callback.setMsg("param[HANDLER_NAME] can not be null.");
+			String logConteng = XxlJobFileAppender.readLog(triggerDate, trigger_log_id);
+			callback.setStatus(RemoteCallBack.SUCCESS);
+			callback.setMsg(logConteng);
 		}
 		
-		logger.info(">>>>>>>>>>> xxl-job pushHandleQueue end, triggerData:{}", new Object[]{callback});
-		return JacksonUtil.writeValueAsString(callback);
+		logger.info(">>>>>>>>>>> xxl-job service end, triggerData:{}", new Object[]{callback});
+		return JacksonUtil.writeValueAsString(callback); 
 	}
 	
 }

+ 2 - 0
xxl-job-client/src/main/java/com/xxl/job/client/handler/HandlerThread.java

@@ -12,6 +12,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.xxl.job.client.handler.IJobHandler.JobHandleStatus;
+import com.xxl.job.client.log.XxlJobFileAppender;
 import com.xxl.job.client.util.HttpUtil;
 import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
 
@@ -63,6 +64,7 @@ public class HandlerThread extends Thread{
 					JobHandleStatus _status = JobHandleStatus.FAIL;
 					String _msg = null;
 					try {
+						XxlJobFileAppender.contextHolder.set(trigger_log_id);
 						_status = handler.handle(handlerParams);
 					} catch (Exception e) {
 						logger.info("HandlerThread Exception:", e);

+ 180 - 0
xxl-job-client/src/main/java/com/xxl/job/client/log/XxlJobFileAppender.java

@@ -0,0 +1,180 @@
+package com.xxl.job.client.log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Layout;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * store trigger log in each log-file
+ * @author xuxueli 2016-3-12 19:25:12
+ */
+public class XxlJobFileAppender extends AppenderSkeleton {
+	
+	// for HandlerThread
+	public static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
+	public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+	
+	// trogger log file path
+	public static volatile String filePath;
+	public void setFilePath(String filePath) {
+		XxlJobFileAppender.filePath = filePath;
+	}
+	
+	@Override
+	protected void append(LoggingEvent event) {
+		String trigger_log_id = contextHolder.get();
+		if (trigger_log_id==null || trigger_log_id.trim().length()==0) {
+			return;
+		}
+		
+		// filePath/
+		File filePathDir = new File(filePath);	
+		if (!filePathDir.exists()) {
+			filePathDir.mkdirs();
+		}
+		
+		// filePath/yyyy-MM-dd/
+		String nowFormat = sdf.format(new Date());
+		File filePathDateDir = new File(filePathDir, nowFormat);	
+		if (!filePathDateDir.exists()) {
+			filePathDateDir.mkdirs();
+		}
+		
+		// filePath/yyyy-MM-dd/9999.log
+		String logFileName = trigger_log_id.concat(".log");
+		File logFile = new File(filePathDateDir, logFileName);	
+		if (!logFile.exists()) {
+			try {
+				logFile.createNewFile();
+			} catch (IOException e) {
+				e.printStackTrace();
+				return;
+			}
+		}
+		
+		// append file content
+		try {
+			FileOutputStream fos = null;
+			try {
+				fos = new FileOutputStream(logFile, true);
+				fos.write(layout.format(event).getBytes("utf-8"));
+				if (layout.ignoresThrowable()) {
+					String[] throwableInfo = event.getThrowableStrRep();
+					if (throwableInfo != null) {
+						for (int i = 0; i < throwableInfo.length; i++) {
+							fos.write(throwableInfo[i].getBytes("utf-8"));
+							fos.write(Layout.LINE_SEP.getBytes("utf-8"));
+						}
+					}
+				}
+				fos.flush();
+			} finally {
+				if (fos != null) {
+					try {
+						fos.close();
+					} catch (IOException e) {
+						e.printStackTrace();
+					}
+				}
+			} 
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		
+	}
+
+	@Override
+	public void close() {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	public boolean requiresLayout() {
+		// TODO Auto-generated method stub
+		return false;
+	}
+	
+	/**
+	 * support read log-file
+	 * @param triggerDate
+	 * @param trigger_log_id
+	 * @return
+	 */
+	public static String readLog(Date triggerDate, String trigger_log_id ){
+		if (triggerDate==null || trigger_log_id==null || trigger_log_id.trim().length()==0) {
+			return null;
+		}
+		
+		// filePath/
+		File filePathDir = new File(filePath);	
+		if (!filePathDir.exists()) {
+			filePathDir.mkdirs();
+		}
+		
+		// filePath/yyyy-MM-dd/
+		String nowFormat = sdf.format(triggerDate);
+		File filePathDateDir = new File(filePathDir, nowFormat);	
+		if (!filePathDateDir.exists()) {
+			filePathDateDir.mkdirs();
+		}
+		
+		// filePath/yyyy-MM-dd/9999.log
+		String logFileName = trigger_log_id.concat(".log");
+		File logFile = new File(filePathDateDir, logFileName);	
+		if (!logFile.exists()) {
+			try {
+				logFile.createNewFile();
+			} catch (IOException e) {
+				e.printStackTrace();
+				return null;
+			}
+		}
+		
+		try {
+			InputStream ins = null;
+			BufferedReader reader = null;
+			try {
+				ins = new FileInputStream(logFile);
+				reader = new BufferedReader(new InputStreamReader(ins, "utf-8"));
+				if (reader != null) {
+					String content = null;
+					StringBuilder sb = new StringBuilder();
+					while ((content = reader.readLine()) != null) {
+						sb.append(content).append("\n");
+					}
+					return sb.toString();
+				}
+			} finally {
+				if (ins != null) {
+					try {
+						ins.close();
+					} catch (IOException e) {
+						e.printStackTrace();
+					}
+				}
+				if (reader != null) {
+					try {
+						reader.close();
+					} catch (IOException e) {
+						e.printStackTrace();
+					}
+				}
+			} 
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return null;
+	}
+	
+}

+ 1 - 1
xxl-job-client/src/main/java/com/xxl/job/client/netcom/jetty/XxlJobJettyServerHandler.java

@@ -32,7 +32,7 @@ public class XxlJobJettyServerHandler extends AbstractHandler {
 			}
 		}
 
-		String resp = HandlerRepository.pushHandleQueue(_param);
+		String resp = HandlerRepository.service(_param);
 
 		httpServletResponse.setContentType("text/html;charset=utf-8");
 		httpServletResponse.setStatus(HttpServletResponse.SC_OK);

+ 1 - 1
xxl-job-client/src/main/java/com/xxl/job/client/netcom/servlet/XxlJobServlet.java

@@ -44,7 +44,7 @@ public class XxlJobServlet extends HttpServlet {
 			}
 		}
 		
-		String resp = HandlerRepository.pushHandleQueue(_param);
+		String resp = HandlerRepository.service(_param);
 		response.getWriter().append(resp);
 		return;
 	}