阿里巴巴分布式任務調度系統SchedulerX 2.0提供Log Service,您無需修改代碼,只需增加一個Log4j或Logback的配置,即可在控制台看到每次任務調度(包括分布式任務)的業務日誌。本文介紹如何通過SchedulerX接入並查看Log Service。
前提條件
接入配置
升級SchedulerX用戶端版本
將SchedulerX用戶端版本升級到最新版本,用戶端最新版本,請參見用戶端發布記錄。以Spring Boot Starter為例,在應用程式的pom.xml檔案中添加SchedulerxWorker依賴。
<dependency>
<groupId>com.aliyun.schedulerx</groupId>
<artifactId>schedulerx2-spring-boot-starter</artifactId>
<version>${schedulerx最新版本}</version>
</dependency>配置Log Appender採集Log Service
Log4j2 Appender
方法一:單獨收集任務調度日誌
該方法可以由業務自己控制,只將任務調度日誌採集,其他業務代碼不會被採集,方便排查問題。
log4j2增加一個Appender和Logger如下:<?xml version="1.0" encoding="UTF-8"?> <Configuration status="off"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %m%n" /> </Console> <SchedulerxLog4j2Appender name="schedulerxLog" timeFormat="yyyy-MM-dd'T'HH:mmZ" timeZone="UTC" ignoreExceptions="true"> <PatternLayout pattern="%d %-5level [%thread] %logger{0}: %msg"/> </SchedulerxLog4j2Appender> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console" /> </Root> <Logger name="schedulerx" level="info" additivity="false"> <AppenderRef ref="schedulerxLog" /> </Logger> </Loggers> </Configuration>修改業務代碼如下,使用Logger: schedulerx採集任務調度的日誌。
package com.hxm.test.processor; import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.JavaProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class HelloWorldJob3 extends JavaProcessor { private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { LOGGER.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
方法二:搜集所有業務日誌
該方法只需要配置Log4j檔案,不需要修改一行業務代碼。如果將SchedulerxLog配置在rootLogger裡,會讓所有日誌都通過SchedulerX採集,不僅搜尋速度較慢,而且業務日誌和任務調度日誌會混在一起,難以排查問題。配置如下:
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="off"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %m%n" /> </Console> <SchedulerxLog4j2Appender name="schedulerxLog" timeFormat="yyyy-MM-dd'T'HH:mmZ" timeZone="UTC" ignoreExceptions="true"> <PatternLayout pattern="%d %-5level [%thread] %logger{0}: %msg"/> </SchedulerxLog4j2Appender> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="Console" /> <AppenderRef ref="schedulerxLog" /> </Root> </Loggers> </Configuration>
Log4j Appender
方法一:單獨收集任務調度日誌
log4j.properties增加一個Appender和Logger。log4j.rootLogger = INFO,console log4j.logger.schedulerx=schedulerxLog log4j.appender.schedulerxLog=com.alibaba.schedulerx.worker.log.appender.SchedulerxLog4jAppender修改業務代碼如下,使用Logger: schedulerx採集任務調度的日誌。
package com.hxm.test.processor; import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.JavaProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class HelloWorldJob3 extends JavaProcessor { private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { logger.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
方法二:收集所有日誌
log4j.properties增加一個Appender,將這個Appender配置在rootLogger裡:log4j.rootLogger = INFO,console,schedulerxLog log4j.appender.schedulerxLog=com.alibaba.schedulerx.worker.log.appender.SchedulerxLog4jAppender
Logback Appender
SchedulerxLogbackAppender這個類在依賴的SDK schedulerx2-worker JAR包裡面,需要升級SchedulerX用戶端到最新版本。用戶端最新版本,請參見用戶端發布記錄。
方法一:單獨收集任務調度日誌
logback.xml增加一個Appender和Logger。<appender name="schedulerxLog" class="com.alibaba.schedulerx.worker.log.appender.SchedulerxLogbackAppender"> <timeFormat>yyyy-MM-dd'T'HH:mmZ</timeFormat> <timeZone>UTC</timeZone> </appender> <root level="INFO"> <appender-ref ref="CONSOLE" /> </root> <logger name="schedulerx" level="INFO"> <appender-ref ref="schedulerxLog"/> </logger>修改業務代碼如下,使用Logger: schedulerx採集任務調度的日誌。
package com.hxm.test.processor; import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.JavaProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class HelloWorldJob3 extends JavaProcessor { private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { LOGGER.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
方法二:收集所有日誌
logback.xml增加一個Appender,將其配置在rootLogger裡:<appender name="schedulerxLog" class="com.alibaba.schedulerx.worker.log.appender.SchedulerxLogbackAppender"> <timeFormat>yyyy-MM-dd'T'HH:mmZ</timeFormat> <timeZone>UTC</timeZone> </appender> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="schedulerxLog"/> </root>
查看輸出的日誌
登入分布式任務調度平台。
在左側導覽列單擊任務管理。
在工作清單中找到目標任務,在目標任務的操作列選擇,進入到任務執行個體記錄頁面。
在任務執行個體記錄頁面,單擊目標任務操作列的日誌。

日誌中關鍵詞的定義如下:
ip: 列印該日誌的執行機器。executionId: 本次任務執行個體的執行ID,格式為${jobId}_${jobInstanceId}_${taskId}。level: 日誌的層級。log:日誌的資訊。throwable: 應用拋出異常時,會列印該欄位。time:列印日誌的時間。
應用情境及示範
查詢業務失敗的原因
SchedulerX 2.0的Log Service可以收集任務的執行日誌和異常,包括Service的日誌都可以收集。
建立代碼。
建立任務代碼,配置使用SchedulerX列印日誌。
package com.hxm.test.processor; import com.alibaba.schedulerx.test.service.TestService; import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.JavaProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class HelloWorldJob extends JavaProcessor { /**使用SchedulerX收集日誌**/ private static final Logger LOGGER = LogManager.getLogger("schedulerx"); @Autowired private TestService testService; @Override public ProcessResult process(JobContext context) throws Exception { String parameters = context.getJobParameters(); String tokens[] = parameters.split(" "); int a = Integer.valueOf(tokens[0]); int b = Integer.valueOf(tokens[1]); int c = testService.doDivision(a, b); LOGGER.info("testService.doDivision finished, a={}, b={}, c={}", a, b, c); if (c < 0) { return new ProcessResult(false, "result=" + c); } return new ProcessResult(true); } }建立Service業務代碼,配置使用SchedulerX列印日誌。
package com.hxm.test.service; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.stereotype.Service; @Service("testService") public class TestServiceImpl implements TestService { /**使用SchedulerX收集日誌**/ private static final Logger LOGGER = LogManager.getLogger("schedulerx"); @Override public int doDivision(int a, int b) { try { LOGGER.info("start to do division c = " + a + "/" + b); int c = a/b; LOGGER.info("c=" + c); return c; } catch (Exception e) { LOGGER.error("", e); } return -1; } }
控制台配置任務。
根據代碼邏輯可知1除以0肯定會拋出異常。

任務運行一次後,通過任務執行個體列表查看日誌。

根據日誌內容,可得出失敗的原因是TestServiceImpl拋出了除0的異常。

查詢分布式任務失敗原因
SchedulerX 2.0的分布式任務用來執行批量任務,例如某個任務批次執行失敗了,您想查詢具體是哪個子任務失敗時,可執行如下操作:
建立任務代碼,配置使用SchedulerX列印日誌。
package com.hxm.test.processor; import java.util.ArrayList; import java.util.List; import com.alibaba.schedulerx.worker.domain.JobContext; import com.alibaba.schedulerx.worker.processor.MapJobProcessor; import com.alibaba.schedulerx.worker.processor.ProcessResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class TestMapJobProcessor extends MapJobProcessor { private static final Logger LOGGER = LogManager.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { String taskName = context.getTaskName(); String parameter = context.getJobParameters(); int dispatchNum = Integer.valueOf(parameter); if (isRootTask(context)) { LOGGER.info("start root task"); List<String> msgList = new ArrayList<>(); for (int i = 0; i <= dispatchNum; i++) { msgList.add("msg_" + i); } return map(msgList, "Level1Dispatch"); } else if (taskName.equals("Level1Dispatch")) { String task = (String)context.getTask(); if (task.equals("msg_23")) { LOGGER.error("msg={}, failed", task); return new ProcessResult(false); } else { LOGGER.info("msg={}, success", task); } return new ProcessResult(true); } return new ProcessResult(false); } }控制台配置任務並執行一次。

查看日誌。具體操作,請參見查看輸出的日誌。
在日誌中搜尋索引鍵,快速定位失敗的任務及原因。

根據關鍵字查詢歷史日誌
任務執行個體的記錄只保留最近60條。如果想排查歷史上任務失敗的原因,可以通過控制台左側導覽列的日誌查詢來檢索。日誌查詢支援根據任務ID、關鍵字和時間區間搜尋。

