logging.properties

JavaAPI標準のjava.util.loggingライブライに関わらずJavaのログライブラリ(Log4J,logback,SLF4Jなど)は、
必ず提供されるjarファイルの中か外だしでデフォルトの設定ファイルを用意しています。

基本的にデフォルトで提供されているログファイルを直接書き換える事はしません。
デフォルトのログファイルをコピーしてクラスパス配下や任意のディレクトリに配置して、
ログライブラリに独自のログ設定ファイルを読み込ませることにより、設定を反映させます。

デフォルトの設定ファイルlogging.properties

java.util.loggingのデフォルトの設定ファイル「logging.properties」は、JREをインストールした「%JRE_HOME%¥lib」配下にあります。
本サイトのJava8のインストールの手順で実行された方は、
「C:¥developer¥java¥jre¥jre1.8.0_112¥lib」配下に格納されています。

logging.properties
############################################################
#  	Default Logging Configuration File
#
# You can use a different file by specifying a filename
# with the java.util.logging.config.file system property.
# For example java -Djava.util.logging.config.file=myfile
############################################################

############################################################
#  	Global properties
############################################################

# "handlers" specifies a comma separated list of log Handler
# classes.  These handlers will be installed during VM startup.
# Note that these classes must be on the system classpath.
# By default we only configure a ConsoleHandler, which will only
# show messages at the INFO and above levels.
handlers= java.util.logging.ConsoleHandler

# To also add the FileHandler, use the following line instead.
#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler

# Default global logging level.
# This specifies which kinds of events are logged across
# all loggers.  For any given facility this global level
# can be overriden by a facility specific level
# Note that the ConsoleHandler also has a separate level
# setting to limit messages printed to the console.
.level= INFO

############################################################
# Handler specific properties.
# Describes specific configuration info for Handlers.
############################################################

# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.XMLFormatter

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

# Example to customize the SimpleFormatter output format
# to print one-line log message like this:
#     <level>: <log message> [<date/time>]
#
# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n

############################################################
# Facility specific properties.
# Provides extra control for each logger.
############################################################

# For example, set the com.xyz.foo logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
						

前項のサンプル結果と同じ挙動の設定になっている事が分かります。
FileHandlerとConsoleHandlerが定義されており、handlers= java.util.logging.ConsoleHandlerでルートハンドラーの設定がConsoleHandlerになっています。
FileHandlerも有効にする場合には、コメントに記載されているように「,」で連結してFileHandlerも設定します。

尚、設定ファイルのプロパティーのキーの接頭辞「java.util.logging.」が「名前空間」を意味しています。

また、コメントにあるようにjava -Djava.util.logging.config.file=myfile 形式でjavaコマンドの引数として設定ファイルを引き渡せます。

設定ファイルの作成とロード

javaコマンドから設定ファイルの引渡しパターンは、まず利用しません。
javaアプリケーションやWebアプリケーションを利用する際にjavaコマンドなどが記載されたバッチファイルに記載漏れの恐れがあるからです。

javaソースコードで設定ファイルをロードするアプリケーション初期化クラスを作成して、ロードするのが一般的です。

設定ファイルの作成

「%JRE_HOME%¥lib」配下の「logging.properties」をコピーして「C:¥projects¥education¥src¥resources」に保存して下さい。

logging.properties
############################################################
#  	Education Logging Configuration File
############################################################
handlers= java.util.logging.FileHandler,java.util.logging.ConsoleHandler

.level= INFO
# default file output is in user's home directory.
java.util.logging.FileHandler.pattern = C:/projects/education/logs/education%u.log
java.util.logging.FileHandler.limit = 50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level = WARNING

# Limit the message that are printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
# %1:date/time %2:className and methodName %3logName %4:level %5:message %6:errormessage

java.util.logging.SimpleFormatter.format=%1$tY/%1$tm/%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$s %2$s %5$s %6$s%n
jp.co.yourcompany.education.level = INFO
						

設定ファイル実行サンプル

logging.propertiesファイルをクラスパスから読み込ませるサンプルクラスです。

Javaデザインパターンのシングルトン(Singleton)を利用してインスタンスを常に1つにします。

このようにJavaアプリケーションの初回ロード時に初期処理を行いたい場合には、以下のようなクラスを作成し、
javaコマンドから初回呼び出されるクラスのデフォルトコンストラクタや明示して作成した初期化メソッドinit()などで
アプリケーションの初期処理を行うのが定石です。

InitApplication.java
package jp.co.yourcompany.education.log;

import java.io.IOException;
import java.io.InputStream;
import java.util.logging.LogManager;

public class InitApplication {

    /**
     * シングルトン
     */
    private static InitApplication instance = null;

    /**
     * java.util.log.LogManagerに読み込ませるログプロパティファイル
     */
    public static final String LOG_PROPERTIES_NAME = "logging.properties";


    /**
     * InitApplicationのインスタンスを返す。
     * @return InitApplicationのインスタンス
     */
    public static InitApplication getInstance(){
        if( instance == null){
            instance = new InitApplication();
        }
        return instance;
    }

    /**
     * アプリケーションの初期化処理
     */
    public void init(){
        initLog();
    }

    /**
     * ログの初期化
     */
    private void initLog(){

        InputStream in = null;
        try {
            in = InitApplication.class.getClassLoader().getResourceAsStream("logging.properties");
            if (in == null) {
                System.err.println("logging.propertiesファイルがクラスパスに存在しません。");
            }
            LogManager.getLogManager().readConfiguration( in );
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if( in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
						

実際にログを出力する側のサンプルです。

JavaAPILogSample.java
package jp.co.yourcompany.education.log;

import java.util.logging.Level;
import java.util.logging.Logger;;


/**
 * java.util.loggingAPIを利用して、
 * 設定ファイルに指定したログを出力
 * @author raita.kuwabara
 */
public class JavaAPILogSample {

    /**
     * ロガーインスタンスの生成
     * このようにロガーは、クラスメンバーフィールド(static)で定義します。
     */
    public static final Logger log = Logger.getLogger( JavaAPILogSample.class.getName() );

    /**
     * デフォルトコンストラクタ
     * アプリケーションの初期化を実施する。
     */
    public JavaAPILogSample(){
        InitApplication application = InitApplication.getInstance();
        application.init();

    }


    /**
     * ログ出力サンプルを全て実行する。
     */
    public void execAllSamples(){

        logExceptionSample();
        logSevere();
        logWarning();
        logInfo();
        logConfig();
        logFine();
        logFiner();
        logFinest();

    }

    /**
     * 例外の出力例
     */
    private void logExceptionSample(){
        System.out.println("logExceptionSample START ");
        String test = null;
        //nullポを起こすためのコーディングで本来このような記述はしません。
        try{
            if( test.equals("TEST") ){
                System.out.println(" test is TEST. ");
            }
        } catch( NullPointerException e){
            log.log(Level.SEVERE, "例外発生", e);
        }
        log.severe("logExceptionSample");
        System.out.println("logExceptionSample END ");
    }

    /**
     * ログの出力レベル:SERVEREの確認
     */
    private void logSevere(){
        System.out.println("logSevere START ");
        log.severe("LOGLEVEL:SERVERE");
        System.out.println("logSevere END ");
    }

    /**
     * ログの出力レベル:WARNINGの確認
     */
    private void logWarning(){
        System.out.println("logWarning START ");
        log.warning("LOGLEVEL:WARNING");
        System.out.println("logWarning END ");
    }

    /**
     * ログの出力レベル:INFOの確認
     */
    private void logInfo(){
        System.out.println("logInfo START ");
        log.info("LOGLEVEL:INFO");
        System.out.println("logInfo END ");
    }

    /**
     * ログの出力レベル:CONFIGの確認
     */
    private void logConfig(){
        System.out.println("logConfig START ");
        log.config("LOGLEVEL:CONFIG");
        System.out.println("logConfig END ");
    }

    /**
     * ログの出力レベル:FINEの確認
     */
    private void logFine(){
        System.out.println("logFine START ");
        log.fine("LOGLEVEL:FINE");
        System.out.println("logFine END ");
    }

    /**
     * ログの出力レベル:FINERの確認
     */
    private void logFiner(){
        System.out.println("logFiner START ");
        log.finer("LOGLEVEL:FINER");
        System.out.println("logFiner END ");
    }

    /**
     * ログの出力レベル:FINESTの確認
     */
    private void logFinest(){
        System.out.println("logFinest START ");
        log.finest("LOGLEVEL:FINEST");
        System.out.println("logFinest END ");
    }


    /**
     * javaコマンドから実行されるmainメソッド
     */
    public static final void main( String[] args ) {
        JavaAPILogSample sample = new JavaAPILogSample();
        sample.execAllSamples();
    }
}
						
実行結果[標準出力]
logExceptionSample START
2017/03/13 18:24:11.023 重大 jp.co.yourcompany.education.log.JavaAPILogSample logExceptionSample 例外発生
java.lang.NullPointerException
	at jp.co.yourcompany.education.log.JavaAPILogSample.logExceptionSample(JavaAPILogSample.java:66)
	at jp.co.yourcompany.education.log.JavaAPILogSample.execAllSamples(JavaAPILogSample.java:47)
	at jp.co.yourcompany.education.log.JavaAPILogSample.main(JavaAPILogSample.java:145)

2017/03/13 18:24:11.070 重大 jp.co.yourcompany.education.log.JavaAPILogSample logExceptionSample logExceptionSample
logExceptionSample END
logSevere START
2017/03/13 18:24:11.071 重大 jp.co.yourcompany.education.log.JavaAPILogSample logSevere LOGLEVEL:SERVERE
logSevere END
logWarning START
2017/03/13 18:24:11.073 警告 jp.co.yourcompany.education.log.JavaAPILogSample logWarning LOGLEVEL:WARNING
logWarning END
logInfo START
2017/03/13 18:24:11.074 情報 jp.co.yourcompany.education.log.JavaAPILogSample logInfo LOGLEVEL:INFO
logInfo END
logConfig START
logConfig END
logFine START
logFine END
logFiner START
logFiner END
logFinest START
logFinest END
					
実行結果[education.log]
2017/03/13 18:24:11.023 重大 jp.co.yourcompany.education.log.JavaAPILogSample logExceptionSample 例外発生
java.lang.NullPointerException
	at jp.co.yourcompany.education.log.JavaAPILogSample.logExceptionSample(JavaAPILogSample.java:66)
	at jp.co.yourcompany.education.log.JavaAPILogSample.execAllSamples(JavaAPILogSample.java:47)
	at jp.co.yourcompany.education.log.JavaAPILogSample.main(JavaAPILogSample.java:145)

2017/03/13 18:24:11.070 重大 jp.co.yourcompany.education.log.JavaAPILogSample logExceptionSample logExceptionSample
2017/03/13 18:24:11.071 重大 jp.co.yourcompany.education.log.JavaAPILogSample logSevere LOGLEVEL:SERVERE
2017/03/13 18:24:11.073 警告 jp.co.yourcompany.education.log.JavaAPILogSample logWarning LOGLEVEL:WARNING
					

実行結果から次の事が実現できました。

  1. 標準出力にはINFOレベルを出力し、ログファイルには、WARNING以上を出力しました。
  2. フォーマットを整形し、ログ出力日時 ログレベル 実行クラス 実行メソッド メッセージ エラーメッセージ
    形式に出力しました。

重要ポイントとなる点は以下になります。

  1. ファイル出力先のディレクトリは事前に存在しなくてはならない。
    ログディレクトリ名に動的な%h(時間指定)等を行う際には注意が必要です。
  2. ファイル出力先のディレクトリが存在しない場合には、javaAPIのlogging.propertiesの設定が利用されます。
  3. デフォルトのログファイルの出力先は、Windowsの場合「C:¥Users¥ログインしているアカウント名¥java%u.log」になります。
  4. フォーマットの引数$1~$6には次の節で説明する出力内容が存在します。
  5. フォーマットはjava.util.Formatter形式を指定します。

java.util.logging.SimpleFormatter

ログの出力形式を決めるSimpleFormatterのformatの引数について説明します。

No[$指定] 内容 説明
$1 ログ出力日時 ログ出力日時(ミリオン秒まで保持)
$2 クラス名とメソッド名 ログ出力要求を実行したクラスの完全修飾子名とメソッド名
$3 ログ名 Logger.getLogger("ログ名")で指定したログ名
$4 ログレベル java.logging.Levelに定義されているログレベルがログの実行要求時のログレベルで出力
$5 メッセージ 各種ログメソッド("ログメッセージ")で指定したログメッセージ
$6 エラーメッセージ log( java.logging.Level , "メッセージ" , throwable )メソッド
で引渡したした第3引数のExceptionインスタンス

サンプルのダウンロードと実行方法

  • java_sample15.zipファイルを「c:¥download¥java¥samples¥」に保存して下さい。
  • java_sample15.zipファイルを「c:¥projects」配下に展開して下さい。
  • コマンドプロンプトを起動して、「sample15.bat」を実行して下さい。
  • javac,jar,javaが実行されてJavaAPILogSampleが実行されます。
  • 「c:¥projects¥education¥logs」配下のログの実行結果を確認して下さい。
  • Linux,Unix,iOSの方はバッチファイルはお手数ですが作成して下さい。改行コードが「CRLF」の点ご留意ください。
  • SLF4Jとの連携方法は、SLF4Jのメニューから2017年4月~5月にリリースする予定です。

参考文献