環境について
環境は、以前書いた記事のものと同一です。
IntelliJ Community で Tomcat の実行環境を整備する
一応雑にまとめると以下のような感じになります。
種類 | ソフトウェア |
---|---|
言語 | Java SE 8 |
サーバーAPI | JavaEE |
Log API | Log4j2 |
IDE | IntelliJ Community |
ビルドツール | Gradle |
コンテナ | Tomcat |
webappフォルダを作成する
JavaEEプロジェクトであれば既に作成済みかもしれませんが、以下のようにディレクトリを作成します。
<プロジェクト> -> src -> main -> webapp (※) -> WEB-INF (※)
(※) 作成するディレクトリ
また、ディレクトリはちゃんと"webapp"、"WEB-INF"としましょう。
そして、WEB-INF内に"classes"、"lib"というディレクトリも作成しておきましょう。
プロジェクトにlog4j2を追加
build.gradleのdependancesに以下のように追加します。
dependencies {
// log4jを使えるようにする
compile group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.1'
compile group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.1'
compile group: 'org.apache.logging.log4j', name: 'log4j-web', version: '2.11.1'
}
Loggerクラスを作成する
Logを書き込む際、毎回前準備のコードを書くのは面倒であるため、以下のようにラップクラスを作成します。
コードは、以下のリンクを参考にしました。
SpringMVC の小径 ちょっと寄り道 ロギングの小径
import org.apache.logging.log4j.LogManager;
import java.io.File;
/**
* ロギング処理を行う
*/
public class Log4j {
private static Log4j logger = null;
private Log4j() {
}
public static synchronized Log4j getInstance() {
if (logger == null) {
logger = new Log4j();
}
return logger;
}
private String getMessage(final String msg) {
String thisClassName = this.getClass().getName();
//クラス名を取得
String SuperClassName = Logger.class.getName();
Thread t = Thread.currentThread();
StackTraceElement[] stackTraceElements = t.getStackTrace();
int pos = 0;
for (StackTraceElement stackTraceElement : stackTraceElements) {
String steClassName = stackTraceElement.getClassName();
if (thisClassName.equals(steClassName) || SuperClassName.equals(steClassName)){
break;
}
pos++;
}
pos += 2;
StackTraceElement m = stackTraceElements[pos];
return m.getClassName() + ":" + m.getMethodName() + "() \n" + msg;
}
private String getErrorMessage(final Exception e) {
StringBuilder sb = new StringBuilder();
StackTraceElement[] st = e.getStackTrace();
if (st != null && st.length > 0) {
sb.append("Class:")
.append(e.getClass().getName())
.append("¥n")
.append("Detail:")
.append(e.getMessage())
.append("¥n");
for (StackTraceElement s : st) {
sb.append(s.toString())
.append("¥n");
}
}
return sb.toString();
}
public void debug(final String msg) {
LogManager.getLogger(this.getClass()).debug(getMessage(msg));
}
public void info(final String msg) {
LogManager.getLogger(this.getClass()).info(getMessage(msg));
}
public void info(final Object obj, final String msg) {
LogManager.getLogger(obj.getClass()).info(msg);
}
public void warn(final String msg) {
LogManager.getLogger(this.getClass()).warn(getMessage(msg));
}
public void error(final Exception e) {
LogManager.getLogger(e.getClass()).error(getErrorMessage(e));
}
public void trace(final String msg) {
LogManager.getLogger(this.getClass()).trace(getMessage(msg));
}
public void fatal(final String msg) {
LogManager.getLogger(this.getClass()).fatal(getMessage(msg));
}
}
EndPoint内では、以下のように呼び出して利用します。
Log4j logger = Log4j.getInstance();
logger.info("ここにログ内容を書く");
log4jには、以下のようなレベルのログが用意されており、それに合わせてラップメソッドを定義してあります。
fatal > error > warn > info > debug > trace
log4j2設定ファイルを作成する
log4j2の設定ファイルは、"log4j2.xml"という名前のxmlファイルに記述します。
また、Tomcatでは、webapp -> WEB-INF -> classesフォルダに置くことで、自動で読み込むことが出来ます。
log4j2.xmlの記入例を示します。
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="off">
<Properties>
<Property name="loglayout">[%d{yyyy-MM-dd HH:mm:ss.SSS}], %-5p, %t, %c, %m%n</Property>
</Properties>
<Appenders>
<!--
fileName:ログを出力するファイル名
filePattern:ログが溜まってきたときに圧縮するファイルのパターン
-->
<RollingFile name="rolling" fileName="./log/webapp.log" filePattern="./log/webapp-%d{yyyy-MM-dd}-%i.zip">
<PatternLayout pattern="${loglayout}"/>
<Policies>
<OnStartupTriggeringPolicy/>
<SizeBasedTriggeringPolicy size="20 MB"/>
<TimeBasedTriggeringPolicy/>
</Policies>
<DefaultRolloverStrategy max="10"/>
</RollingFile>
<Console name="console" target="SYSTEM_OUT">
<PatternLayout pattern="${ptn}" />
</Console>
</Appenders>
<Loggers>
<!--
name:ログ出力を行うパッケージ名
level:ログの出力レベル
additivity:上位のログを出力するかどうか
-->
<Logger name="Logger" level="info" additivity="true">
<AppenderRef ref="rolling"/>
</Logger>
</Loggers>
</Configuration>
詳しい説明については、以下のリンクに記載されています。
war化した時にファイルパスを変更する
Gradleプロジェクトでは、相対パスがプロジェクト直下であるため、ファイルのディレクトリを
. -> log
としていましたが、Tomcatでは、相対パスのルートがtomcatインストールフォルダになっているので、
. -> webapps -> -> WEB-INF -> log
にする必要があります。
xml内で指定する方法もあるようでしたが、
log4j2.xml //開発用
log4j2_exe.xml //本番用
これを、war化するときだけ
log4j2_test.xml //開発用
log4j2.xml //本番用
に名前変更することで対応しました。
実際には、build.gradleに、以下のコードを追加します。
// warタスク実行前に実行
war.doFirst {
//子ファイルを取得
java.io.File[] flist = (new java.io.File("./src/main/webapp/WEB-INF/classes")).listFiles();
for(i in flist) {
//ファイル名判定
switch (i.getName()) {
case "log4j2.xml":
//リネーム
i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2_test.xml"));
break;
case "log4j2_exe.xml":
i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2.xml"));
break;
}
}
}
//warタスク実行後に実行
war.doLast {
java.io.File[] flist = (new java.io.File("./src/main/webapp/WEB-INF/classes")).listFiles();
for(i in flist) {
switch (i.getName()) {
case "log4j2_test.xml":
i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2.xml"));
break;
case "log4j2.xml":
i.renameTo(new java.io.File("./src/main/webapp/WEB-INF/classes/log4j2_exe.xml"));
break;
}
}
}
問題点
warタスク実行ごとにファイルを作成すると、gitに管理ファイルとして認識されない
-> 設定をほにゃほにゃして1つのxmlでできるようにするべき