スケジュールされたジョブが失敗したり、予期しない結果を生成したりした場合、根本原因を特定するには、一元管理され検索可能なログが必要です。これは特に、複数のワーカーで実行される分散ジョブの場合に重要です。SchedulerX 2.0 の Simple Log Service は、分散ジョブを含むすべてのジョブタイプから実行ログを収集し、SchedulerX コンソールで検索可能にします。この統合をセットアップするには、Log4j2、Log4j、または Logback の設定に SchedulerX のアペンダーを追加します。
事前準備
以下が準備できていることを確認してください:
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 つの収集戦略が利用可能です:
| 戦略 | スコープ | トレードオフ |
|---|---|---|
| ジョブログのみ | schedulerx ロガーに書き込まれたログ | ジョブログをアプリケーションログから分離します。ほとんどのユースケースで推奨されます。 |
| すべてのアプリケーションログ | ルートロガー経由のすべてのログ | すべてをキャプチャしますが、ジョブログが一般的なアプリケーション出力と混在し、クエリ効率が低下します。 |
Log4j2
ジョブログのみを収集 (推奨)
Log4j2 設定ファイルに SchedulerX アペンダーと専用の
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" /> </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 コンソールにログインします。
左側のナビゲーションウィンドウで、タスク管理 をクリックします。
対象のジョブを見つけ、操作 列で その他 > 履歴 を選択します。
タスクインスタンスの履歴 パネルで、対象のジョブインスタンスを見つけ、操作 列の ログ をクリックします。
ログフィールド
| フィールド | 説明 |
|---|---|
ip | ログエントリを生成したワーカーの IP アドレス。 |
executionId | 実行 ID。フォーマットは ${jobId}_${jobInstanceId}_${taskId} です。この ID を使用して、分散タスク間のログを関連付けます。 |
level | ログレベル (INFO、WARN、ERROR など)。 |
log | ログの内容。 |
throwable | 例外のスタックトレース。アプリケーションがエラーをスローした場合にのみ存在します。 |
time | ログエントリのタイムスタンプ。 |
キーワードによるログのクエリ
SchedulerX 2.0 は、ジョブインスタンスの最新 60 件の実行レコードのみを保持します。古い実行を検索するには、左側のナビゲーションウィンドウで ログクエリ をクリックします。ログクエリ ページで、ジョブ 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に設定して、ゼロ除算エラーをトリガーします。
ジョブをトリガーし、タスクインスタンスの履歴 パネルを開き、ログを確認します。ログには、
TestServiceImplがArithmeticException("/ by zero") をスローし、これによりジョブが失敗したことが示されます。
分散ジョブの失敗の診断
分散ジョブは、バッチ処理のために複数のワーカーにサブタスクをディスパッチします。サブタスクが失敗した場合は、ログを検索して、失敗したタスクとその原因を特定します。
メッセージをディスパッチするマップジョブプロセッサを作成します。この例では、
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) と根本原因を特定します。