<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany</groupId> <artifactId>SLF4JExam</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <!-- SLF4J and Logback-class and Logback-core --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.1</version> </dependency> <!-- DB Appender needs JDBC Driver --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.3-1101-jdbc41</version> </dependency> <!-- SMTP Appender needs JavaMail and Activation --> <dependency> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> <version>1.4</version> </dependency> <!-- GEventEvaluator Filter needs Groovy --> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.0.7</version> </dependency> <!-- JaninoEventEvaluator Filter needs Janino and Commons-Compiler --> <dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> <version>2.6.1</version> </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> </project>
package com.mycompany.logbackexam; import com.mycompany.logbackexam.app.buggy.BuggyClass; import com.mycompany.logbackexam.app.gentle.GentleClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static Logger logger = LoggerFactory.getLogger(App.class); public static void main(String[] args) { // slf4j には fatal は無い //logger.fatal("本当にやばいログ "); logger.error("普通にやばいログ "); logger.warn("ちょっとやばいログ "); logger.info("運用時に必要なログ "); logger.debug("開発時に必要なログ "); logger.trace("デスマ時に必要なログ"); BuggyClass buggy = new BuggyClass(); GentleClass gentle = new GentleClass(); buggy.doSomething(); gentle.doSomething(); } }
package com.mycompany.logbackexam.app.buggy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BuggyClass { private static Logger logger = LoggerFactory.getLogger(BuggyClass.class); public void doSomething() { // slf4j には fatal は無い //logger.fatal("本当にやばいログ "); logger.error("普通にやばいログ "); logger.warn("ちょっとやばいログ "); logger.info("運用時に必要なログ "); logger.debug("開発時に必要なログ "); logger.trace("デスマ時に必要なログ"); } }
package com.mycompany.logbackexam.app.gentle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class GentleClass { private static Logger logger = LoggerFactory.getLogger(GentleClass.class); public void doSomething() { // slf4j には fatal は無い //logger.fatal("本当にやばいログ "); logger.error("普通にやばいログ "); logger.warn("ちょっとやばいログ "); logger.info("運用時に必要なログ "); logger.debug("開発時に必要なログ "); logger.trace("デスマ時に必要なログ"); } }
<configuration> <!-- ##################### # pattern structure # ##################### http://logback.qos.ch/manual/layouts.html * %logger{length} log source. this is the argument of LoggerFactory.getLogger(class). %logger{0} prints class name. * %date{pattern}, %date{pattern, timezone} %date => 2006-10-20 14:06:49,812 (It's ISO8601) %date{dd MMM yyy;HH:mm:ss.SSS} => 20 oct. 2006;14:05:49.812 * %relative milliseconds elapsed from application start. * %level level * %message, %msg message * %n \n or \r\n * %thread thread * %mdc{key:-default} MDC * %class{length} log source. this came from stacktrace. very slow. * %file java source file name. very slow. * %caller{depth} show stack trace. very slow * %method method. very slow * %line line number. very slow * right padding msg = 12345 => %-10msg = "12345 " * highlight %highlight(%-5level) %cyan(%logger{0}) Jansi lib and <withJansi>true</withJansi> is needed if run on win. --> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <withJansi>true</withJansi> <encoder> <pattern>%date [%thread] %highlight(%-5level) %cyan(%-20logger{20}) %msg %n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration>
package com.mycompany.slf4jexam; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.core.util.StatusPrinter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class App { private static Logger logger = LoggerFactory.getLogger(App.class); public static void main(String[] args) { // slf4j には fatal は無い //logger.fatal("本当にやばいログ"); logger.error("普通にやばいログ"); logger.warn("ちょっとやばいログ"); logger.info("運用時に必要なログ"); logger.debug("開発時に必要なログ"); logger.trace("デスマ時に必要なログ"); // print internal state LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); StatusPrinter.print(lc); } }
2014-03-30 16:37:53,748 [main] ERROR c.m.slf4jexam.App 普通にやばいログ 2014-03-30 16:37:53,751 [main] WARN c.m.slf4jexam.App ちょっとやばいログ 2014-03-30 16:37:53,751 [main] INFO c.m.slf4jexam.App 運用時に必要なログ 2014-03-30 16:37:53,751 [main] DEBUG c.m.slf4jexam.App 開発時に必要なログ |- Could NOT find resource [logback.groovy] |- Could NOT find resource [logback-test.xml] |- Found resource [logback.xml] at [file:/Users/atsushi/NetBeansProjects/SLF4JExam/target/classes/logback.xml] |- debug attribute not set |- About to instantiate appender of type [ch.qos.logback.core.ConsoleAppender] |- Naming appender as [STDOUT] |- Assuming default type [ch.qos.logback.classic.encoder.PatternLayoutEncoder] for [encoder] property |- Setting level of ROOT logger to DEBUG |- Attaching appender named [STDOUT] to Logger[ROOT] |- End of configuration. |- Registering current configuration as safe fallback point
level ::= TRACE | DEBUG | INFO | WARN | ERROR | OFF
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <logger name="com.mycompany.logbackexam.app.buggy" level="DEBUG"/> <logger name="com.mycompany.logbackexam.app.gentle" level="WARN"/> <root level="OFF"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER1* c.m.l.a.b.BuggyClass 普通にやばいログ *LOGGER1* c.m.l.a.b.BuggyClass ちょっとやばいログ *LOGGER1* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 開発時に必要なログ *LOGGER1* c.m.l.a.g.GentleClass 普通にやばいログ *LOGGER1* c.m.l.a.g.GentleClass ちょっとやばいログ
素直に継承される
指定した level | 出力 level | |
root | OFF | - |
App | - | なし |
Buggy | DEBUG | DEBUG, INFO, WARN, ERROR |
Gentle | WARN | WARN, ERROR |
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <appender name="STDOUT2" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER2* %-20logger{20} %msg%n</pattern> </encoder> </appender> <appender name="STDOUT3" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER3* %-20logger{20} %msg%n</pattern> </encoder> </appender> <logger name="com.mycompany.logbackexam.app.buggy" level="DEBUG"> <appender-ref ref="STDOUT2" /> </logger> <logger name="com.mycompany.logbackexam.app.gentle" level="WARN"> <appender-ref ref="STDOUT3" /> </logger> <root level="OFF"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER2* c.m.l.a.b.BuggyClass 普通にやばいログ *LOGGER1* c.m.l.a.b.BuggyClass 普通にやばいログ *LOGGER2* c.m.l.a.b.BuggyClass ちょっとやばいログ *LOGGER1* c.m.l.a.b.BuggyClass ちょっとやばいログ *LOGGER2* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER2* c.m.l.a.b.BuggyClass 開発時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 開発時に必要なログ *LOGGER3* c.m.l.a.g.GentleClass 普通にやばいログ *LOGGER1* c.m.l.a.g.GentleClass 普通にやばいログ *LOGGER3* c.m.l.a.g.GentleClass ちょっとやばいログ *LOGGER1* c.m.l.a.g.GentleClass ちょっとやばいログ
指定した level | 出力 level | |||
root | OFF | STDOUT1 | - | - |
App | - | - | なし | なし |
Buggy | DEBUG | STDOUT2 | DEBUG, INFO, WARN, ERROR | STDOUT1, STDOUT2 |
Gentle | WARN | STDOUT3 | WARN, ERROR | STDOUT1, STDOUT3 |
level と appender が root から継承されている
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <appender name="STDOUT2" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER2* %-20logger{20} %msg%n</pattern> </encoder> </appender> <appender name="STDOUT3" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER3* %-20logger{20} %msg%n</pattern> </encoder> </appender> <logger name="com.mycompany.logbackexam.app.buggy" level="DEBUG" additivity="false"> <appender-ref ref="STDOUT2" /> </logger> <logger name="com.mycompany.logbackexam.app.gentle" level="WARN" additivity="false"> <appender-ref ref="STDOUT3" /> </logger> <root level="OFF"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER2* c.m.l.a.b.BuggyClass 普通にやばいログ *LOGGER2* c.m.l.a.b.BuggyClass ちょっとやばいログ *LOGGER2* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER2* c.m.l.a.b.BuggyClass 開発時に必要なログ *LOGGER3* c.m.l.a.g.GentleClass 普通にやばいログ *LOGGER3* c.m.l.a.g.GentleClass ちょっとやばいログ
<configuration> <property name="USER_HOME" value="/home/sebastien" /> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE" /> </root> </configuration>
java -DUSER_HOME="/home/sebastien" MyApp2
<configuration> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE" /> </root> </configuration>
<configuration> <property file="src/main/java/chapters/configuration/variables1.properties" /> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE" /> </root> </configuration>
properties ファイルの中で変数を使うことも可能
USER_HOME=/home/sebastien fileName=myApp.log destination=${USER_HOME}/${fileName}
USER_HOME=/home/sebastien
<configuration> <property resource="resource1.properties" /> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>${USER_HOME}/myApp.log</file> <encoder> <pattern>%msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="FILE" /> </root> </configuration>
<configuration> <insertFromJNDI env-entry-name="java:comp/env/appName" as="appName" /> <contextName>${appName}</contextName> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d ${CONTEXT_NAME} %level %msg %logger{50}%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="CONSOLE" /> </root> </configuration>
<configuration> <include file="src/main/java/chapters/configuration/includedConfig.xml"/> <root level="DEBUG"> <appender-ref ref="includedConsole" /> </root> </configuration>
<included> <appender name="includedConsole" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>"%d - %m%n"</pattern> </encoder> </appender> </included>
<configuration> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <!-- colorize --> <withJansi>true</withJansi> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg %n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT" /> </root> </configuration>
<configuration> <timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/> <appender name="FILE" class="ch.qos.logback.core.FileAppender"> <file>log-${bySecond}.txt</file> <encoder> <pattern>%logger{35} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="FILE" /> </root> </configuration>
<configuration> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <!-- Support multiple-JVM writing to the same log file --> <prudent>true</prudent> <!-- (1) daily rolling --> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>logFile.%d{yyyy-MM-dd}.log</fileNamePattern> <maxHistory>30</maxHistory> </rollingPolicy> <!-- (2) size rolling --> <!-- <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>logFile.%i.log</fileNamePattern> <minIndex>1</minIndex> <maxIndex>3</maxIndex> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>5MB</maxFileSize> </triggeringPolicy> --> <!-- (3) daily and size rolling --> <!-- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>mylog-%d{yyyy-MM-dd}.%i.txt</fileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>100MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> --> <encoder> <pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="FILE" /> </root> </configuration>
<configuration> <appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender"> <smtpHost>ADDRESS-OF-YOUR-SMTP-HOST</smtpHost> <to>EMAIL-DESTINATION</to> <to>ANOTHER_EMAIL_DESTINATION</to> <!-- additional destinations are possible --> <from>SENDER-EMAIL</from> <subject>TESTING: %logger{20} - %m</subject> <layout class="ch.qos.logback.classic.PatternLayout"> <pattern>%date %-5level %logger{35} - %message%n</pattern> </layout> </appender> <root level="DEBUG"> <appender-ref ref="EMAIL" /> </root> </configuration>
<configuration> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.DriverManagerConnectionSource"> <driverClass>org.postgresql.Driver</driverClass> <url>jdbc:postgresql://localhost:5432/demo</url> <user>atsushi</user> <password>**********</password> </connectionSource> </appender> <root level="DEBUG"> <appender-ref ref="DB" /> </root> </configuration>
JNDI 経由で Connection Pool を使うこともできる
<configuration debug="true"> <appender name="DB" class="ch.qos.logback.classic.db.DBAppender"> <connectionSource class="ch.qos.logback.core.db.JNDIConnectionSource"> <!-- please note the "java:comp/env/" prefix --> <jndiLocation>java:comp/env/jdbc/logging</jndiLocation> </connectionSource> </appender> <root level="INFO"> <appender-ref ref="DB" /> </root> </configuration>
<configuration> <appender name="SYSLOG" class="ch.qos.logback.classic.net.SyslogAppender"> <syslogHost>remote_home</syslogHost> <!-- default is 514 <port>514</port> --> <!-- KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP, NTP, AUDIT, ALERT, CLOCK, LOCAL0, LOCAL1, LOCAL2, LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7 --> <facility>AUTH</facility> <suffixPattern>[%thread] %logger %msg</suffixPattern> <!-- Out put the stackTracePattern string before each lines of the stack trace. default is \t. <stackTracePattern>\t</stackTracePattern> --> <!-- Don't send stacktraces to syslog doemon. default is false, ie. send stacktraces to syslog doemon. <throwableExcluded>false</throwableExcluded> --> </appender> <root level="DEBUG"> <appender-ref ref="SYSLOG" /> </root> </configuration>
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER1* c.m.logbackexam.App 運用時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER1* c.m.l.a.g.GentleClass 運用時に必要なログ
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <level>INFO</level> </filter> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER1* c.m.logbackexam.App 普通にやばいログ *LOGGER1* c.m.logbackexam.App ちょっとやばいログ *LOGGER1* c.m.logbackexam.App 運用時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 普通にやばいログ *LOGGER1* c.m.l.a.b.BuggyClass ちょっとやばいログ *LOGGER1* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER1* c.m.l.a.g.GentleClass 普通にやばいログ *LOGGER1* c.m.l.a.g.GentleClass ちょっとやばいログ *LOGGER1* c.m.l.a.g.GentleClass 運用時に必要なログ
<configuration> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator> <!-- defaults to type ch.qos.logback.classic.boolex.JaninoEventEvaluator --> <expression>return message.contains("必要");</expression> </evaluator> <OnMismatch>DENY</OnMismatch> <OnMatch>ACCEPT</OnMatch> </filter> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT1" /> </root> </configuration>
*LOGGER1* c.m.logbackexam.App 運用時に必要なログ *LOGGER1* c.m.logbackexam.App 開発時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 運用時に必要なログ *LOGGER1* c.m.l.a.b.BuggyClass 開発時に必要なログ *LOGGER1* c.m.l.a.g.GentleClass 運用時に必要なログ *LOGGER1* c.m.l.a.g.GentleClass 開発時に必要なログ
<filter class="ch.qos.logback.core.filter.EvaluatorFilter"> <evaluator> <matcher> <Name>odd</Name> <!-- filter out odd numbered statements --> <regex>statement [13579]</regex> </matcher> <expression>odd.matches(formattedMessage)</expression> </evaluator> <OnMismatch>NEUTRAL</OnMismatch> <OnMatch>DENY</OnMatch> </filter>
<configuration> <turboFilter class="ch.qos.logback.classic.turbo.DuplicateMessageFilter"> <!-- Default AllowedRepetitions is 5. <AllowedRepetitions>2</AllowedRepetitions> --> <!-- Default CacheSize is 100. <CacheSize>100</CacheSize> --> </turboFilter> <appender name="STDOUT1" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>*LOGGER1* %-20logger{20} %msg%n</pattern> </encoder> </appender> <root level="DEBUG"> <appender-ref ref="STDOUT1" /> </root> </configuration>
logger.info("{} sheep.", 1); logger.info("{} sheep.", 2); logger.info("{} sheep.", 3); logger.info("{} sheep.", 4); logger.info("{} sheep.", 5); logger.info("{} sheep.", 6); logger.info("{} sheep.", 7); logger.info("{} sheep.", 8); logger.info("{} sheep.", 9); logger.info("Yawn."); logger.info("{} sheep.", 1); logger.info("{} sheep.", 2); logger.info("{} sheep.", 3); logger.info("{} sheep.", 4); logger.info("{} sheep.", 5); logger.info("{} sheep.", 6); logger.info("{} sheep.", 7); logger.info("{} sheep.", 8); logger.info("{} sheep.", 9);
--- exec-maven-plugin:1.2.1:exec (default-cli) @ SLF4JExam --- *LOGGER1* c.m.logbackexam.App 1 sheep. *LOGGER1* c.m.logbackexam.App 2 sheep. *LOGGER1* c.m.logbackexam.App 3 sheep. *LOGGER1* c.m.logbackexam.App 4 sheep. *LOGGER1* c.m.logbackexam.App 5 sheep. *LOGGER1* c.m.logbackexam.App 6 sheep. *LOGGER1* c.m.logbackexam.App Yawn. ------------------------------------------------------------------------
<turboFilter class="ch.qos.logback.classic.turbo.MDCFilter"> <MDCKey>username</MDCKey> <Value>sebastien</Value> <OnMatch>ACCEPT</OnMatch> </turboFilter> <turboFilter class="ch.qos.logback.classic.turbo.MarkerFilter"> <Marker>billing</Marker> <OnMatch>DENY</OnMatch> </turboFilter>