スケジュールされたジョブが失敗した場合や予期しない結果を生成した場合、根本原因を特定するには、一元化された検索可能なログが必要です。これは、複数のワーカーで実行される分散ジョブでは特に重要です。SchedulerX 2.0 の Simple Log Service は、分散ジョブを含むすべてのジョブタイプから実行ログを収集し、SchedulerX コンソールで検索できます。連携を設定するには、SchedulerX アペンダーを Log4j2、Log4j、または Logback の設定に追加します。
前提条件
以下が用意されていることを確認してください:
Simple Log Service を有効化した SchedulerX 2.0 Professional Edition

ログは、有効化後最大 2 週間保持されます。有効期限が切れたログは自動的に削除されます。
ステップ 1:SchedulerX エージェントの更新
SchedulerX エージェントを最新バージョンに更新します。バージョンの詳細については、「リリースノート」をご参照ください。
アプリケーションが Spring Boot Starter を使用している場合は、次の依存関係を pom.xml に追加します:
<dependency>
<groupId>com.aliyun.schedulerx</groupId>
<artifactId>schedulerx2-spring-boot-starter</artifactId>
<version>${SchedulerX クライアントの最新バージョン}</version>
</dependency>ステップ 2:ログアペンダーの設定
SchedulerX は、Log4j2、Log4j、および Logback 用のアペンダーを提供します。お使いのロギングフレームワークに対応するセクションを選択してください。
2 つの収集戦略を利用できます:
戦略 | 範囲 | トレードオフ |
ジョブのみのログ |
| ジョブログをアプリケーションログから分離します。ほとんどのユースケースで推奨します。 |
すべてのアプリケーションログ | ルートロガーを介したすべてのログ | すべてをキャプチャしますが、ジョブログが一般的なアプリケーション出力と混在し、クエリ効率が低下します。 |
Log4j2
ジョブのみのログの収集 (推奨)
SchedulerX アペンダーと専用の
schedulerxロガーを Log4j2 設定ファイルに追加します:<?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>ジョブプロセッサで、
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 { // "schedulerx" ロガーを使用して Simple Log Service にログを送信します private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { logger.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
すべてのアプリケーションログの収集
すべてのログを収集するには、専用ロガーの代わりに schedulerxLog アペンダーをルートロガーに追加します:
<?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
ジョブのみのログの収集 (推奨)
アペンダーと専用の
schedulerxロガーをlog4j.propertiesに追加します:log4j.rootLogger = INFO,console log4j.logger.schedulerx=schedulerxLog log4j.appender.schedulerxLog=com.alibaba.schedulerx.worker.log.appender.SchedulerxLog4jAppenderジョブプロセッサで、
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 { // "schedulerx" ロガーを使用して Simple Log Service にログを送信します private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { logger.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
すべてのアプリケーションログの収集
すべてのログを収集するには、schedulerxLog アペンダーを log4j.properties のルートロガーに追加します:
log4j.rootLogger = INFO,console,schedulerxLog
log4j.appender.schedulerxLog=com.alibaba.schedulerx.worker.log.appender.SchedulerxLog4jAppenderLogback
SchedulerxLogbackAppender は schedulerx2-worker.jar にパッケージ化されています。このアペンダーを設定する前に、SchedulerX エージェントを最新バージョンに更新してください。バージョンの詳細については、「リリースノート」をご参照ください。
ジョブのみのログの収集 (推奨)
アペンダーと専用の
schedulerxロガーをlogback.xmlに追加します:<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>ジョブプロセッサで、
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 { // "schedulerx" ロガーを使用して Simple Log Service にログを送信します private static final Logger logger = LoggerFactory.getLogger("schedulerx"); @Override public ProcessResult process(JobContext context) throws Exception { logger.info("hello HelloWorldJob3"); return new ProcessResult(true); } }
すべてのアプリケーションログの収集
すべてのログを収集するには、schedulerxLog アペンダーを logback.xml のルートロガーに追加します:
<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>ステップ 3:ジョブログの表示
SchedulerX コンソールにログインします。
左側のナビゲーションペインで、[Task Management] をクリックします。
対象のジョブを見つけ、[Operation] 列で [more] > [Historical records] を選択します。
[Task instance records] パネルで、対象のジョブインスタンスを見つけ、[Operation] 列の [Log] をクリックします。
ログフィールド
フィールド | 説明 |
| ログエントリを出力したワーカーの IP アドレス。 |
| 実行 ID は |
| INFO、WARN、ERROR などのログレベル。 |
| ログの内容。 |
| 例外のスタックトレース。アプリケーションがエラーをスローした場合にのみ記録されます。 |
| ログエントリのタイムスタンプ。 |
キーワードによるログのクエリ
SchedulerX 2.0 は、ジョブインスタンスの最新 60 件の実行履歴のみを保持します。過去の実行を検索するには、左側のナビゲーションペインで [Log Query] をクリックします。[Log Query] ページで、ジョブ ID、キーワード、または時間範囲でフィルタリングします。
トラブルシューティングの例
ジョブの失敗の診断
Simple Log 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" ロガーを使用して Simple Log Service にログを送信します 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); } }サービスクラスを作成します:
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" ロガーを使用して Simple Log Service にログを送信します 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; } }SchedulerX コンソールでジョブを設定します。ジョブパラメータを
1 0に設定して、ゼロ除算エラーをトリガーします。
ジョブをトリガーし、[Task instance records] パネルを開いてログを確認します。ログから、
TestServiceImplがArithmeticException("/ by zero") をスローし、ジョブが失敗したことがわかります。
分散ジョブの失敗の診断
分散ジョブは、バッチ処理のために複数のワーカーにサブタスクをディスパッチします。サブタスクが失敗した場合は、ログを検索して、失敗したタスクとその原因を特定します。
メッセージをディスパッチする map ジョブプロセッサを作成します。この例では、
msg_23は意図的に失敗するように設定されています: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); } }SchedulerX コンソールでジョブを設定し、トリガーします。

ログビューアーを開きます。手順については、「ステップ 3:ジョブログの表示」をご参照ください。
failedなどのキーワードで検索して、失敗したサブタスク (msg_23) と根本原因を特定します。