diff --git a/doc/images/qq群-一个xxl同学进了58.png b/doc/images/qq群-一个xxl同学进了58.png new file mode 100644 index 00000000..a525e0b7 Binary files /dev/null and b/doc/images/qq群-一个xxl同学进了58.png differ diff --git a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java index d07bf952..d83c96d5 100644 --- a/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java +++ b/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java @@ -7,6 +7,7 @@ import com.xxl.job.admin.dao.IXxlJobGroupDao; import com.xxl.job.admin.dao.IXxlJobInfoDao; import com.xxl.job.admin.dao.IXxlJobLogDao; import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.rpc.netcom.NetComClientProxy; import org.apache.commons.lang.StringUtils; @@ -92,43 +93,42 @@ public class JobLogController { maps.put("data", list); // 分页列表 return maps; } - - @RequestMapping("/logDetail") - @ResponseBody - public ReturnT logDetail(int id){ - // base check - XxlJobLog log = xxlJobLogDao.load(id); - if (log == null) { - return new ReturnT(500, "查看执行日志失败: 参数异常"); - } - if (ReturnT.SUCCESS_CODE != log.getTriggerCode()) { - return new ReturnT(500, "查看执行日志失败: 任务发起调度失败,无法查看执行日志"); - } - - // trigger id, trigger time - ExecutorBiz executorBiz = null; - try { - executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, log.getExecutorAddress()).getObject(); - } catch (Exception e) { - e.printStackTrace(); - return new ReturnT(500, e.getMessage()); - } - ReturnT logResult = executorBiz.log(log.getTriggerTime().getTime(), id); - if (ReturnT.SUCCESS_CODE == logResult.getCode()) { - return new ReturnT(logResult.getMsg()); - } else { - return new ReturnT(500, "查看执行日志失败: " + logResult.getMsg()); - } - } - @RequestMapping("/logDetailPage") public String logDetailPage(int id, Model model){ - ReturnT data = logDetail(id); - model.addAttribute("result", data); + + // base check + ReturnT logStatue = ReturnT.SUCCESS; + XxlJobLog jobLog = xxlJobLogDao.load(id); + if (jobLog == null) { + logStatue = new ReturnT(ReturnT.FAIL_CODE, "查看执行日志失败: 日志ID非法"); + } else { + if (ReturnT.SUCCESS_CODE != jobLog.getTriggerCode()) { + logStatue = new ReturnT(ReturnT.FAIL_CODE, "查看执行日志失败: 任务发起调度失败,无法查看执行日志"); + } + + model.addAttribute("executorAddress", jobLog.getExecutorAddress()); + model.addAttribute("triggerTime", jobLog.getTriggerTime().getTime()); + model.addAttribute("logId", jobLog.getId()); + } + + model.addAttribute("logStatue", logStatue); return "joblog/logdetail"; } - + + @RequestMapping("/logDetailCat") + @ResponseBody + public ReturnT logDetailCat(String executorAddress, long triggerTime, int logId, int fromLineNum){ + try { + ExecutorBiz executorBiz = (ExecutorBiz) new NetComClientProxy(ExecutorBiz.class, executorAddress).getObject(); + ReturnT logResult = executorBiz.log(triggerTime, logId, fromLineNum); + return logResult; + } catch (Exception e) { + e.printStackTrace(); + return new ReturnT(ReturnT.FAIL_CODE, e.getMessage()); + } + } + @RequestMapping("/logKill") @ResponseBody public ReturnT logKill(int id){ diff --git a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/logdetail.ftl b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/logdetail.ftl index bc2c90d8..41c9d57d 100644 --- a/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/logdetail.ftl +++ b/xxl-job-admin/src/main/webapp/WEB-INF/template/joblog/logdetail.ftl @@ -1,7 +1,95 @@ - -
-
-<#if result.code == 200>${result.content} -<#else>${result.msg} -
+ + + + 任务调度中心 +<#import "/common/common.macro.ftl" as netCommon> +<@netCommon.commonStyle /> + + + + +
+ +
+ +
+ +
+
  • +
    + +
    + +<@netCommon.commonScript /> + + + + \ No newline at end of file diff --git a/xxl-job-admin/src/main/webapp/static/js/logdetail.index.1.js b/xxl-job-admin/src/main/webapp/static/js/logdetail.index.1.js new file mode 100644 index 00000000..7dbb7d34 --- /dev/null +++ b/xxl-job-admin/src/main/webapp/static/js/logdetail.index.1.js @@ -0,0 +1,78 @@ +$(function() { + + // valid + if (!running) { + return; + } + + // 加载日志 + var fromLineNum = 0; + var pullFailCount = 0; + function pullLog() { + + // pullFailCount, max=20 + if (pullFailCount >= 20) { + console.log("pullLog fail-count limit"); + running = false; + } + + // valid + if (!running) { + $('.logConsoleRunning').hide(); + logRun = window.clearInterval(logRun) + return; + } + + // load + console.log("pullLog, fromLineNum:" + fromLineNum); + $.ajax({ + type : 'POST', + async: false, // async, avoid js invoke pagelist before jobId data init + url : base_url + '/joblog/logDetailCat', + data : { + "executorAddress":executorAddress, + "triggerTime":triggerTime, + "logId":logId, + "fromLineNum":fromLineNum + }, + dataType : "json", + success : function(data){ + pullFailCount++; + if (data.code == 200) { + if (!data.content) { + console.log('pullLog fail'); + return; + } + if (fromLineNum != data.content.fromLineNum) { + console.log('pullLog fromLineNum not match'); + return; + } + if (fromLineNum == (data.content.toLineNum + 1) ) { + console.log('pullLog already line-end'); + return; + } + + // append + fromLineNum = data.content.toLineNum + 1; + $('#logConsole').append(data.content.logContent); + pullFailCount = 0; + + // valid end + if (data.content.end) { + running = false; + console.log("pullLog already file-end"); + } + } else { + ComAlertTec.show(data.msg); + } + } + }); + } + + // 周期运行 + pullLog(); + var logRun = setInterval(function () { + pullLog() + }, 3000); + +}); diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java b/xxl-job-core/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java index 7fbaa8b0..40465725 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/biz/ExecutorBiz.java @@ -1,5 +1,6 @@ package com.xxl.job.core.biz; +import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.TriggerParam; @@ -25,9 +26,10 @@ public interface ExecutorBiz { * log * @param logDateTim * @param logId + * @param fromLineNum * @return */ - public ReturnT log(long logDateTim, int logId); + public ReturnT log(long logDateTim, int logId, int fromLineNum); /** * run diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java b/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java index fd393245..babb739b 100644 --- a/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java +++ b/xxl-job-core/src/main/java/com/xxl/job/core/biz/impl/ExecutorBizImpl.java @@ -1,6 +1,7 @@ package com.xxl.job.core.biz.impl; import com.xxl.job.core.biz.ExecutorBiz; +import com.xxl.job.core.biz.model.LogResult; import com.xxl.job.core.biz.model.ReturnT; import com.xxl.job.core.biz.model.TriggerParam; import com.xxl.job.core.executor.XxlJobExecutor; @@ -42,12 +43,12 @@ public class ExecutorBizImpl implements ExecutorBiz { } @Override - public ReturnT log(long logDateTim, int logId) { + public ReturnT log(long logDateTim, int logId, int fromLineNum) { // log filename: yyyy-MM-dd/9999.log String logFileName = XxlJobFileAppender.makeLogFileName(new Date(logDateTim), logId); - String logConteng = XxlJobFileAppender.readLog(logFileName); - return new ReturnT(ReturnT.SUCCESS_CODE, logConteng); + LogResult logResult = XxlJobFileAppender.readLog(logFileName, fromLineNum); + return new ReturnT(logResult); } @Override diff --git a/xxl-job-core/src/main/java/com/xxl/job/core/biz/model/LogResult.java b/xxl-job-core/src/main/java/com/xxl/job/core/biz/model/LogResult.java new file mode 100644 index 00000000..edf0c686 --- /dev/null +++ b/xxl-job-core/src/main/java/com/xxl/job/core/biz/model/LogResult.java @@ -0,0 +1,47 @@ +package com.xxl.job.core.biz.model; + +import java.io.Serializable; + +/** + * Created by xuxueli on 17/3/23. + */ +public class LogResult implements Serializable { + private static final long serialVersionUID = 42L; + + private int fromLineNum; + private int toLineNum; + private String logContent; + private boolean isEnd; + + public int getFromLineNum() { + return fromLineNum; + } + + public void setFromLineNum(int fromLineNum) { + this.fromLineNum = fromLineNum; + } + + public int getToLineNum() { + return toLineNum; + } + + public void setToLineNum(int toLineNum) { + this.toLineNum = toLineNum; + } + + public String getLogContent() { + return logContent; + } + + public void setLogContent(String logContent) { + this.logContent = logContent; + } + + public boolean isEnd() { + return isEnd; + } + + public void setEnd(boolean end) { + isEnd = end; + } +} 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 0e1a3955..6ff532c8 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 @@ -1,5 +1,6 @@ package com.xxl.job.core.log; +import com.xxl.job.core.biz.model.LogResult; import org.apache.log4j.AppenderSkeleton; import org.apache.log4j.Layout; import org.apache.log4j.spi.LoggingEvent; @@ -117,8 +118,9 @@ public class XxlJobFileAppender extends AppenderSkeleton { * @param logFileName * @return log content */ - public static String readLog(String logFileName ){ + public static LogResult readLog(String logFileName, int fromLineNum){ + // valid log file if (logFileName==null || logFileName.trim().length()==0) { return null; } @@ -127,11 +129,49 @@ public class XxlJobFileAppender extends AppenderSkeleton { if (!logFile.exists()) { return null; } - - String logData = readLines(logFile); - return logData; + + // read file + StringBuffer logContentBuffer = new StringBuffer(); + int toLineNum = 0; + LineNumberReader reader = null; + try { + reader = new LineNumberReader(new FileReader(logFile)); + String line = null; + + while ((line = reader.readLine())!=null) { + toLineNum++; + if (reader.getLineNumber() >= fromLineNum) { + logContentBuffer.append(line).append("\n"); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + // result + LogResult logResult = new LogResult(); + logResult.setFromLineNum(fromLineNum); + logResult.setToLineNum(toLineNum); + logResult.setLogContent(logContentBuffer.toString()); + logResult.setEnd(false); + return logResult; + + /* + // it will return the number of characters actually skipped + reader.skip(Long.MAX_VALUE); + int maxLineNum = reader.getLineNumber(); + maxLineNum++; // 最大行号 + */ } - + /** * read log data * @param logFile @@ -162,52 +202,5 @@ public class XxlJobFileAppender extends AppenderSkeleton { } return null; } - - /** - * read data from line num - * @param logFile - * @param fromLineNum - * @return log content - * @throws Exception - */ - public static String readLinesFrom(File logFile, int fromLineNum) { - LineNumberReader reader = null; - try { - reader = new LineNumberReader(new FileReader(logFile)); - - // sBuffer - StringBuffer sBuffer = new StringBuffer(); - String line = null; - int maxLineNum = 0; - while ((line = reader.readLine())!=null) { - maxLineNum++; - if (reader.getLineNumber() >= fromLineNum) { - sBuffer.append(line).append("\n"); - } - } - - System.out.println("maxLineNum : " + maxLineNum); - return sBuffer.toString(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - return null; - - /* - // it will return the number of characters actually skipped - reader.skip(Long.MAX_VALUE); - int maxLineNum = reader.getLineNumber(); - maxLineNum++; // 最大行号 - */ - } - + }