はじめに
新卒1年目のhirotoです
今回は研修で実装した、Spring BootでJSON形式のログを出力する方法を紹介します。本記事では「画面表示処理の開始・終了」を例にしています。
技術スタック
- 言語:Java(JDK 21)
- ビルドツール:Gradle 9.6.1
- フレームワーク:Spring Boot 4.1.0
- テンプレートエンジン:Thymeleaf
- DB:Postgres 15.18
参考にした記事
Java + SLF4J + Logback によるログ出力のサンプルコード
ログとは
ログとは、アプリケーション内で発生した出来事を記録するものです。
例えば
- ユーザーがログインした
- 商品登録処理が開始した
- エラーが発生した
などを記録します。
ログにはさまざまな種類があります。
- 操作ログ
- アプリケーションログ
- エラーログ
- アクセスログ
本記事では、SLF4J + Logbackを利用したアプリケーションログの出力方法を紹介します。
今回の実装
SLF4JというロギングファサードとLogbackというロギングフレームワークを利用して実装しました。
出力方法としては、標準出力にテキストで表示し、ログファイルとしてJSON形式で出力しています
実装方法
学習用設定であり、本番では保存権限・保持期間・暗号化・集中管理を設計する必要があります
ディレクトリ構成(初学者向け)
project
├─ logs
│ ├─ app.log //現在出力中のログ
│ └─ app-2026-07-01.log //ローテーション後のログ
├─ src
│ └─ main
│ ├─ java
│ │ └─ package
│ │ ├─ WebController.java
│ │ └─ // その他ファイル
│ └─ resources
│ ├─ application.properties
│ └─ logback-spring.xml ←これがロギング設定用のファイル
└─ build.gradle
gradleファイルの設定
Spring Boot StarterにはSLF4JとLogbackが標準で含まれています。今回は、Logbackの設定ファイルからJSON形式を細かく設定するために、logstash-logback-encoderを追加します。
今回の環境では、依存関係に含まれるLogbackおよびSLF4Jのバージョン競合を避けるため、logstash-logback-encoder側の依存関係を除外しています。環境によっては除外せずに動作するため、まずは通常の依存関係追加で確認してください。
競合回避については以前別の記事として作成しました
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation('net.logstash.logback:logstash-logback-encoder:8.0') {
exclude group: 'ch.qos.logback', module: 'logback-classic'
exclude group: 'ch.qos.logback', module: 'logback-core'
exclude group: 'org.slf4j', module: 'slf4j-api'
}
//...その他設定
}
ログの出力形式の設定
ログの出力形式を設定するためにはlogback-spring.xmlというファイルをresources直下に作成してその中で設定していきます
Spring Bootではresources配下にあるlogback-spring.xmlを起動時に自動で読み込みます。
- コンソール出力のロギング設定
-
appender name="STDOUT"で標準出力の設定 -
<charset>UTF-8</charset>で文字コードをUTF-8に指定 -
<pattern>で出力するログメッセージのフォーマットパターンを指定
-
- ログファイル出力のロギング設定
-
<appender name="APPLICATION_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">でファイル出力とローテーションの設定 -
rollingPolicyはログファイルを一定条件(日付やサイズなど)で切り替える設定 -
fileNamePatternはバックアップファイルの命名ルール(日付パターン)を指定 -
maxHistoryはバックアップしたログファイルを保持する日数を指定します(TimeBasedRollingPolicyの日次ローテーションの場合)
-
- 出力範囲の指定
-
<root level="INFO">と設定することでINFOレベル以上のログを出力する設定にしています。- TRACE:処理の詳細な流れを確認したいとき
- DEBUG:開発中のデバッグ情報
- INFO:通常の処理状況
- WARN:処理は継続できるが注意が必要
- ERROR:エラーが発生した場合
-
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- コンソール出力のロギング設定 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<charset>UTF-8</charset>
<pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level [%thread] - %msg%n</pattern>
</encoder>
</appender>
<!-- logsフォルダに出力する設定 -->
<appender name="APPLICATION_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/app.log</file>
<!-- ログを新しく切り替える時のバックアップファイルの設定 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/app-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="APPLICATION_LOG" />
</root>
</configuration>
ソースコードでログ出力の設定
実際のソースコードでログを出力していきます。今回は元の研修で扱っていた初期表示画面の表示を行うController層に適用したものを紹介します。
import java.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class WebController {
// ロガーの設定
// Loggerインスタンスを作成し、logger.info()などのメソッドからログを出力できるようになります。
private final Logger logger = LoggerFactory.getLogger(WebController.class);
@GetMapping(value = "/")
public String index(Model model) {
logger.info("index画面の表示処理を開始します");
model.addAttribute("message","ようこそ");
model.addAttribute("datetime",LocalDateTime.now());
logger.info("index画面の表示処理を完了しました");
return "index";
}
}
出力結果
標準出力
2026/07/27 10:57:26 INFO [http-nio-8080-exec-4] - index画面の表示処理を開始します
2026/07/27 10:57:26 INFO [http-nio-8080-exec-4] - index画面の表示処理を完了しました
ファイル出力:1行ごとに1つのJSONオブジェクトを出力する形式
{"@timestamp":"2026-07-27T10:57:26.174183+09:00","@version":"1","message":"index画面の表示処理を開始します","logger_name":"com.example.demo.controller.WebController","thread_name":"http-nio-8080-exec-4","level":"INFO","level_value":20000}
{"@timestamp":"2026-07-27T10:57:26.174183+09:00","@version":"1","message":"index画面の表示処理を完了しました","logger_name":"com.example.demo.controller.WebController","thread_name":"http-nio-8080-exec-4","level":"INFO","level_value":20000}
JSON形式で出力するメリット
JSON形式でログを出力すると、ログの情報を項目ごと(キーと値)に管理できます。
例えば、今回出力されているログには次のような項目があります。
-
@timestamp:ログの出力日時 -
level:ログレベル -
logger_name:ログを出力したクラス -
thread_name:実行スレッド -
message:ログメッセージ
このように項目が分かれているため、
-
levelがERRORのログだけを検索する -
logger_nameごとにログを集計する -
@timestampを利用して特定時間帯のログを抽出する
といった検索・分析がしやすくなります。
ログへ出力する情報を設計する際の注意点
ログは障害調査や運用に役立つ一方で、機密情報や個人情報が含まれてしまうと情報漏えいのリスクにつながります。そのため、「調査に必要な情報」と「出力すべきではない情報」を切り分けて設計することが重要です。
例えば、次のような情報はそのままログへ出力しないようにします。
- パスワード
- アクセストークン
- APIキー
- セッションID
- クレジットカード情報
- 個人情報(氏名・住所・電話番号・メールアドレスなど)
一方で、調査に必要な情報は、機密情報を含まない形で出力するとよいでしょう。
例えば、次のような個人情報を含まない情報を記録しておくと、障害調査やログ検索に役立ちます。
- リクエストID
- エラーコード
- 処理時間
- 操作対象のID
- 必要に応じた追跡用の内部識別子(個人に直接紐づかない形に加工したもの)
ログを設計する際は、「何でも出力する」のではなく、「調査に必要な情報だけを、安全な形で出力する」という考え方が重要です。
まとめ
今回はSLF4JとLogbackを利用して、次の処理を実装しました。
- コンソールへのテキスト形式のログ出力
- ファイルへのJSON形式のログ出力
- 日付によるログローテーション
JSON形式で出力しておくことで、将来的にElastic StackやCloudWatch Logsなどのログ管理基盤とも連携しやすくなります。
今回は基本的なログ出力を扱いましたが、今後は、個人情報を含めずに調査しやすいログ項目をどう設計するかや、必要に応じたマスキング・ハッシュ化、クラウド環境での安全な収集・検索方法についても学んでいきたいと思います。