2021/9/4
こんにちは。前回はDBからデータ取得して一覧画面に表示させるとこまでできましたので、今回はログの出力を追加したいと思います。
ログを出力する上で必要なものをネットからMavenを使って取得しましょう。
今回はAOPを使用してメソッド実行前後でログを出力したいと思いますので、
spring-boot-starter-aopを使用します。
pom.xmlのdependenciesタグに以下を追加してください。
/demo/pom.xml
まず、開発用のプロファイルを追加し、開発環境に合わせてログ情報を出力できるようにします。application.propertiesに"spring.profiles.active=dev"を追記すると、開発(dev)用のプロファイルとしてapplication-dev.propertiesを読み込めるようになります。
/demo/src/main/resources/application.properties
開発(dev)プロファイル用の設定としてapplication-dev.propertiesを新規に作成します。名前に-devを追加したファイルを作成してください。
/demo/src/main/resources/application-dev.properties
開発環境ではspringframework.webのログのレベルをERRORに、mybatisの実行SQLを取得するため、com.example.demo.mapperのDEBUGに設定しました。
ログのレベルにはTRACE、DEBUG、INFO、WARN、ERRORがあり、エラーログ情報のみ欲しいときはERRORを、詳細なログが欲しいときはDEBUGを指定することができます。
次に、ログをコンソールの標準出力だけでなく、ファイル出力したいのでSpring Bootに標準でついているlogbackの設定を加えましょう。
/demo/src/main/resources/logback-spring.xml
appenderは、ログの出力先を指定するものでch.qos.logback.core.ConsoleAppenderクラスを設定しているSTDOUTの方が標準出力のコンソールへ出力します。patternタグのlevelはログのレベル、messageはロギングイベントに関連付けられたメッセージを表示します。
一方、RollingFileAppenderクラスを設定しているAPPLIATION_LOGはファイルへの出力を行います。
それでは、確認のため前回作成したUserControllerに、usersテーブルで取得したデータをログ出力できるようにしてみます。25行目のLoggerFactory.getLogger(this.getClass())でロガーを呼び出し、44行目でmodelに設定されたusersテーブルの情報を表示しています。
logger.infoはログレベルINFOでログ出力します。エラーならlogger.errorになります。
/demo/src/main/java/com/example/demo/controller/UserController.java
AOP(Aspect Oriented Programming):アスペクト指向プログラミングは、ログやキャッシュなど共通的に使う処理(横断的な関心事)を、主要な処理と分離させて記述する開発手法です。分離した共通処理は実行した処理の前後で呼び出すことができます。こうすることで開発者は自分の作業に集中することができます。
技術的には@Aspectと@Componentのアノテーションをクラスに加えることでSpringコンテナにBeanとして外出しします。これも前回やった依存性の注入(DI)のひとつといえるでしょう。
その他、
JoinPoint : 横断的な処理を挿入するメソッド側の情報を取得できます 。getTarget().getClass().toString()で実行しているメソッドのクラス名、
getSignature().getName()で実行しているメソッドのメソッド名を取得できます。
Advice : @Beforeや@Afterといったアノテーションを共通処理を行うメソッドに記述することで処理実行前後に共通処理を行うことができます(今回使用している@AfterReturningは、正常終了したときのみ戻りを返します)。
PointCut : execution(* com.example.demo..*(..))で、com.example.demoパッケージ内の処理実行時に共通処理を行うことができます。
これ以外にもexecution(* com.xyz.service.AccountService.*(..))など特定のクラスやメソッド名を指定することができます。
AOPは、知らなくても実装を進めるすることはできますが、知らないと、他人の書いたロジックを追えなくなることがありますので、注意してください。
/demo/src/main/java/com/example/demo/aspect/AspectLog.java
ここまでできたらプロジェクトを右クリックして、実行 -> Spring Boot アプリケーションを選択。
ブラウザのurlにhttp://localhost:8080/usersを入力して確認します。
下記のように、ログファイル(C:\log\app.log)とコンソールに、before aop、afterReturning aop、実行SQL、usersテーブルの情報が確認できればOKです。
参考
Spring Bootでapplication.propertiesを環境ごとに切り替える方法
Spring Boot解説第10回(開発環境編:ログの設定について~logback)
第4章 アペンダー
第6章 レイアウト
3. プロファイル
4. ロギング
5. Spring によるアスペクト指向プログラミング
Spring Boot入門② ~AOP~
お借りした素材
NYN姉貴.png
NYN姉貴.long
JAVA おすすめの本
こんにちは。前回はDBからデータ取得して一覧画面に表示させるとこまでできましたので、今回はログの出力を追加したいと思います。
前準備
ログを出力する上で必要なものをネットからMavenを使って取得しましょう。
今回はAOPを使用してメソッド実行前後でログを出力したいと思いますので、
spring-boot-starter-aopを使用します。
pom.xmlのdependenciesタグに以下を追加してください。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
/demo/pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
ログ機能の追加
まず、開発用のプロファイルを追加し、開発環境に合わせてログ情報を出力できるようにします。application.propertiesに"spring.profiles.active=dev"を追記すると、開発(dev)用のプロファイルとしてapplication-dev.propertiesを読み込めるようになります。
/demo/src/main/resources/application.properties
spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:5432/web?web_schema spring.datasource.username=dev spring.datasource.password=xxxx #開発(dev)プロファイルの読み込み spring.profiles.active=dev
開発(dev)プロファイル用の設定としてapplication-dev.propertiesを新規に作成します。名前に-devを追加したファイルを作成してください。
/demo/src/main/resources/application-dev.properties
logging.level.org.springframework.web=ERROR # mybatisのSQLを取得する logging.level.com.example.demo.mapper=DEBUG
開発環境ではspringframework.webのログのレベルをERRORに、mybatisの実行SQLを取得するため、com.example.demo.mapperのDEBUGに設定しました。
ログのレベルにはTRACE、DEBUG、INFO、WARN、ERRORがあり、エラーログ情報のみ欲しいときはERRORを、詳細なログが欲しいときはDEBUGを指定することができます。
次に、ログをコンソールの標準出力だけでなく、ファイル出力したいのでSpring Bootに標準でついているlogbackの設定を加えましょう。
/demo/src/main/resources/logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE logback> <configuration> <!--デフォルト設定読み込み --> <include resource="org/springframework/boot/logging/logback/base.xml" /> <!--開発(dev)プロファイル 環境用設定 --> <springProfile name="dev"> <!--変数の設定 --> <property name="logFilePath" value="C:/log/" /> <property name="logFileName" value="app" /> </springProfile> <!--標準出力 --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <target>System.out</target> <encoder> <charset>UTF-8</charset> <!--level ロギングイベントのレベル --> <!--message ロギングイベントに関連付けられたメッセージ --> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level [%thread] - %message%n</pattern> </encoder> </appender> <!-- アプリケーションログ --> <appender name="APPLIATION_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- 出力先ファイルパス --> <file>${logFilePath}${logFileName}.log</file> <!-- ログのローテーション設定 --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <!--日付けが変わったら年月フォルダ内にzipファイル作成 --> <fileNamePattern>${logFilePath}/%d{yyyyMM,aux}/${logFileName}-%d{yyyy-MM-dd}.log.zip</fileNamePattern> <!--最大30日間保存 --> <maxHistory>30</maxHistory> </rollingPolicy> <encoder> <charset>UTF-8</charset> <pattern>%d{yyyy/MM/dd HH:mm:ss} %-5level [%thread] - %message%n</pattern> </encoder> </appender> <!--rootロガー、コンソールとアプリケーションログに出力する --> <root level="INFO"> <appender-ref ref="STDOUT" /> <appender-ref ref="APPLIATION_LOG" /> </root> </configuration>
appenderは、ログの出力先を指定するものでch.qos.logback.core.ConsoleAppenderクラスを設定しているSTDOUTの方が標準出力のコンソールへ出力します。patternタグのlevelはログのレベル、messageはロギングイベントに関連付けられたメッセージを表示します。
一方、RollingFileAppenderクラスを設定しているAPPLIATION_LOGはファイルへの出力を行います。
それでは、確認のため前回作成したUserControllerに、usersテーブルで取得したデータをログ出力できるようにしてみます。25行目のLoggerFactory.getLogger(this.getClass())でロガーを呼び出し、44行目でmodelに設定されたusersテーブルの情報を表示しています。
logger.infoはログレベルINFOでログ出力します。エラーならlogger.errorになります。
/demo/src/main/java/com/example/demo/controller/UserController.java
package com.example.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import com.example.demo.service.UserService; /** * * Spring Boot 勉強用 コントローラ * * @author otoku-se * @version 1.0.0 */ @Controller @RequestMapping("/users") public class UserController { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired private UserService userService; /** * * usersテーブルからデータを取得する -> モデル * users.htmlに返す -> ビュー * * @param model users.htmlへデータを持っていく * @return users.htmlへ遷移 */ @GetMapping public String findAll(Model model) { model.addAttribute("users", userService.findAll()); // usersテーブルのデータをログに出力 logger.info("[usersテーブルの中身] " + model.getAttribute("users").toString()); return "users"; } }
AOP
技術的には@Aspectと@Componentのアノテーションをクラスに加えることでSpringコンテナにBeanとして外出しします。これも前回やった依存性の注入(DI)のひとつといえるでしょう。
その他、
JoinPoint : 横断的な処理を挿入するメソッド側の情報を取得できます 。getTarget().getClass().toString()で実行しているメソッドのクラス名、
getSignature().getName()で実行しているメソッドのメソッド名を取得できます。
Advice : @Beforeや@Afterといったアノテーションを共通処理を行うメソッドに記述することで処理実行前後に共通処理を行うことができます(今回使用している@AfterReturningは、正常終了したときのみ戻りを返します)。
PointCut : execution(* com.example.demo..*(..))で、com.example.demoパッケージ内の処理実行時に共通処理を行うことができます。
これ以外にもexecution(* com.xyz.service.AccountService.*(..))など特定のクラスやメソッド名を指定することができます。
AOPは、知らなくても実装を進めるすることはできますが、知らないと、他人の書いたロジックを追えなくなることがありますので、注意してください。
/demo/src/main/java/com/example/demo/aspect/AspectLog.java
package com.example.demo.aspect; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * * Spring Boot 勉強用 AOP ログ * * @author otoku-se * @version 1.0.0 */ @Aspect @Component public class AspectLog { private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * * com.example.demo内でメソッドが実行される前に * クラスとメソッド名をログに出力する。 * * @param jp JoinPoint -> 横断的な処理を埋め込むメソッドの情報 */ @Before(value = "execution(* com.example.demo..*(..))") public void beforeLog(JoinPoint jp) { logger.info("[before aop] start " + jp.getTarget().getClass().toString() + "#" + jp.getSignature().getName() ); } /** * * com.example.demo内でメソッドが実行された後で * 例外が発生しなければ * クラスとメソッド名とをログに出力する。 * * @param jp JoinPoint -> 横断的な処理を埋め込むメソッドの情報 * @param rtn JoinPoint処理後の戻り値 */ @AfterReturning(value = "execution(* com.example.demo..*(..))", returning = "rtn") public void afterLog(JoinPoint jp, String rtn) { logger.info("[afterReturning aop] end " + jp.getTarget().getClass().toString() + "#" + jp.getSignature().getName() + " return : " + rtn); } }
ここまでできたらプロジェクトを右クリックして、実行 -> Spring Boot アプリケーションを選択。
ブラウザのurlにhttp://localhost:8080/usersを入力して確認します。
下記のように、ログファイル(C:\log\app.log)とコンソールに、before aop、afterReturning aop、実行SQL、usersテーブルの情報が確認できればOKです。
参考
Spring Bootでapplication.propertiesを環境ごとに切り替える方法
Spring Boot解説第10回(開発環境編:ログの設定について~logback)
第4章 アペンダー
第6章 レイアウト
3. プロファイル
4. ロギング
5. Spring によるアスペクト指向プログラミング
Spring Boot入門② ~AOP~
お借りした素材
NYN姉貴.png
NYN姉貴.long
JAVA おすすめの本
0 件のコメント:
コメントを投稿