SLF4j-Log4j-JCL-JUL
<!-- JCL(Jakarta Commons Logging) commons-logging.jar, log4j.jar + log4j.properties or log4j.xml commons-logging.properties //Is optional, but is recommended, if absent, will guess(discover) your preferred logging system dynamically in some order. Theory: LogFactory guess (discover) your preferred logging system dynamically. 1) LogFactory.getAttribute("org.apache.commons.logging.Log"), this attribute can be set by code LogFactory.setAttribute() or set it in commons-logging.properties(preferred) 2) System property of org.apache.commons.logging.Log 3) Log4J.jar 4) If the application is executing on a JDK 1.4 system, use the corresponding wrapper class (Jdk14Logger). 5) Fall back to the default simple logging wrapper (SimpleLog). Best practice: commons-logging.properties: If you have a particular preference then providing a simple commons-logging.properties file which specifies the concrete logging library to be used is recommended Log Level: 1.trace (the least serious) 2.debug 3.info 4.warn 5.error 6.fatal (the most serious) Fault: 1) Use class loader to discover logging system dynamically, so it conflicts with OSGi. 2) log.isInfoEnabled() deduces the code readability. SLF4J(Simple Logging Facade for Java) A abstract layer of logging, like commons-logging, need a concrete log framework: JUL(java.util.logging), Log4j, Loback Features 1) Binding log implementation statically, so it can be used with OSGi. 2) No need "if log.isInfoEnabled()" 3) Use placeholder : log.info("Hello {0}, {1}", "Alice", "Bob"); Usage Log4j: slf4j-api.jar, slf4j-log4j.jar, log4j.jar Logback: slf4j-api.jar, logback.jar JUL: slf4j-api.jar, slf4j-jdk14.jar Simple: slf4j-api.jar, slf4j-simple.jar None: slf4j-api.jar, slf4j-nop.jar Redirect to Slf4J log4j-over-slf4j.jar replace log4j.jar jcl-over-slf4j.jar replace commons-logging.jar Add jul-to-slf4j.jar Error Exception in thread "main" java.lang.StackOverflowError at java.util.Hashtable.containsKey(Hashtable.java:306) at org.apache.log4j.Log4jLoggerFactory.getLogger(Log4jLoggerFactory.java:36) at org.apache.log4j.LogManager.getLogger(LogManager.java:39) Reason dependency cycle: Slf4j redirect to Log4j, and Log4j redirect to Slf4j classpath: slf4j-log4j.jar, log4j-over-slf4j.jar Logback(https://logback.qos.ch, successor of Log4j, native implementation of slf4j, no need slf4j adapter) logback-classic will import logback-core and slf4j. logback.xml <?xml version="1.0" encoding="UTF-8"?> <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL --> <configuration scan="false" debug="false"> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %caller %msg%n</pattern> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %replace(%caller{1}){'\bCaller\+0\s\sat',''} - %msg%n</pattern> --> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %level %replace(%caller{1}){'\bCaller\+0\s\sat',''} - %msg%n</pattern> </encoder> </appender> <root level="debug"> <appender-ref ref="STDOUT" /> </root> </configuration> JUL(java.util.logging) JUL log level: FINEST,FINER,FINE (TRACE), CONFIG (DEBUG), INFO, WARNING, SEVERE(ERROR), ALL, OFF import java.util.logging.Formatter; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; public class Test { public static void main(String[] args) { Logger log = Logger.getLogger(ODNTest.class.getName()); log.setLevel(Level.ALL); //Useless, solution: \jdk8\jre\lib\logging.properties\java.util.logging.ConsoleHandler.level = ALL /* ConsoleHandler consoleHandler = new ConsoleHandler(); consoleHandler.setLevel(Level.ALL); log.addHandler(consoleHandler); */ /* FileHandler fileHandler = new FileHandler("C:/testlog%g.log"); fileHandler.setLevel(Level.ALL); fileHandler.setFormatter(new MyLogFormater()); log.addHandler(fileHandler); */ log.severe("Severe 111"); log.warning("Warning 222"); log.info("Info 333"); log.config("Config 444"); log.fine("Fine 555"); log.finer("Finer 666"); log.finest("Finest 777"); } } class MyLogFormater extends Formatter { public String format(LogRecord record) { return record.getLevel() + ":" + record.getMessage()+"\n"; } } logback.xml <!-- OFF, FATAL, ERROR, WARN, INFO, DEBUG, TRACE, ALL --> <configuration scan="true" scanPeriod="60 seconds" debug="false"> <property name="log_dir" value="c:/tmp" /> <property name="maxHistory" value="7" /> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%thread] %replace(%caller{1}){'\bCaller\+0\s\sat',''} %m%n</pattern> <!-- <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %level [%thread] %logger %m %n</pattern> --> </encoder> </appender> <appender name="fileAppender" class="ch.qos.logback.core.rolling.RollingFileAppender"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <fileNamePattern>${log_dir}/pim_%d{yyyyMMdd}.log</fileNamePattern> <maxHistory>${maxHistory}</maxHistory> </rollingPolicy> <encoder> <charset>UTF-8</charset> <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%thread] %logger [%file:%line] - %msg%n</pattern> </encoder> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <maxFileSize>10MB</maxFileSize> </triggeringPolicy> </appender> <logger name="org.apache.ibatis" level="INFO"/> <root level="info"> <appender-ref ref="STDOUT"/> <appender-ref ref="fileAppender"/> </root> </configuration> -->