JavaのWebアプリケーション開発フレームワークによる、Webサイト開発の顛末記です。

EclipseのMavenを使った、Spring-MVC、Thymeleaf、MyBatis 等のプログラミングテクニックを、
備忘録的に記録しています。実際に動くソースコードを多用して説明していますので、
これからEclipseや、Spring-MVCを始めたいと思っている人にとって、少しでも参考になれば幸いです。
■SpringMVC の小径 ちょっと寄り道 ロギングの小径
9-3)log4j2 ログクラスの実装
Log4j2を利用するためには、まずLog4j2のプラグインが必要になりますが、
これは当然、Mavenさんにとって来てもらうつもりなので、pom.xmlに記述します。
「1-3)pom.xmlの編集」で定義した pom.xmlを確認すると、
おや!既に定義されてましたね!!(あんたはエライ!)
ということで、プラグインの事は気にしないで先に進みましょう。

Log4j2についてネットで検索すると、色々なサイトで実際のサンプルソースコードが紹介されています。
その中でも、代表的なものとして以下のようなソースコードを良く見かけます。

package jp.co.hoge.log;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

public class MyClass {
  //Loggerを取得
  private static Logger logger = LogManager.getLogger(MyClass.class);

  public static void main(String[] args) {
   try {
     //情報を出力
     logger.info("running {}", MyClass.getSimpleName());
   } catch(Exception e) {
     //エラー情報を出力
     logger.error("exception {}", e.getMessage());
   }
  }
}
上のソースコードは、確かに非の打ち所のない素晴らしいお手本のコードだと私も思います。
では、ほんとにこれをそのまま実際のアプリケーションで使っているの?
と、問われれば、答えは「いいえ」です。
正直言って、上のようなソースコードを紹介しているサイトの製作者(Log4j2を知り尽くしている人)が
こんなソースコードを実際の業務で書いているとは到底思えません。
理由1:private static Logger logger 宣言を各クラスごとに指定しないといけないのは、ダサい。
理由2:LogManager.getLogger(MyClass.class);
     getLoggerの引数をクラス名固定で指定しているので汎用性がない。(コピペできないのよ)
理由3:LogManagerメソッドの第一引数にある "{}"は、log4j2の特殊な意味を持つ文字列なので
    こんなlog4j2事情を、アプリケーションレイヤーのソースコードにベタベタと
    直書きするのは好ましくない(個人的には)

等々の事情により、上のソースコードは、あくまで教科書であって実戦ではあまり使いたくないコードです。
んな偉そうなこと言うなら、じゃぁ、ホントの実戦的なコードというのを見せてみろや!!。
と仰るのは当然の事。
そういうLog4j2マスターなホントにえらい人達がどんな実戦的ソースコード書いているか見たことはないので
あくまで私の個人的産物ですが、いつも私が実装しているソースコードをご紹介しておきます。
私のばやいは、ログ出力するための専用のクラス(MyLog4J.java)を一つ贅沢に作ってしまいます。
src/main/java/jp/dip/arimodoki/common/MyLog4J.java

何も隠し事はしません。一糸まとわぬ裸の私を全て見てください(きゃ
説明はソースコードのコメントに書いてあります。
もし使いたかったら自由に使ってください。

これで先ほどのサンプルソースコードを置き換えると

package jp.co.hoge.log;

import jp.dip.arimodoki.common.MyLog4J;

public class MyClass {
  //Loggerを取得
  private MyLog4J logger = MyLog4J.getInstance();

  public static void main(String[] args) {
   try {
     //情報を出力
     logger.log_info(this, "running [" + MyClass.getSimpleName() + ”]");
   } catch(Exception e) {
     //エラー情報を出力
     logger.log_error(e);
   }
  }
}
となり、最初よりは少しだけシンプルになりました。
偉そうな事言うた割には大したことないなぁワレェ!!
はい、すみませんねぇ。
じゃあちょっとだけ隠し味をふりかけます。
アプリケーションを開発するときは、だいたい共通の定数とかがあって、
それらを全部まとめたインターフェースとかよく作りますよね。
具体例)
package jp.dip.arimodoki.common;
/**
* アプリケーション共通の定数などを宣言するインターフェースです。
*/

public interface CConst {
  public static final String NANTYARA_TEISU = "なんちゃらな定数";
}

これに、隠し味として次の1行(赤字)を追加します。
package jp.dip.arimodoki.common;
/**
* アプリケーション共通の定数などを宣言するインターフェースです。
*/

public interface CConst {
  public static MyLog4J logger = MyLog4J.getInstance();
  public static final String NANTYARA_TEISU = "なんちゃらな定数";
}

これで先ほどのサンプルソースコードを再度置き換えると、今度はスパイスが効いてるので、

package jp.co.hoge.log;

import jp.dip.arimodoki.common.CConst;

public class MyClass implements CConst{

  public static void main(String[] args) {
   try {
     //情報を出力
     logger.log_info(this, "running [" + MyClass.getSimpleName() + ”]");
   } catch(Exception e) {
     //エラー情報を出力
     logger.log_error(e);
   }
  }
}
みたいに、クラスに対してCConstをimplementsしてあげれば
どのクラスでもいちいちloggerクラスの変数宣言が必要なくなり、だいぶすっきりします。
ログ出力メソッド自体はこれ以上隠しようがありませんが、これはどの方法でも仕方がないので諦めます。
人によっては、loggerの宣言が見えなくてわかりにくいと思う人もいると思いますが、
そういう人は、最初のprivate MyLog4J logger = MyLog4J.getInstance();宣言方式を使うようにすれば
気にならないと思います。

だいぶいい感じやんけ?もらっとこ。
そやけど、log_info()はしゃーないけど、
log_error()は、いちいち try {} catch() {} せなアカンし、いちいち面倒やのぅ?
そーですね確かに。それでは最後の寄り道。Aspectの魔法を ちちんぷいぷい してみましょうか。
続く。
(ところで、なんで関西弁?)