ねらいリクエスト単位の処理時間ログと、稼働状態を1回のリクエストで確かめられる口を足します。
さわるファイル| 書く | src/main/java/com/example/order/config/WebConfig.javaaddInterceptors を追記して登録 |
| 新規 | src/main/java/com/example/order/config/RequestLoggingInterceptor.javaIDと処理時間。logback-spring.xml も新規 |
| 新規 | src/main/java/com/example/order/controller/HealthController.javaGET /api/health。HealthResponse も新規 |
手順1
考える
ログに出す3点、つまりリクエストIDをどこに持たせるか、処理時間をどこからどこまで測るか、MDC に入れた値をいつ消すかを手元に書き出します。あわせて返す JSON の形も決め、status、database.status、database.orderCount、memory.usagePercent の入れ子と型をここで固めます。
2
書く
claude を起動し、@WebConfig.java を付けて、リクエストIDと処理時間を出す RequestLoggingInterceptor の新規作成と /api/** への登録を依頼します。あわせて src\main\resources\logback-spring.xml を新規作成し、パターンを %d{HH:mm:ss.SSS} [%X{requestId}] %-5level %logger{36} - %msg%n にするところまで頼みます。
3
実行
プロジェクト直下(mvnw.cmd がある階層)で .\mvnw.cmd spring-boot:run を打ち、VSCode のターミナルを分割して2枚目から curl.exe http://localhost:8080/api/orders を打ちます。同じリクエストのログ行の角括弧に同一のIDが並び、終了行に処理時間のミリ秒が出るのを読みます。
4
答え合わせ
決めた JSON の形のまま /api/health を返す HealthController の新規作成を依頼し、差分に @Autowired のフィールドが混じっていないかを見てから承認します。Java が増えたので Ctrl+C で止めて .\mvnw.cmd spring-boot:run を打ち直し、curl.exe -s http://localhost:8080/api/health | jq . で database.orderCount が 10 になるかを確かめます。
できたら- curl.exe -s http://localhost:8080/api/health | jq . が JSON を返し、database.orderCount が 10 になる
- 1リクエストのログ行の角括弧に同じIDが入り、終了行に処理時間のミリ秒が出る
- 差分の依存が private final と @RequiredArgsConstructor で組まれている
考えることDB が落ちているとき、全体を DOWN にするか、database.status だけ DOWN にして status は UP のままにするか。
AI の出方返す JSON の形と入れ子は毎回ぶれます。先に自分で書いた形をそのまま貼って渡すと揃います。@Autowired のフィールドインジェクションで書いてくることがあるので、そのときはコンストラクタインジェクションに直して、と一言足してください。
D3-3+1リクエストで発行された SQL の本数を数えて、10件を超えたら WARN を出します。Hibernate の Statistics を使うと依存を増やさずに済みますが、既定は無効です。配布時点の src\main\resources\application.yml には generate_statistics の指定が無く、このままだと本数が常に 0 で WARN が出ません。spring.jpa.properties.hibernate.generate_statistics: true を足し、設定ファイルなので Ctrl+C で止めて .\mvnw.cmd spring-boot:run を打ち直します。しきい値は SQL_COUNT_THRESHOLD という定数に切り出してください。D1-4 で OrderDTO に明細を含める実装を終えていれば、受注一覧で SQL が11本になって WARN が出ます。未実装のままだと SQL は1本しか出ないので、しきい値を一時的に 1 へ下げて動作だけ確かめます。
くわしく(背景・詰まったときの対処)
このプロジェクトは Spring Boot Actuator を入れていません。アプリが生きているか、DB に繋がっているかを外から確かめる口が無い状態です。監視に GET /api/orders を使うと業務データを毎回読みに行くので、軽い専用の口を別に置きます。返す中身は status、application、version、database.status、database.orderCount、memory.used、memory.max、memory.usagePercent です。orderCount は配布データの受注件数と同じ 10 になります。
処理時間ログの方は、config パッケージの WebConfig に addInterceptors を足して登録します。HandlerInterceptor は、コントローラの処理の前後に共通処理を差し込む仕組みで、入り口の preHandle と出口の afterCompletion を使います。リクエストIDは MDC に入れます。MDC はログ出力ライブラリがスレッド単位で値を持つ置き場で、消し忘れると次のリクエストに前のIDが残ります。afterCompletion の最後に消す行が入っているかを、差分で必ず見てください。MDC に入れただけではログ行にIDは出ません。既定のログパターンに %X{requestId} が無いためで、logback-spring.xml を新しく作ってパターンを差し替えるところまでが1組です。
依存の受け取り方は2通りあります。private final のフィールドをコンストラクタで受ける形が規約で推奨、@Autowired をフィールドに付ける形が規約で禁止です。差分に @Autowired の行があれば直させてください。新しく作るのは RequestLoggingInterceptor、logback-spring.xml、HealthController、応答を組み立てる src\main\java\com\example\order\dto\HealthResponse.java の4本で、これに WebConfig への addInterceptors 追記が加わります。レスポンスは Map で組まず、record か DTO の専用型にします。JdbcTemplate の Bean が見つからないと言われたら、EntityManager のネイティブクエリで SELECT 1 を実行する形に直させます。jq が入っていない環境では、| jq . を外して curl.exe http://localhost:8080/api/health だけで中身を読めます。細かい打鍵と模範プロンプトは exercises\day3\exercise2-監視とセキュリティ.md にあります。
この口ができたら、Day1 で作った src\main\resources\static\dashboard.html から /api/health を呼び、自分の画面の上に UP と受注件数を並べられます。この画面ファイルはアプリを起動したまま書き換えられ、保存してブラウザを再読み込みすると新しい中身に差し替わります。表示を見て気に入らないところを claude に直させ、また再読み込みして見る、という往復をそのまま続けられます。止めて起動し直すのは Java か設定ファイルを書き換えたときだけです。
新規4本と追記1本を30分で通します。時間内に両方が届かないときは、先にヘルスチェックを動かしてください。処理時間ログは logback-spring.xml までを1組として、残った時間で足します。