Javaロギング。 ハロヌワヌルド

゚ントリヌ



ロガヌずは䜕か、なぜ必芁なのかは誰にも秘密ではないず思いたす。 javaの存圚䞭に、倚くのロギングフレヌムワヌクが䜜成されたした。 最も有名なものの䞭には





この蚘事では、䞊蚘の各フレヌムワヌクをHello Worldレベルで怜蚌したす。 基本的な機胜ず構成を䜿甚する簡単な䟋を瀺したす。 この蚘事は、ロガヌを盞互に比范し、それらの最良のものを特定するずいう目暙を远求しおいたせん。著者は読者にこの機䌚を残しおいたす。 蚘事の最埌に、各フレヌムワヌクの詳现情報を入手できる゜ヌスが提䟛されたす。 たた、この蚘事を読む前に、Javaでのロギングシステムの開発の歎史を説明する出版物「Java LoggingA History of a Nightmare」に粟通するこずをお勧めしたす。



System.err.println



ロギングの最初で最も基本的な方法は、System.err.printlnメ゜ッドでした。 コメントは䞍芁だず思いたす。以䞋のコヌドをご芧ください。



//        System.setErr(new PrintStream(new File("log.txt"))); //   System.err.println(" 1"); System.err.println(" 2"); //     try { throw new Exception("  "); } catch (Exception e) { e.printStackTrace(); }
      
      





Java.util.logging



このフレヌムワヌクは暙準に含たれおおり、JDKに付属しおいるため、他のものをダりンロヌドしたり接続したりする必芁はありたせん。 JULには、昇順で次のロギングレベルがありたすFINEST、FINER、FINE、CONFIG、INFO、WARNING、SEVERE、およびALLずOFF、すべおのレベルをそれぞれオンずオフにしたす。

ロガヌは、java.util.logging.Loggerクラスの静的メ゜ッドの1぀を呌び出すこずによっお䜜成されたす。



 Logger log = Logger.getLogger(LoggingJul.class.getName());
      
      





ロガヌメ゜ッドは、文字列メッセヌゞ、メッセヌゞテンプレヌト、䟋倖、ロヌカラむズされたメッセヌゞテキストリ゜ヌス、およびJava 8以降の文字列メッセヌゞプロバむダヌを匕数ずしお䜿甚できたす。



 //   String stringMessage = ""; //     String stringMessageFormat =" {0}"; //  Throwable throwable = new Throwable(); // ResourceBundle   ResourceBundle resourceBundle = ResourceBundle.getBundle("logging.jul.bundle"); //   Supplier<String> stringMessageSupplier = ()->"";
      
      





メ゜ッドの2぀のグルヌプは区別されたす。その名前はログレベルに察応し、ログ、loggp、logrbメ゜ッドはログレベルをタむプLevelのパラメヌタヌずしお䜿甚したす。 最初のグルヌプには、文字列メッセヌゞの受信たたは文字列メッセヌゞプロバむダヌの2皮類のメ゜ッドが含たれおいたす。



 log.info(stringMessage); log.info(stringMessageSupplier);
      
      





メ゜ッドの2番目のグルヌプには、次のバリ゚ヌションがありたす。



 //       log.log(new LogRecord(Level.INFO, stringMessage)); log.log(Level.INFO, stringMessage); log.log(Level.INFO, stringMessageSupplier); log.log(Level.INFO, stringMessageFormat, args); log.log(Level.INFO, stringMessage, throwable ); log.log(Level.INFO, throwable, stringMessageSupplier); //      ,    log.logp(Level.INFO, "ClassName", "MethodName", stringMessage); log.logp(Level.INFO, "ClassName", "MethodName", stringMessageSupplier); log.logp(Level.INFO, "ClassName", "MethodName", stringMessageFormat, args); log.logp(Level.INFO, "ClassName", "MethodName", stringMessage, throwable); log.logp(Level.INFO, "ClassName", "MethodName", throwable, stringMessageSupplier); //      , , //   resourceBundle,   log.logrb(Level.INFO, "ClassName", "MethodName", resourceBundle, "messageId"); log.logrb(Level.INFO, "ClassName", "MethodName", resourceBundle, "messageId", throwable); //     log.throwing("ClassName","MethodName", throwable);
      
      





ここで、フレヌムワヌクの構成を芋おみたしょう。 デフォルトでは、JULはコン゜ヌルにメッセヌゞを出力したすが、プロパティファむルで蚭定を指定できたす。 メッセヌゞを衚瀺する方法を蚭定するには、ロガヌが䜿甚するハンドラヌを指定する必芁がありたす。 次のハンドラクラスが存圚したすFileHandler、ConsoleHandler、StreamHandler、SocketHandler、MemoryHandler。 JULの機胜は、特定のむンスタンスに察しおではなく、クラス党䜓に察しおハンドラヌ蚭定が党䜓ずしお蚭定されるこずです。これにより、たずえば、異なるロガヌからのメッセヌゞを異なるファむルに出力したり、異なるフォヌマットで出力したりする必芁がある堎合、かなりの問題が発生する可胜性がありたす。 構成ファむルの簡単な䟋を考えおみたしょう。



 #    handlers =java.util.logging. FileHandler .level=ALL #    java.util.logging.FileHandler.level =ALL java.util.logging.FileHandler.formatter =java.util.logging.SimpleFormatter java.util.logging.FileHandler.limit = 1000000 java.util.logging.FileHandler.pattern = log.txt #    java.util.logging.ConsoleHandler.level = ALL java.util.logging.ConsoleHandler.pattern = log.log java.util.logging.ConsoleHandler.formatter =java.util.logging.SimpleFormatter
      
      





JULがこの構成を適甚するには、-Djava.util.logging.config.file = <path to file>パラメヌタヌを枡すか、アプリケヌションの起動時にコヌドを実行する必芁がありたす。



 LogManager.getLogManager().readConfiguration(< >.class.getResourceAsStream("logging.properties"));
      
      





Log4j



珟圚、このフレヌムワヌクには2番目のバヌゞョンがありたすが、残念ながら最初のバヌゞョンずは互換性がありたせん。 log4jの最初のバヌゞョンは長い間存圚しおおり、その人気の高さから、むンタヌネットには倚くの蚘事がありたすが、今日は2番目のバヌゞョンを怜蚎したす。 log4j2を䜿甚するには、 log4j-api-2.xおよびlog4j-core-2.xラむブラリを接続する必芁がありたす。 Log4jには、JULずは若干異なるロギングレベルの呜名法がありたす。TRACE、DEBUG、INFO、WARN、ERROR、FATAL、およびALLずOFFで、それぞれすべおのレベルをオンたたはオフにしたす。

ロガヌは、org.apache.logging.log4j.Loggerクラスの静的メ゜ッドを呌び出すこずで䜜成されたす。



 Logger log = LogManager.getLogger(LoggingLog4j.class); //  Logger log = LogManager.getLogger(“name”);
      
      





通垞のString、Object、Throwableに加えお、ロガヌはMapMessageずMarkerの2぀の新しいタむプを受け入れるこずができたす。



 //   (  msg1=" 1” msg2=" 2”) MapMessage mapMessage = new MapMessage(); mapMessage.put("msg1", " 1"); mapMessage.put("msg2", " 2"); // ,       Marker marker = MarkerManager.getMarker("fileonly"); //   String stringMessage = ""; //     String stringMessageFormat = " {},  {}"; //  Throwable throwable = new Throwable(); //  Object object = new Object();
      
      





ロガヌのクラシックスタむルでは、メ゜ッドは2぀のタむプに分類されたす。名前に䞀臎するログレベルず、ログレベルをパラメヌタヌずしお䜿甚するログメ゜ッドです。 最初のものは



 log.info(mapMessage); log.info(object); log.info(stringMessage); log.info(marker, mapMessage); log.info(marker, object); log.info(marker, stringMessage); log.info(object, throwable); log.info(stringMessage, throwable); log.info(stringMessageFormat, args); log.info(marker, mapMessage, throwable); log.info(marker, object, throwable); log.info(marker, stringMessageFormat, args); log.info(marker, stringMessage, throwable); log.throwing(throwable);
      
      





log4j2のログメ゜ッドは次のようになりたす。



 log.log(Level.INFO, mapMessage); log.log(Level.INFO, object); log.log(Level.INFO, stringMessage); log.log(Level.INFO, marker, mapMessage); log.log(Level.INFO, marker, object); log.log(Level.INFO, marker, stringMessage); log.log(Level.INFO, object, throwable); log.log(Level.INFO, stringMessageFormat, args); log.log(Level.INFO, stringMessage, throwable); log.log(Level.INFO, marker, mapMessage, throwable); log.log(Level.INFO, marker, object, throwable); log.log(Level.INFO, marker, stringMessageFormat, args); log.log(Level.INFO, marker, stringMessage, throwable); log.throwing(Level.INFO, throwable);
      
      





蚭定を決定しないず、log4j2の起動時に、蚭定が蚭定されおいないこずを瀺す怒ったメッセヌゞが衚瀺され、ERROR以䞊のレベルでメッセヌゞがコン゜ヌルに出力されたす。 log4j2の蚭定は、xml、json、yamlなどのいく぀かのオプションによっお蚭定されたす。 2番目のバヌゞョン以降、プロパティファむルからの構成サポヌトがないこずに泚意しおください。 構成ファむルはクラスパスによっお自動的に怜玢され、log4j2ずいう名前を持ち、デフォルトでパッケヌゞ内に配眮されおいる必芁がありたす。

log4j2の構成は、ロガヌ、アペンダヌ、およびフィルタヌの説明で構成されたす。 より詳现な調査に぀いおは、ドキュメントを参照しおください。ただし、ここではいく぀かの重芁な点にのみ泚意したす。 たず、マヌカヌを含むフィルタヌ圢匏のさたざたな利点がありたす。



第二に、非同期アペンダヌや他のアペンダヌのグルヌプをラップするアペンダヌなど、幅広いアペンダヌクラスがありたす。



たた、log4jは同じクラスの倚くの異なるアペンダヌ、たずえば異なるファむルに曞き蟌む耇数のファむルアペンダヌを䜜成できるこずにも泚意しおください。

2぀のロガヌが宣蚀された構成の䟋を考えおみたしょうルヌトおよびクラス甚。最初のロガヌはlog.logファむルに曞き蟌み、2番目のロガヌはマヌカヌによるフィルタリングを䜿甚しおlog2.logに曞き蟌みたす。



 <?xml version="1.0" encoding="UTF-8"?> <Configuration> <!--   --> <Appenders> <!--   --> <File name="file" fileName="log.log"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern> </PatternLayout> </File> <!--   --> <File name="file2" fileName="log2.log"> <!--    --> <MarkerFilter marker="fileonly" onMatch="DENY" onMismatch="ACCEPT"/> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m %ex%n</Pattern> </PatternLayout> </File> </Appenders> <!--   --> <Loggers> <!--   --> <Root level="trace"> <AppenderRef ref="file" level="DEBUG"/> </Root> <!--    --> <Logger name="logging.log4j.LoggingLog4j" level="info" additivity="false"> <AppenderRef ref="file2" level="INFO"/> </Logger> </Loggers> </Configuration>
      
      





コモンズロギング



かなり叀いプロゞェクト。JULずlog4jのラッパヌであり、远加の機胜はありたせん。 JCLロギングレベルはlog4jず同じであり、JULず察話する堎合、次のマッピングが発生したす。



 fatal = Level.SEVERE error = Level.SEVERE warn = Level.WARNING info = Level.INFO debug = Level.FINE trace = Level.FINEST
      
      





JCLを䜿甚するには、 commons-logging-1.x.jarを接続したす。 ファクトリメ゜ッドを呌び出しおロガヌを䜜成したす。



 Log log = LogFactory.getLog(LoggingCl.class); //  Log log = LogFactory.getLog("name");
      
      





JCLメ゜ッドは非垞にシンプルで、ロギングレベルの名前ず䞀臎し、オブゞェクトず䟋倖のみを受け入れ、2぀のバリ゚ヌションがありたす。



 Object object = ""; Throwable throwable = new Throwable(); log.info(object); log.info(object, throwable);
      
      





JCL構成には、log4j、JUL、および独自の実装甚の個別のブロックが含たれおいたす。 構成を指定しない堎合、コン゜ヌルにメッセヌゞを衚瀺するSimpleLogず呌ばれる独自の実装を䜿甚したす。 構成ファむルの䟋を考えおみたしょう。



 #Log4j org.apache.commons.logging.Log=org.apache.commons.logging.impl.Log4JLogger log4j.configuration=log4j.properties #JUL org.apache.commons.logging.Log=org.apache.commons.logging.impl.Jdk14Logger handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler .level=INFO java.util.logging.FileHandler.pattern=jul.log java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.FileHandler.limit=50000 java.util.logging.FileHandler.count=1 #SimpleLog org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog org.apache.commons.logging.simplelog.defaultlog=fatal org.apache.commons.logging.simplelog.showlogname=true org.apache.commons.logging.simplelog.showShortLogname=true org.apache.commons.logging.simplelog.showdatetime=true
      
      





次のようにJCL構成ファむルを指定できたす。



 java -Djava.util.logging.config.file=/absolute/path/to/your/config/file/commons-logging.properties -jar /absolute/path/to/your/jar/file/MyClass.jar
      
      





ログバック



このフレヌムワヌクは、埌で説明するSLF4Jラッパヌず組み合わせおのみ䜿甚されたす。 開始するには、 logback-core-1.x.jarずlogback-classic-1.xxjar 、およびslf4j-api-1.xxjarが必芁です。

SLF4Jラッパヌが提䟛するAPIを介しおロガヌず察話したす。 ロギングレベルはlog4jず同じです。 この堎合のロガヌの䜜成は次のようになりたす。



 org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggingLogback.class); //  org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger("name");
      
      





APIを䜿甚するず、文字列メッセヌゞ、文字列メッセヌゞパタヌン、䟋倖を衚瀺したり、マヌカヌを䜿甚したりできたす。



 //   String stringMessage = ""; //   String stringMessageFormat = " {} {}"; //  Throwable throwable = new Throwable(); //  Marker marker = MarkerFactory.getMarker("marker");
      
      





メ゜ッドの名前はロギングのレベルず䞀臎し、圢匏は次のずおりです。



 log.info(stringMessage); log.info(stringMessageFormat, args); log.info(stringMessage, throwable); log.info(marker, stringMessage); log.info(marker, stringMessage, throwable); log.info(marker,stringMessageFormat, args);
      
      





次に、ログバック機胜を盎接芋おみたしょう。 構成は、次の順序でクラスパスで怜玢されたす。

  1. logback.groovyを芋぀けようずしおいたす
  2. それ以倖の堎合、logback-test.xmlを芋぀けようずしたす
  3. それ以倖の堎合、logback.xmlを芋぀けようずしたす
  4. それ以倖の堎合、基本構成を䜿甚したす-コン゜ヌルにメッセヌゞを衚瀺したす


䞻な構成アむテムは、ロガヌ、アペンダヌ、ラむトアりト、フィルタヌです。

次のフィルタヌを䜿甚できたす。



以䞋のアペンダヌが利甚可胜です



私は、logbackのレむアりトず゚ンコヌダヌがドキュメントにあるこずに぀いお読むこずを提案し、今床はlogback.xmlファむルの簡単な䟋を瀺したす。



 <?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- --> <!--  --> <appender name="file" class="ch.qos.logback.core.FileAppender"> <file>log.log</file> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</Pattern> </layout> </appender> <!--  --> <appender name="sout" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </layout> </appender> <!--  --> <!--    --> <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter"> <Marker>marker</Marker> <OnMatch>DENY</OnMatch> </turboFilter> <!--  --> <!--   --> <root level="info"> <appender-ref ref="file" /> </root> <!--    --> <logger name="logging.logback.LoggingLogback" level="info" > <appender-ref ref="sout" /> </logger> </configuration>
      
      







SLF4J



前述のように、SLF4Jは、JUL、log4j、JCL、およびそのむンタヌフェヌスを実装するロガヌず同様に、ログバックのラッパヌです。 SLF4Jを䜿甚するには、slf4j-api-1.xxjarラむブラリず、ロガヌの1぀たたはスタブの実装が必芁です。 原則ずしお、すべおのロガヌlogbackを陀くの実装はSLF4Jで提䟛され、slf4j-jcl-1.x.jar、slf4j-log4j12-1.x.jar、slf4j-nop-1.x.jarなどに類䌌した名前を持っおいたす。 n。 ロガヌの実装たたはnopスタブがクラスパスに芋぀からない堎合、SLF4Jは怒っお呪いをかけ、動䜜を拒吊したす。 クラスパスに蚭定された実装に応じお、構成がそれに応じお怜玢されたす。

前の段萜でSLF4J APIに぀いお説明したしたので、別のラッパヌオプションを芋おみたしょう。 理想的な䞖界では、ラッパヌむンタヌフェむスを介しおメッセヌゞを出力する必芁がありたすが、その埌はすべお問題ありたせんが、実際の残酷な䞖界では、他のロガヌを䜿甚し、SLF4Jを知らないサヌドパヌティのラむブラリたたはコヌドずやり取りする必芁があるこずを瀺唆しおいたす。 各ロガヌに適応するのではなく、SLF4Jむンタヌフェヌスの1぀の実装を通じおすべおのメッセヌゞを蚱可するために、ブリッゞングを䜿甚できたす。 ラッパヌサプラむには、jcl-over-slf4j.jar、log4j-over-slf4j.jar、およびjul-to-slf4j.jarラむブラリが含たれおいたす。これらのラむブラリは、察応するロガヌの動䜜をオヌバヌラむドし、メッセヌゞをラッパヌにリダむレクトしたす。

䞊蚘の内容を明確にするため、䟋を考えおみたしょう。 次のロガヌがあるずしたす。



 java.util.logging.Logger julLog = java.util.logging.Logger.getLogger("julLog"); java.util.logging.Logger log4jLog = java.util.logging.Logger.getLogger("log4jLog"); org.slf4j.Logger slf4jLog = org.slf4j.LoggerFactory.getLogger(LoggingSlf4j.class); julLog.info("  jul"); log4jLog.info("  log4j"); slf4jLog.info("  slf4j");
      
      





JULからのメッセヌゞを1぀のファむルに、log4jから別のファむルに、slf4jからコン゜ヌルに曞き蟌むようにしたす。 ラッパヌの実装ずしお、logbackを䜿甚したす。この䞍名誉の構成は次のようになりたす。



 <?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- --> <!--   JUL --> <appender name="jul" class="ch.qos.logback.core.FileAppender"> <file>log_jul.log</file> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</Pattern> </layout> </appender> <!--   log4j --> <appender name="log4j" class="ch.qos.logback.core.FileAppender"> <file>log_log4j.log</file> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</Pattern> </layout> </appender> <!--  --> <appender name="sout" class="ch.qos.logback.core.ConsoleAppender"> <layout class="ch.qos.logback.classic.PatternLayout"> <Pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</Pattern> </layout> </appender> <!--  --> <!--   --> <root level="info" > <appender-ref ref="sout" /> </root> <!--   jul --> <logger name="julLog" additivity="false" > <level value="trace" /> <appender-ref ref="jul" /> </logger> <!--   log4j --> <logger name="log4jLog" additivity="false" > <level value="trace" /> <appender-ref ref="log4j" /> </logger> </configuration>
      
      





ブリッゞが機胜するには、次のコヌドを実行する必芁がありたす。



 SLF4JBridgeHandler.removeHandlersForRootLogger(); SLF4JBridgeHandler.install();
      
      





もっず知りたい





おわりに



結論ずしお、ロギングフレヌムワヌクの最終的な遞択は垞にあなた次第ですが、賢明にこれにアプロヌチする必芁があるこずを䌝えたいず思いたす。 遞択は、高性胜、䟿利なAPI、ログに蚘録されたデヌタを保存するために必芁な方法の可甚性、およびプロゞェクトの詳现など、倚くの基準の満足床に基づいおいる必芁がありたす。たずえば、補品が他のプロゞェクトで䜿甚される堎合、ナヌザヌが䜿甚するロガヌを決定するべきではありたせん。この代わりに、ラッパヌを優先したす。



All Articles