ローカルデバッグガイド — Java
注釈:本資料はAI技術を用いて翻訳されています。
このガイドでは、Java で記述された Extend Event Handler アプリのデバッグに固有の内容を扱います。環境セットアップ、VS Code のデバッグワークフロー、ログの読み方、よくある問題など一般的なデバッグの概念については、以下を参照してください。
- Extend ローカルデバッグガイド — すべての Extend アプリタイプに共通する概念
- Java 言語セットアップガイド — Java の前提条件、JVM リモートデバッグ、jq、Java 固有のトラブルシューティング
このガイドに記載されているファイルパス、クラス名、設定ファイルは AccelByte Extend Event Handler Java テンプレートを参照しています。 プロジェクトで異なる名前を使用している場合でも、概念は同様に適用されます。パスをご自身のレイアウトに合わせて調整してください。
前提条件
インストール要件については、Java 言語セットアップガイドを参照してください。 加えて、ローカル開発中に受信イベントをシミュレートするために grpcurl が必要です。インストールと使用方法については、メインガイドの テスト用にイベントをトリガーするを参照してください。
プロジェクト構造
| ファイル / クラス | 役割 |
|---|---|
src/main/java/net/accelbyte/Application.java | エントリーポイント — Spring Boot アプリケーションを起動します。 |
src/main/java/net/accelbyte/config/AppConfig.java | Spring 設定 — ITEM_ID_TO_GRANT を検証し、AccelByteSDK ビーンを作成します(起動時に loginClient() を呼び出します)。 |
src/main/java/net/accelbyte/service/LoginHandler.java | userLoggedIn イベントのビジネスロジック — 生成された gRPC スタブを拡張し、grantEntitlement を呼び出します。 |
src/main/java/net/accelbyte/service/ThirdPartyLoginHandler.java | userThirdPartyLoggedIn イベントのビジネスロジック — LoginHandler と同じパターンです。 |
src/main/java/net/accelbyte/service/EntitlementService.java | AGS Fulfillment API を呼び出してユーザーにアイテムを付与する共有 Spring サービスです。 |
src/main/java/net/accelbyte/grpc/DebugLoggerServerInterceptor.java | plugin.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 のデフォルトで設定):
| ポート | 用途 |
|---|---|
6565 | gRPC サーバー — Kafka Connect からのイベントとシミュレートされた grpcurl 呼び出しを受信します |
8080 | Prometheus メトリクスエンドポイント(/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.java — onMessage の先頭 |
| 到着するサードパーティログインイベント | ThirdPartyLoginHandler.java — onMessage の先頭 |
| エンタイトルメント付与ロジック | EntitlementService.java — grantEntitlement の内部 |
| SDK ログイン / 認証情報の検証 | AppConfig.java — provideAccelbyteSdk 内、loginClient() の後 |
ITEM_ID_TO_GRANT の検証 | AppConfig.java — validateItemIdToGrant の内部 |
| すべての生の gRPC リクエストを確認 | DebugLoggerServerInterceptor.java — ForwardingServerCallListener の onMessage の内部 |
受信イベントのペイロードを確認する
デバッガーが onMessage の内部で一時停止したとき、request パラメーターにはイベント全体が含まれます。Variables パネルで展開すると、イベントタイプに応じて userId、namespace、platformId などのすべてのフィールドを確認できます。
条件付きブレークポイントの構文
ブレークポイントを右クリック → 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_URL、AB_CLIENT_ID、または AB_CLIENT_SECRET が誤っているか、設定されていない場合に発生します。
対処法:
AB_BASE_URLに到達可能かを確認します:curl "$AB_BASE_URL/iam/v3/public/config"。AB_CLIENT_IDとAB_CLIENT_SECRETが設定されており、既存の OAuth クライアントと一致していることを確認します。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 サーバーがまだ起動していない、起動時にクラッシュした、または別のポートで待機しています。
対処法:
- サービスログで
ERROR行を確認し、Spring の起動失敗を探します。 - ポート 6565 が開いていることを確認します:
ss -tlnp | grep 6565。 grpcurl -plaintext localhost:6565 listを再実行します。成功すればサーバーは起動しています。
ハンドラーが INTERNAL を返すが ERROR ログが表示されない
症状: grpcurl が Code: Internal を報告しますが、ログに ERROR 行が表示されません。
原因: 例外が構造化ロガーに到達する前に ExceptionServerInterceptor によって捕捉されているか、ログレベルによってフィルタリングされています。
対処法:
- 例外が伝播する前に検査するために、
EntitlementService.grantEntitlementのcatch (Exception e)ブロックにブレークポイントを設定します。 - 一時的にログレベルを下げます。
application-local.ymlにlogging.level.net.accelbyte=DEBUGを追加して再起動してください。
proto の変更が反映されない
症状: src/main/proto/ 内のファイルを編集しましたが、変更が実行時に反映されません。
原因: 生成された Java スタブが再生成されていません。
対処法: クリーンビルドを実行して proto のコンパイルをトリガーします。
./gradlew clean build
その後、サービスを再起動してください。
AI アシスタンス
アプリテンプレートには、
.claude/skills/debugging-guide/SKILL.mdにある Claude エージェントスキルが同梱されています。
スキルファイル全体を自分のリポジトリにコピーし、AI アシスタントで有効化してください。
スキルの全内容とプロンプトのヒントについては、メインガイドの AI アシスタンスセクションを参照してください。