001/*
002 * Copyright (c) 2017 The openGion Project.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013 * either express or implied. See the License for the specific language
014 * governing permissions and limitations under the License.
015 */
016package org.opengion.fukurou.fileexec;
017
018//      import java.nio.file.Paths;                                                     // 6.8.1.5 (2017/09/08)
019
020import java.util.logging.Logger;
021import java.util.logging.Level;
022import java.util.function.Supplier;                                             // 6.8.1.0 (2017/07/14)
023import java.util.function.Function;                                             // 7.2.5.0 (2020/06/01)
024
025/**
026 * XLoggerは、Throwable を引数に取るwarningと、Level 600 の debug メソッドを
027 * 持つ、Logger の拡張クラスです。
028 * ここでは、継承するのではなく、委譲で、最低限のメソッドだけに対応しています。
029 * (LogManager とか、色々とややこしそうなので、調査する暇が無い)
030 *
031 * WARNING(900) → INFO(800) → CONFIG(700) → XXXX(600) → FINE(500) → ALL(Integer.MIN_VALUE)
032 * となっていますが、FINE では、多すぎ、INFO は、通常使用、間に、DEBUG的な、
033 * ロギングが欲しい場合に使用します。
034 * CONFIG を使いたいところですが、「CONFIGは静的な構成メッセージのメッセージ・レベルです。」と
035 * JavaDocにわざわざ、書かれていることから、使用を避けます。
036 *
037 * @og.rev 7.0.0.0 (2017/07/07) 新規作成
038 *
039 * @version  7.0
040 * @author   Kazuhiko Hasegawa
041 * @since    JDK1.8,
042 */
043public class XLogger {
044        // 7.2.5.0 (2020/06/01) 各クラスで、class.getSimpleName() を渡すようにしたので短縮不要。
045//      /** 初期設定されているリソースバンドルのbaseName {@value} */
046//      public static final String OMIT_NAME = "org.opengion.fukurou." ;        // fileexec は残す
047
048        /**
049         * デバッグレベルを新規に定義します。
050         *
051         * OFF:Integer.MAX_VALUE , SEVERE:1000 , WARNING:900 , INFO:800 , CONFIG:700 , FINE:500 , FINER:400 , FINEST:300 , ALL:Integer.MIN_VALUE
052         * LEVEL_DEBUG:600 で定義することで、INFO より細かいが、FINE より荒いログ出力が可能です。
053         * 他のアプリケーションで、INFO は許せても、FINE は許せない場合があるので、独自のログ出力が、可能です。
054         */
055        private static final class LEVEL_DEBUG extends Level {
056                private static final long serialVersionUID = 681020170714L ;            // 6.8.1.0 (2017/07/14)
057                /**
058                 * デバッグレベルのコンストラクター
059                 */
060                public LEVEL_DEBUG() { super( "DEBUG",600 ); }
061        };
062
063//      private static final Level DEBUG = new LEVEL_DEBUG();
064        private static final Level L_DEBUG = new LEVEL_DEBUG();                                 // 6.9.7.0 (2018/05/14) PMD Field DEBUG has the same name as a method
065
066        private final Logger LOGGER;
067
068        /**
069         * 名前を指定して、XLoggerオブジェクトを作成します。
070         *
071         * @og.rev 6.8.1.5 (2017/09/08) logフォルダの存在チェックと作成
072         *
073         * @param       name     ロガーの名前。通常は、クラス.class.getName() を渡せばよいです。
074         */
075        private XLogger( final String name ) {
076//              FileUtil.mkdirs( Paths.get( "log" ) );          // Logger の log フォルダが無ければ作成します。
077
078                LOGGER = Logger.getLogger( name );
079        }
080
081        /**
082         * 名前を指定して、XLoggerオブジェクトを作成します。
083         *
084         * @og.rev 7.2.1.0 (2020/03/13) ロガーの名前から、共通部分を削除します。
085         * @og.rev 7.2.5.0 (2020/06/01) 各クラスで、class.getSimpleName() を渡すようにした。
086         *
087         * @param       name     ロガーの名前。通常は、クラス.class.getName() を渡せばよいです。
088         * @return      XLoggerオブジェクト
089         */
090        public static XLogger getLogger( final String name ) {
091//              String key = name ;
092//              if( key.startsWith( OMIT_NAME ) ) {
093//                      key = name.substring( OMIT_NAME.length() );
094//              }
095
096//              return new XLogger( name );             // 今は、個別に作成していますが、本来は、同じオブジェクトを返すようにすべき。
097                return new XLogger( name );             // 各クラスで static で持つのでキャッシュしません。
098        }
099
100        /**
101         * INFO レベルのログをとります。
102         *
103         * 引数は Supplier のみなので、実行直前まで処理されません。
104         * よって、呼出元では、log level guards する必要はありません。
105         *
106         * @og.rev 7.3.0.0 (2021/01/06) PMD:GuardLogStatement:  Logger calls should be surrounded by log level guards.
107         *
108         * @param       msgSupplier     呼び出されると、目的のログ・メッセージを生成する関数
109         * @see         Logger#info( Supplier )
110         */
111        public void info( final Supplier<String> msgSupplier ) {
112                if( LOGGER.isLoggable( Level.INFO ) ) {
113                        LOGGER.info( msgSupplier );
114                }
115        }
116
117        /**
118         * WARNING レベルのログをとります。
119         *
120         * 引数は Supplier のみなので、実行直前まで処理されません。
121         * よって、呼出元では、log level guards する必要はありません。
122         *
123         * @og.rev 7.3.0.0 (2021/01/06) PMD:GuardLogStatement:  Logger calls should be surrounded by log level guards.
124         *
125         * @param       msgSupplier     呼び出されると、目的のログ・メッセージを生成する関数
126         * @see         Logger#warning( Supplier )
127         */
128        public void warning( final Supplier<String> msgSupplier ) {
129                if( LOGGER.isLoggable( Level.WARNING ) ) {
130                        LOGGER.warning( msgSupplier );
131                }
132        }
133
134        /**
135         * WARNING レベルのログが、処理されるか、判定します。
136         *
137         * 引数が Supplier のみでない場合は、実行前に、log level guards してください。
138         *
139         * @og.rev 7.3.0.0 (2021/01/06) 新規追加
140         *
141         * @return  args        WARNINGレベルのログを出力する場合は、trueを返します。
142         */
143        public boolean isWarningEnabled() {
144                return LOGGER.isLoggable( Level.WARNING );
145        }
146
147        /**
148         * WARNING レベルのログをとります。
149         *
150         * 引数処理が発生しますので、呼出元で、log level guards してください。
151         *
152         * if( XLogger.isWarningEnabled() ) {
153         *    XLogger.warning( id,args1,args2,… );
154         * }
155         *
156         * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
157         *
158         * @param id    リソースのキーとなるID。
159         * @param args  リソースを、MessageFormat.format で加工する場合の引数。
160         * @see         Logger#warning( Supplier )
161         */
162        public void warning( final String id , final Object... args ) {
163                LOGGER.warning( MsgUtil.errPrintln( id,args ) );
164        }
165
166        /**
167         * WARNING レベルのログをとります。
168         *
169         * これは、Throwable を引数に取る拡張されたメソッドです。
170         * 引数処理が発生しますので、呼出元で、log level guards してください。
171         *
172         * @param       th      ログ・メッセージに関連したThrowable。
173         * @param       msgSupplier     呼び出されると、目的のログ・メッセージを生成する関数
174         * @see         Logger#log( Level,Throwable,Supplier )
175         */
176        public void warning( final Throwable th , final Supplier<String> msgSupplier ) {
177                LOGGER.log( Level.WARNING , th , msgSupplier );
178        }
179
180        /**
181         * WARNING レベルのログをとります。
182         *
183         * これは、Throwable を引数に取る拡張されたメソッドです。
184         * 引数処理が発生しますので、呼出元で、log level guards してください。
185         *
186         * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
187         *
188         * @param th    発生元のThrowable( null値は許容されます )
189         * @param id    リソースのキーとなるID。
190         * @param args  リソースを、MessageFormat.format で加工する場合の引数。
191         * @see         Logger#log( Level,Throwable,Supplier )
192         */
193        public void warning( final Throwable th , final String id , final Object... args ) {
194                LOGGER.log( Level.WARNING , MsgUtil.errPrintln( id,args ) , th );                       // 1.4.0 (2019/10/01) StackTraceの重複を避けるため
195        }
196
197        /**
198         * 600 レベルのログをとります。
199         *
200         * Supplierを引数に、Level = 600 のログをとります。
201         *
202         * 引数は Supplier のみなので、実行直前まで処理されません。
203         * よって、呼出元では、log level guards する必要はありません。
204         *
205         * @og.rev 7.3.0.0 (2021/01/06) PMD:GuardLogStatement:  Logger calls should be surrounded by log level guards.
206         *
207         * @param       msgSupplier     呼び出されると、目的のログ・メッセージを生成する関数
208         * @see         Logger#log( Level,Supplier )
209         */
210        public void debug( final Supplier<String> msgSupplier ) {
211//              LOGGER.log( DEBUG , msgSupplier );
212                if( LOGGER.isLoggable( L_DEBUG ) ) {
213                        LOGGER.log( L_DEBUG , msgSupplier );
214                }
215        }
216
217        /**
218         * WARNING レベルのログが、処理されるか、判定します。
219         *
220         * 引数が Supplier のみでない場合は、実行前に、log level guards してください。
221         *
222         * @og.rev 7.3.0.0 (2021/01/06) 新規追加
223         *
224         * @return  args        WARNINGレベルのログを出力する場合は、trueを返します。
225         */
226        public boolean isDebugEnabled() {
227                return LOGGER.isLoggable( L_DEBUG );
228        }
229
230        /**
231         * 数値の変数を受け取って表示する、600 レベルのログをとります。
232         *
233         * Supplierを引数に、Level = 600 のログをとります。
234         * 関数型インタフェースは引数にfinal変数しか使えませんが、数値は大抵可変なので
235         * final化せずに、引数として渡すことが出来るようにします。
236         * 引数処理が発生しますので、呼出元で、log level guards してください。
237         *
238         * @og.rev 7.2.5.0 (2020/06/01) メソッド追加。
239         *
240         * @param       num                     数値引数
241         * @param       msgFunction     呼び出されると、目的のログ・メッセージを生成する関数
242         * @see         Logger#log( Level,Supplier )
243         */
244        public void debug( final int num , final Function<Integer,String> msgFunction ) {
245                LOGGER.log( L_DEBUG , () -> msgFunction.apply( num ) );
246        }
247}