Jakarta-Commons-Logging の概要 †
- プログラムとロギングフレームワークを分離する薄いラッパー
- 環境にlog4jがあればlog4jを使うし、なければJDKに付属するjava.util.loggingを使用する。*1
- プログラムから出力されたログをどのように整形して、どこに出力するかはそれぞれのフレームワークの設定ファイルで設定する。
Jakarta-Commons-Logging のアプリ側プログラミング †
- 環境
- Jakartaプロジェクトのダウンロードサイトから、commons-logging-1.0.4.zipをダウンロード
- 展開してできたjarファイルをプロジェクトのクラスパスに通す
- commons-logging.jar
- commons-logging-api.jar
- プログラミング
- loggerのインスタンス
- logger=LogFactory?.getLog( 自Class ) で取得。ログに出力するClass名になったり、出力するレベルをパッケージによって変えるのに使う。
- クラスのstaticフィールドとして保持する
- log出力
- 対応するメソッドを使うことにより重要度を変えることができる
- 第二引数にthrowableをとることができる(通常ログファイルにはスタックトレースが出力される...FormatterなりLayoutの設定次第ですが)
- 重いログ出力の前には、logger.is${Level}Enable() メソッドで、現在の設定上出力しなければならないログかを調べること
記述例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
- | | | | - | - | | | | | | | | | | | - | | | | | | | | | ! | | | | - | | - | | ! ! | ! !
public class LogSample { /** jakarta-commons-logging */ private static Log logger = LogFactory.getLog(LogSample.class); public static void main(String[] args) { try { /* ----- 基本的なログ出力 ------ */ logger.fatal("本当にやばいログ"); logger.error("普通にやばいログ"); logger.warn("ちょっとやばいログ"); logger.info("運用時に必要なログ"); logger.debug("開発時に必要なログ"); logger.trace("デスマ時に必要なログ"); /* ---------------------------- */ throw new NullPointerException("('A`) ぬるぽ "); } catch (Exception ex) { /* -- 例外情報を含んだログ出力 -- */ logger.fatal("本当にやばいログ", ex); logger.error("普通にやばいログ", ex); logger.warn("ちょっとやばいログ", ex); logger.info("運用時に必要なログ", ex); logger.debug("開発時に必要なログ", ex); logger.trace("デスマ時に必要なログ", ex); /* ---------------------------- */ } /* ------- 重いログ出力 -------- */ java.util.Map m = new HashMap(); if (logger.isDebugEnabled()) { // Debugレベルが有効ならば、Mapの中身をすべてログに出力する Set keys = m.keySet(); for (Iterator it = keys.iterator(); it.hasNext();) { Object key = it.next(); logger.debug(key + "=" + m.get(key)); } } /* ---------------------------- */ } }
- loggerのインスタンス
java.util.loggingの設定 †
- 設定ファイル
- %JAVA_HOME%\jre\lib\logging.properties
- あるいはjava vm起動時に、-Djava.util.logging.config.file=設定ファイル名 で指定
- 設定方法
- ログレベルの対応
java.util.logging Commons-Logging SEVERE logging.fatal(),logging.error() WARNING logging.warn() INFO logging.info() CONFIG FINE logging.debug() FINER FINEST logging.trace() - あとは、%JAVA_HOME%\jre\lib\logging.propertiesを見りゃあ分かりますな。できることは、コメントに書いてあることで全部です。
%JAVA_HOME%\jre\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 <-- 最大ファイル長さ(byte) 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 ############################################################ # 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 <-- com.xyz.foo パッケージ以下はSEVERE以上のログのみを出力するようにする。
- ログレベルの対応
log4jの設定 †
- 環境
- Logging Services Project @ Apache のダウンロードサイトから logging-log4j-1.2.9.zip をダウンロード
- 展開してできたjarファイルをプロジェクトのクラスパスに通す
- log4j-1.2.9.jar
- 設定ファイルのlog4j.xmlをクラスパスのルートに置く
- eclipseなら、\srcにおいておくと、ビルド時に \binにコピーしてくれます
- antの場合は、コピーするようにスクリプトを書かなければなりませんね
- 設定方法
- ログレベルの対応
log4j Commons-Logging FATAL logging.fatal() ERROR logging.error() WARN logging.warn() INFO logging.info() DEBUG logging.debug(),logging.trace() - log4j.xmlの構造
- log4j.xmlは、appender・category・rootから成ります
<log4j:configuration> ::= <appender>+ <category>* <root>
- appenderセクションには、ログ出力クラスの設定を行います。appenderセクションはlayoutセクションを含み、layoutセクションでログの整形に関する設定を行います。
<appender> ::= 使用Appenderクラス名 Appenderデフォルトログレベル 出力設定 <layout>? <layout> ::= 使用Layoutクラス名 書式
- rootセクションでは、デフォルトのログレベルと、使用するAppender名を指定します。出力されるログレベルは、appenderセクションで定義されたデフォルトログレベルとrootセクションで定義されたデフォルトログレベルの内重要度が大きいものが使用されます。
<root> ::= Rootデフォルトログレベル 使用Appender名+
- categoryセクションでは、特定のカテゴリ(パッケージ)に対して、ログレベルを変更することができます(rootではinfoレベルだが、com.xx.buggy.* だけは traceレベル で出力したい・・・など)。必ずrootカテゴリよりも前に定義します。
<category> ::= 適用カテゴリ名 ログレベル 使用Appender名+
- log4j.xmlは、appender・category・rootから成ります
- 記述例
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'> <!-- ********************** レイアウト書式 *********************** %r アプリ起動から何ミリ秒たったか %d 日時 %d{dd MMM yyyy HH:mm:ss.SSS} %t スレッド名 %x ネスト化診断コンテキスト(@see org.apache.log4j.NDC) %X マップ化診断コンテキスト(@see org.apache.log4j.MDC) %p レベル名(FATAL/ERROR/WARN/INFO/DEBUG) %c カテゴリー名(クラス名) // LogFactoryで指定したもの %m メッセージ %n 改行コード %% % %10m 桁数が10桁未満のとき、左側にSPを追加して10桁にする %.10m 桁数が10桁以上のとき、11桁目以降を削除して10桁にする %10.20m (左側にSPを足して)桁数を10桁~20桁にそろえる %-10m 桁数が10桁未満のとき、右側にSPを追加して10桁にする %-10.20m (右側にSPを足して)桁数を10桁~20桁にそろえる ※パフォーマンス上の問題があるので避けるべき書式(StatcTraceから取得?) %C クラス名 %M メソッド名 %l ファイル名・行番号 %F ファイル名 %L 行番号 --> <!-- ********************** 標準出力への出力 ********************** --> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="debug" /> <!-- レイアウトの指定 --> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{HH:mm:ss.SSS} [%-5p] %.30m%n" /> </layout> </appender> <!-- ********************** ファイルへの出力 ********************** --> <appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="info" /> <!-- ファイル情報 --> <param name="file" value="log.txt" /> <param name="append" value="false" /> <param name="datePattern" value="'.'yyyy-MM-dd" /> <!-- ファイルローテートの指定 '.'yyyy 年の変わり目(1月1日の0時) '.'yyyy-MM 月の変わり目(1日の0時) '.'yyyy-ww 週の変わり目(日曜の0時) '.'yyyy-MM-dd 日の変わり目(0時) --> <!-- レイアウトの指定 --> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d %x [%-5p] %m%n" /> </layout> </appender> <!-- ********************** syslogdへの出力 ********************** --> <appender name="SYSLOG" class="org.apache.log4j.net.SyslogAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="error" /> <!-- (log4j) (syslog) FATAL crit,panic,emerg ERROR err,error WARN warning,warn INFO info DEBUG debug --> <!-- syslogサーバ情報 --> <param name="SyslogHost" value="localhost" /> <param name="facility" value="user" /> <!-- facility には以下の項目を設定できる kern , user , mail , daemon , auth(認証) , syslog , lpr , news , uucp , cron , authpriv(アプリ固有の認証) , ftp , local0~7 --> <!-- レイアウトの指定 --> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{HH:mm:ss.SSS} [%-5p] %.30m%n" /> </layout> </appender> <!-- ********************** NTEventへの出力 ********************** --> <!-- NTEventを記録するサーバの C:\WINNT\SYSTEM32 に logging-log4j-x.x.x\src\java\org\apache\log4j\nt\NTEventLogAppender.dll をコピー --> <appender name="NTEvent" class="org.apache.log4j.nt.NTEventLogAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="fatal" /> <!-- NTEventサーバの設定 --> <param name="source" value="XXアプリ" /> <!-- レイアウトの指定 --> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{HH:mm:ss.SSS} [%-5p] %.30m%n" /> </layout> </appender> <!-- ********************** SMTPへの出力 ************************* --> <!-- JavaMail(mail.jar) http://java.sun.com/j2ee/ja/javamail/index.html JAF(activation.jar) http://java.sun.com/beans/glasgow/jaf.html をクラスパスに通しておく --> <appender name="SMTP" class="org.apache.log4j.net.SMTPAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="fatal" /> <!-- メール送信の設定 --> <param name="SMTPHost" value="mail.xxxxxxx.com" /> <param name="To" value="xxxxx@xxxxxxx.com" /> <param name="Subject" value="【緊急】XXアプリ致命的エラーの発生" /> <param name="From" value="XXMaster@xxxxxxxxxx.com" /> <param name="BufferSize" value="1" /> <!-- レイアウトの指定 --> <!-- PatternLayoutは、getContentType()の返値に文字コードを指定できない ので、文字コード を指定して text/plane; chaset=XXX を出力できるよう に拡張したEncordablePatternLayoutを独自に作る (http://issues.apache.org/bugzilla/show_bug.cgi?id=32074 で議論中) --> <layout class="EncodablePatternLayout"> <param name="Charset" value="ISO-2022-JP" /> <param name="ConversionPattern" value="%d{HH:mm:ss.SSS} [%-5p] %.30m%n" /> </layout> </appender> <!-- **************** Socket(Log4JMonitor)への出力 *************** --> <!-- http://freshmeat.net/projects/log4jmonitor/?topic_id=45%2C846%2C47 --> <!-- log4jmonitor-1.1.jar をダブルクリックすると起動します --> <appender name="SOCKET" class="org.apache.log4j.net.SocketAppender"> <!-- デフォルトのログレベル --> <param name="threshold" value="debug" /> <!-- 送信先の設定 --> <param name="RemoteHost" value="localhost" /> <param name="Port" value="27272" /> <!-- layoutは指定しない --> </appender> <!-- ********************** category定義 ************************* --> <category name="com.xx.buggy"> <priority value="debug" /> <appender-ref="STDOUT" /> </category> <!-- ********************** root定義 ***************************** --> <root> <priority value="info" /> <appender-ref ref="STDOUT" /> <appender-ref ref="SOCKET" /> </root> </log4j:configuration>
- ログレベルの対応
- SMTPAppenderで日本語のメールを送る
PatternLayout?.getContentType?()が常に、"text/plain"を返すので、日本語のメールを送ることができません。
そこで、PatternLayout?を拡張して、ContentType?を指定できるEncordablePatternLayout?を作りました。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
- | | | - | ! | - | ! !
EncodablePatternLayout.java: import org.apache.log4j.PatternLayout; public class EncodablePatternLayout extends PatternLayout { private String charset; public void setCharset(String charset) { this.charset = charset; } public String getContentType() { return "text/plain; charset=\"" + charset + "\""; } }
log4j.xml(抜粋): <layout class="EncodablePatternLayout"> <param name="Charset" value="ISO-2022-JP" /> <param name="ConversionPattern" value="%d{HH:mm:ss.SSS} [%-5p] %.30m%n" /> </layout>
- ネスト化診断コンテキスト
Threadに対して、push(String)で文字列を指定できる。
Servletのフィルタ?やEJBのFacadeなどに用いる。