メインコンテンツまでスキップ

ローカルデバッグガイド — Java

Last updated on July 14, 2026

注釈:本資料はAI技術を用いて翻訳されています。

このガイドでは、Java で記述された Extend Event Handler アプリのデバッグに固有の内容を扱います。環境セットアップ、VS Code のデバッグワークフロー、ログの読み方、よくある問題など一般的なデバッグの概念については、以下を参照してください。

Extend App テンプレートに基づく

このガイドに記載されているファイルパス、クラス名、設定ファイルは AccelByte Extend Event Handler Java テンプレートを参照しています。 プロジェクトで異なる名前を使用している場合でも、概念は同様に適用されます。パスをご自身のレイアウトに合わせて調整してください。


前提条件

インストール要件については、Java 言語セットアップガイドを参照してください。 加えて、ローカル開発中に受信イベントをシミュレートするために grpcurl が必要です。インストールと使用方法については、メインガイドの テスト用にイベントをトリガーするを参照してください。


プロジェクト構造

ファイル / クラス役割
src/main/java/net/accelbyte/Application.javaエントリーポイント — Spring Boot アプリケーションを起動します。
src/main/java/net/accelbyte/config/AppConfig.javaSpring 設定 — ITEM_ID_TO_GRANT を検証し、AccelByteSDK ビーンを作成します(起動時に loginClient() を呼び出します)。
src/main/java/net/accelbyte/service/LoginHandler.javauserLoggedIn イベントのビジネスロジック — 生成された gRPC スタブを拡張し、grantEntitlement を呼び出します。
src/main/java/net/accelbyte/service/ThirdPartyLoginHandler.javauserThirdPartyLoggedIn イベントのビジネスロジックLoginHandler と同じパターンです。
src/main/java/net/accelbyte/service/EntitlementService.javaAGS Fulfillment API を呼び出してユーザーにアイテムを付与する共有 Spring サービスです。
src/main/java/net/accelbyte/grpc/DebugLoggerServerInterceptor.javaplugin.grpc.server.interceptor.debug-logger.enabled=true の場合に、すべてのリクエスト/レスポンスをログに記録するオプションの gRPC インターセプターです。
src/main/java/net/accelbyte/grpc/ExceptionServerInterceptor.java未処理の例外を適切な gRPC ステータスコードに変換する gRPC インターセプターです。
src/main/resources/application.ymlメインの Spring Boot 設定 — 環境変数をアプリケーションプロパティにマッピングします。
src/main/resources/application-local.ymlローカル専用プロファイルのオーバーライド — デバッグロガーインターセプターを有効化し、logback-spring-local.xml を使用します。
src/main/proto/AGS イベントメッセージの形式を記述する .proto ファイルです。
build.gradleビルドファイル — 依存関係、bootRun タスク(OTEL エージェント付き)、bootJar タスクを定義します。

ポート番号application.yml と Spring Boot のデフォルトで設定):

ポート用途
6565gRPC サーバー — Kafka Connect からのイベントとシミュレートされた grpcurl 呼び出しを受信します
8080Prometheus メトリクスエンドポイント(/metrics

サービスをローカルで実行する

ターミナルから実行する

# .env ファイルからすべての変数をエクスポート
export $(grep -v '^#' .env | xargs)

./gradlew bootRun

bootRun タスク(build.gradle に定義)は、自動的に AWS OpenTelemetry エージェントをアタッチし、デバッグロガーインターセプターを有効にする local Spring プロファイルを有効化します。

サービスが起動していることを確認する

Logstash JSON エンコーダーによって整形された、次のようなログ出力が表示されるはずです。

{"@timestamp":"...","level":"INFO","message":"Starting Application using Java 17..."}
{"@timestamp":"...","level":"INFO","message":"LoginHandler initialized"}
{"@timestamp":"...","level":"INFO","message":"ThirdPartyLoginHandler initialized"}
{"@timestamp":"...","level":"INFO","message":"DebugLoggerServerInterceptor initialized"}
{"@timestamp":"...","level":"INFO","message":"Started Application in 3.x seconds"}

gRPC リフレクションが動作していることを確認します。

grpcurl -plaintext localhost:6565 list

期待される出力 — 登録されているサービスの一覧:

accelbyte.iam.account.v1.UserAuthenticationUserLoggedInService
accelbyte.iam.account.v1.UserAuthenticationUserThirdPartyLoggedInService
grpc.health.v1.Health
grpc.reflection.v1alpha.ServerReflection

デバッガーをアタッチする

VS Code(推奨)

リポジトリにはまだ .vscode/launch.json が含まれていないため、以下のコマンドで作成します。

mkdir -p .vscode

次に、以下の内容で .vscode/launch.json を作成します。

{
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Debug: Service",
"request": "attach",
"hostName": "localhost",
"port": 5005
}
]
}

手順:

汎用ガイドのデバッガーのアタッチの手順に従ってください。 Java の場合、デバッガーは直接起動するのではなく JDWP 経由でアタッチします。まず JDWP デバッグエージェント付きでサービスを起動します。

export $(grep -v '^#' .env | xargs)
./gradlew bootRun --jvmArgs="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005"

出力に Started Application in が表示されるまで待ち、Run and Debug パネルを開いて "Debug: Service" を選択し、F5 を押してアタッチします。

Java デバッガーは JDWP 経由で接続します。アタッチされると、任意の .java ファイルに設定したブレークポイントで実行が一時停止します。

その他の IDE — JDWP アタッチモード

上記と同様に JDWP エージェント付きでサービスを起動し、IDE を localhost:5005 にアタッチするように設定します。IntelliJ IDEA の場合は Remote JVM Debug 設定、他の IDE では同等の設定を使用してください。

起動時にサスペンドする(@PostConstruct や静的初期化子内のブレークポイント)

アプリケーションが初期化される前に一時停止させたい場合(例: AppConfig をデバッグする場合)は、suspend=n の代わりに suspend=y を使用します。JVM はデバッガーが接続するまでフリーズします。

./gradlew bootRun --jvmArgs="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005"

ブレークポイントを設定する場所

注目すべきロジックの大部分は、サービスクラスと設定に含まれています。まずはそこから調べ始めてください。

調査したい内容ファイルと位置
到着するあらゆるログインイベントLoginHandler.javaonMessage の先頭
到着するサードパーティログインイベントThirdPartyLoginHandler.javaonMessage の先頭
エンタイトルメント付与ロジックEntitlementService.javagrantEntitlement の内部
SDK ログイン / 認証情報の検証AppConfig.javaprovideAccelbyteSdk 内、loginClient() の後
ITEM_ID_TO_GRANT の検証AppConfig.javavalidateItemIdToGrant の内部
すべての生の gRPC リクエストを確認DebugLoggerServerInterceptor.javaForwardingServerCallListeneronMessage の内部

受信イベントのペイロードを確認する

デバッガーが onMessage の内部で一時停止したとき、request パラメーターにはイベント全体が含まれます。Variables パネルで展開すると、イベントタイプに応じて userIdnamespaceplatformId などのすべてのフィールドを確認できます。

条件付きブレークポイントの構文

ブレークポイントを右クリック → Edit Breakpoint → 次のような Java 式を入力します。

request.getUserId().equals("test-user-001")

条件付きブレークポイントの構文の詳細な例については、 Java 言語ガイドを参照してください。


テスト用にイベントをトリガーする

イベントシミュレーションのオプションと grpcurl コマンドについては、メインガイドの テスト用にイベントをトリガーするを参照してください。

サービスメソッドを記述する

proto メソッドの正確なフィールド名を知る必要がある場合は、grpcurl describe を使用します。

grpcurl -plaintext localhost:6565 \
describe accelbyte.iam.account.v1.UserAuthenticationUserLoggedInService.OnMessage

これにより、メソッドの完全な proto 定義が出力されます。-d ペイロードにどのフィールドを含めるべきかを正確に知りたい場合に便利です。


ログを読む

jq を使ったログのフィルタリングについては、 Java 言語ガイドを参照してください。

ログ内のトレース ID

application.yml は、OpenTelemetry のトレースコンテキストを含めるようにログパターンを設定しています。

trace_id=%mdc{trace_id} span_id=%mdc{span_id} trace_flags=%mdc{trace_flags} %5p

grpcurl リクエストを送信した後、トレース ID で grep すると、その 1 つのイベントに関するすべてのログ行を確認できます。

./gradlew bootRun 2>&1 | jq 'select(.trace_id != null and .trace_id != "") | {trace_id, level, message}'

デバッグロガーインターセプターを有効化する

DebugLoggerServerInterceptor はすべての生の gRPC リクエストとレスポンスをログに記録しますが、デフォルトでは無効になっています。 有効にするには、application-local.yml でプロパティを設定する(すでに設定済み)か、コマンドラインで渡します。

./gradlew bootRun -Dplugin.grpc.server.interceptor.debug-logger.enabled=true

有効にすると、各呼び出しで以下がログに記録されます。

{"level":"INFO","message":"Request path: accelbyte.iam.account.v1.UserAuthenticationUserLoggedInService/OnMessage"}
{"level":"INFO","message":"Request headers: ..."}
{"level":"INFO","message":"Request message: userId: \"test-user-001\" namespace: \"mygame\""}

Java 固有のトラブルシューティング

サービスが起動しない: ITEM_ID_TO_GRANT is not configured

症状:

Caused by: java.lang.IllegalArgumentException: Required envar ITEM_ID_TO_GRANT is not configured

原因: ITEM_ID_TO_GRANT 環境変数が空であるか、設定されていません。

対処法: .env ファイルの ITEM_ID_TO_GRANT に、自分のネームスペース内で公開されているストアの有効なアイテム ID を設定し、再エクスポートしてから再起動してください。


サービスが起動しない: failed to sdk.loginClient()

症状:

Caused by: org.springframework.web.server.ServerErrorException: failed to sdk.loginClient()

原因: AppConfig.provideAccelbyteSdk() が AGS への認証に失敗しました。これは AB_BASE_URLAB_CLIENT_ID、または AB_CLIENT_SECRET が誤っているか、設定されていない場合に発生します。

対処法:

  1. AB_BASE_URL に到達可能かを確認します: curl "$AB_BASE_URL/iam/v3/public/config"
  2. AB_CLIENT_IDAB_CLIENT_SECRET が設定されており、既存の OAuth クライアントと一致していることを確認します。
  3. loginClient() が呼び出される前の SDK の状態を確認するために、AppConfig.provideAccelbyteSdk() にブレークポイントを設定します。

デバッガーがブレークポイントで一時停止しない

症状: アタッチは成功するものの、ブレークポイントが一度もヒットしません。

原因と対処法:

  • 古い .class ファイル — デバッガーがロードしたクラスがソースと一致していません。 ./gradlew clean bootRun --jvmArgs="..." を実行して、完全な再コンパイルを強制してください。
  • ポートの誤り — サービスが 5005 で待機していることを確認します: ss -tlnp | grep 5005
  • ホットスワップの不整合 — Java デバッガーがサポートするホットスワップには限りがあります。アタッチ後にソースを編集した場合は、サービスを再起動して再アタッチしてください。

ポート競合を確認する

Address already in use が表示された場合:

ss -tlnp | grep -E '6565|8080|5005'

古いプロセスを終了させてから、再度起動してください。


grpcurl が "Failed to dial" を返す

症状:

Failed to dial target host "localhost:6565": ...

原因: gRPC サーバーがまだ起動していない、起動時にクラッシュした、または別のポートで待機しています。

対処法:

  1. サービスログで ERROR 行を確認し、Spring の起動失敗を探します。
  2. ポート 6565 が開いていることを確認します: ss -tlnp | grep 6565
  3. grpcurl -plaintext localhost:6565 list を再実行します。成功すればサーバーは起動しています。

ハンドラーが INTERNAL を返すが ERROR ログが表示されない

症状: grpcurlCode: Internal を報告しますが、ログに ERROR 行が表示されません。

原因: 例外が構造化ロガーに到達する前に ExceptionServerInterceptor によって捕捉されているか、ログレベルによってフィルタリングされています。

対処法:

  1. 例外が伝播する前に検査するために、EntitlementService.grantEntitlementcatch (Exception e) ブロックにブレークポイントを設定します。
  2. 一時的にログレベルを下げます。application-local.ymllogging.level.net.accelbyte=DEBUG を追加して再起動してください。

proto の変更が反映されない

症状: src/main/proto/ 内のファイルを編集しましたが、変更が実行時に反映されません。

原因: 生成された Java スタブが再生成されていません。

対処法: クリーンビルドを実行して proto のコンパイルをトリガーします。

./gradlew clean build

その後、サービスを再起動してください。


AI アシスタンス

アプリテンプレートには、 .claude/skills/debugging-guide/SKILL.mdにある Claude エージェントスキルが同梱されています。 スキルファイル全体を自分のリポジトリにコピーし、AI アシスタントで有効化してください。

スキルの全内容とプロンプトのヒントについては、メインガイドの AI アシスタンスセクションを参照してください。


参考資料