支持执行器详细日志
This commit is contained in:
parent
ee9eca0db7
commit
3a4df20e73
|
@ -17,6 +17,7 @@ git.osc地址:http://git.oschina.net/xuxueli0323/xxl-job
|
||||||
7、支持任务执行日志;
|
7、支持任务执行日志;
|
||||||
8、支持自定义参数;
|
8、支持自定义参数;
|
||||||
9、支持任务失败次数超阈值邮件报警;
|
9、支持任务失败次数超阈值邮件报警;
|
||||||
|
10、支持在线查看,执行器详细日志;
|
||||||
|
|
||||||
# 新版本 V1.2.x,新特性
|
# 新版本 V1.2.x,新特性
|
||||||
1、支持任务分组;
|
1、支持任务分组;
|
||||||
|
|
|
@ -16,8 +16,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
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.HttpUtil.RemoteCallBack;
|
||||||
|
import com.xxl.job.client.util.JacksonUtil;
|
||||||
import com.xxl.job.core.constant.Constants.JobGroupEnum;
|
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.core.model.XxlJobLog;
|
||||||
import com.xxl.job.dao.IXxlJobLogDao;
|
import com.xxl.job.dao.IXxlJobLogDao;
|
||||||
|
|
||||||
|
@ -88,4 +92,41 @@ public class JobLogController {
|
||||||
return callBack;
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ public class RemoteHttpJobBean extends QuartzJobBean {
|
||||||
|
|
||||||
// trigger request
|
// trigger request
|
||||||
HashMap<String, String> params = new HashMap<String, String>();
|
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_URL, PropertiesUtil.getString(HandlerRepository.TRIGGER_LOG_URL));
|
||||||
params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
|
params.put(HandlerRepository.TRIGGER_LOG_ID, String.valueOf(jobLog.getId()));
|
||||||
params.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
params.put(HandlerRepository.TRIGGER_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
t.job_cron,
|
t.job_cron,
|
||||||
t.job_desc,
|
t.job_desc,
|
||||||
t.job_class,
|
t.job_class,
|
||||||
t.job_desc,
|
t.job_data,
|
||||||
t.trigger_time,
|
t.trigger_time,
|
||||||
t.trigger_status,
|
t.trigger_status,
|
||||||
t.trigger_msg,
|
t.trigger_msg,
|
||||||
|
|
|
@ -67,8 +67,8 @@
|
||||||
<th name="id" >id</th>
|
<th name="id" >id</th>
|
||||||
<th name="jobGroup" >任务组</th>
|
<th name="jobGroup" >任务组</th>
|
||||||
<th name="jobName" >任务名</th>
|
<th name="jobName" >任务名</th>
|
||||||
<th name="jobCron" >Cron</th>
|
|
||||||
<th name="jobDesc" >描述</th>
|
<th name="jobDesc" >描述</th>
|
||||||
|
<th name="jobCron" >Cron</th>
|
||||||
<th name="jobClass" >JobBean</th>
|
<th name="jobClass" >JobBean</th>
|
||||||
<th name="jobData" >任务数据</th>
|
<th name="jobData" >任务数据</th>
|
||||||
<th name="addTime" >新增时间</th>
|
<th name="addTime" >新增时间</th>
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
<th name="handleTime" >执行时间</th>
|
<th name="handleTime" >执行时间</th>
|
||||||
<th name="handleStatus" >执行结果</th>
|
<th name="handleStatus" >执行结果</th>
|
||||||
<th name="handleMsg" >执行日志</th>
|
<th name="handleMsg" >执行日志</th>
|
||||||
|
<th class="handleMsg" >操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
|
|
|
@ -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>
|
|
@ -18,6 +18,7 @@ $(function() {
|
||||||
{ "data": 'id', "bSortable": false, "visible" : false},
|
{ "data": 'id', "bSortable": false, "visible" : false},
|
||||||
{
|
{
|
||||||
"data": 'jobGroup',
|
"data": 'jobGroup',
|
||||||
|
"visible" : false,
|
||||||
"render": function ( data, type, row ) {
|
"render": function ( data, type, row ) {
|
||||||
var groupMenu = $("#jobGroup").find("option");
|
var groupMenu = $("#jobGroup").find("option");
|
||||||
for ( var index in $("#jobGroup").find("option")) {
|
for ( var index in $("#jobGroup").find("option")) {
|
||||||
|
@ -29,14 +30,18 @@ $(function() {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ "data": 'jobName'},
|
{ "data": 'jobName'},
|
||||||
|
{ "data": 'jobDesc', "visible" : true},
|
||||||
{ "data": 'jobCron', "visible" : true},
|
{ "data": 'jobCron', "visible" : true},
|
||||||
{ "data": 'jobDesc', "visible" : false},
|
{ "data": 'jobClass', "visible" : false},
|
||||||
{ "data": 'jobClass', "visible" : true},
|
|
||||||
{
|
{
|
||||||
"data": 'jobData',
|
"data": 'jobData',
|
||||||
"visible" : true,
|
"visible" : true,
|
||||||
"render": function ( data, type, row ) {
|
"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 +'" '+
|
' handler_name="'+ jobDataMap.handler_name +'" '+
|
||||||
'>'+
|
'>'+
|
||||||
pause_resume +
|
pause_resume +
|
||||||
'<button class="btn btn-info btn-xs job_operate" type="job_trigger" type="button">执行</button> '+
|
'<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 update" type="button">编辑</button><br>'+
|
||||||
'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
|
'<button class="btn btn-warning btn-xs" type="job_del" type="button" '+
|
||||||
'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button> '+
|
'onclick="javascript:window.open(\'' + logUrl + '\')" >查看日志</button> '+
|
||||||
'<button class="btn btn-danger btn-xs job_operate" type="job_del" type="button">删除</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(){
|
$('#searchBtn').on('click', function(){
|
||||||
jobTable.fnDraw();
|
jobTable.fnDraw();
|
||||||
|
|
|
@ -48,6 +48,7 @@ $(function() {
|
||||||
{ "data": 'id', "bSortable": false, "visible" : false},
|
{ "data": 'id', "bSortable": false, "visible" : false},
|
||||||
{
|
{
|
||||||
"data": 'jobGroup',
|
"data": 'jobGroup',
|
||||||
|
"visible" : false,
|
||||||
"bSortable": false,
|
"bSortable": false,
|
||||||
"render": function ( data, type, row ) {
|
"render": function ( data, type, row ) {
|
||||||
var groupMenu = $("#jobGroup").find("option");
|
var groupMenu = $("#jobGroup").find("option");
|
||||||
|
@ -65,9 +66,14 @@ $(function() {
|
||||||
{ "data": 'jobClass', "visible" : false},
|
{ "data": 'jobClass', "visible" : false},
|
||||||
{
|
{
|
||||||
"data": 'jobData',
|
"data": 'jobData',
|
||||||
"visible" : false,
|
"visible" : true,
|
||||||
"render": function ( data, type, row ) {
|
"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 ) {
|
"render": function ( data, type, row ) {
|
||||||
return data?'<a class="logTips" href="javascript:;" >查看<span style="display:none;">'+ data +'</span></a>':"无";
|
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" : {
|
"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(){
|
$('#joblog_list').on('click', '.logTips', function(){
|
||||||
var msg = $(this).find('span').html();
|
var msg = $(this).find('span').html();
|
||||||
ComAlertTec.show(msg);
|
ComAlertTec.show(msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 搜索按钮
|
// 搜索按钮
|
||||||
$('#searchBtn').on('click', function(){
|
$('#searchBtn').on('click', function(){
|
||||||
logTable.fnDraw();
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package com.xxl.job.service.handler;
|
package com.xxl.job.service.handler;
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -25,7 +24,10 @@ public class DemoJobHandler extends IJobHandler {
|
||||||
@Override
|
@Override
|
||||||
public JobHandleStatus handle(String... params) throws Exception {
|
public JobHandleStatus handle(String... params) throws Exception {
|
||||||
logger.info(" ... params:" + params);
|
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;
|
return JobHandleStatus.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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>
|
|
@ -1,5 +1,6 @@
|
||||||
package com.xxl.job.client.handler;
|
package com.xxl.job.client.handler;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@ -7,6 +8,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
|
import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
|
||||||
|
import com.xxl.job.client.log.XxlJobFileAppender;
|
||||||
import com.xxl.job.client.util.JacksonUtil;
|
import com.xxl.job.client.util.JacksonUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,6 +18,9 @@ import com.xxl.job.client.util.JacksonUtil;
|
||||||
public class HandlerRepository {
|
public class HandlerRepository {
|
||||||
private static Logger logger = LoggerFactory.getLogger(HandlerRepository.class);
|
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_ADDRESS = "handler_address";
|
||||||
public static final String HANDLER_NAME = "handler_name";
|
public static final String HANDLER_NAME = "handler_name";
|
||||||
public static final String HANDLER_PARAMS = "handler_params";
|
public static final String HANDLER_PARAMS = "handler_params";
|
||||||
|
@ -35,36 +40,68 @@ public class HandlerRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
// handler push to queue
|
// handler push to queue
|
||||||
public static String pushHandleQueue(Map<String, String> _param) {
|
public static String service(Map<String, String> _param) {
|
||||||
logger.info(">>>>>>>>>>> xxl-job pushHandleQueue start, _param:{}", new Object[]{_param});
|
logger.info(">>>>>>>>>>> xxl-job service start, _param:{}", new Object[]{_param});
|
||||||
|
|
||||||
// callback
|
// callback
|
||||||
RemoteCallBack callback = new RemoteCallBack();
|
RemoteCallBack callback = new RemoteCallBack();
|
||||||
callback.setStatus(RemoteCallBack.FAIL);
|
callback.setStatus(RemoteCallBack.FAIL);
|
||||||
|
|
||||||
// encryption check
|
// check namespace
|
||||||
long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
|
String namespace = _param.get(HandlerRepository.NAMESPACE);
|
||||||
if (System.currentTimeMillis() - timestamp > 60000) {
|
if (namespace==null || namespace.trim().length()==0) {
|
||||||
callback.setMsg("Timestamp check failed.");
|
callback.setMsg("param[NAMESPACE] can not be null.");
|
||||||
return JacksonUtil.writeValueAsString(callback);
|
return JacksonUtil.writeValueAsString(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// push data to queue
|
// parse namespace
|
||||||
String handler_name = _param.get(HandlerRepository.HANDLER_NAME);
|
if (namespace.equals(HandlerRepository.NameSpaceEnum.RUN.name())) {
|
||||||
if (handler_name!=null && handler_name.trim().length()>0) {
|
// encryption check
|
||||||
HandlerThread handlerThread = handlerTreadMap.get(handler_name);
|
long timestamp = _param.get(HandlerRepository.TRIGGER_TIMESTAMP)!=null?Long.valueOf(_param.get(HandlerRepository.TRIGGER_TIMESTAMP)):-1;
|
||||||
if (handlerThread != null) {
|
if (System.currentTimeMillis() - timestamp > 60000) {
|
||||||
handlerThread.pushData(_param);
|
callback.setMsg("Timestamp check failed.");
|
||||||
callback.setStatus(RemoteCallBack.SUCCESS);
|
return JacksonUtil.writeValueAsString(callback);
|
||||||
} else {
|
|
||||||
callback.setMsg("handler[" + handler_name + "] not found.");
|
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
callback.setMsg("param[HANDLER_NAME] can not be null.");
|
// 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);
|
||||||
|
}
|
||||||
|
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});
|
logger.info(">>>>>>>>>>> xxl-job service end, triggerData:{}", new Object[]{callback});
|
||||||
return JacksonUtil.writeValueAsString(callback);
|
return JacksonUtil.writeValueAsString(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.xxl.job.client.handler.IJobHandler.JobHandleStatus;
|
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;
|
||||||
import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
|
import com.xxl.job.client.util.HttpUtil.RemoteCallBack;
|
||||||
|
|
||||||
|
@ -63,6 +64,7 @@ public class HandlerThread extends Thread{
|
||||||
JobHandleStatus _status = JobHandleStatus.FAIL;
|
JobHandleStatus _status = JobHandleStatus.FAIL;
|
||||||
String _msg = null;
|
String _msg = null;
|
||||||
try {
|
try {
|
||||||
|
XxlJobFileAppender.contextHolder.set(trigger_log_id);
|
||||||
_status = handler.handle(handlerParams);
|
_status = handler.handle(handlerParams);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.info("HandlerThread Exception:", e);
|
logger.info("HandlerThread Exception:", e);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.setContentType("text/html;charset=utf-8");
|
||||||
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
|
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class XxlJobServlet extends HttpServlet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String resp = HandlerRepository.pushHandleQueue(_param);
|
String resp = HandlerRepository.service(_param);
|
||||||
response.getWriter().append(resp);
|
response.getWriter().append(resp);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue