日志包含程序运行时的逻辑信息、错误信息、事件描述信息、关键数据等,因此,可以通过这些信息帮助开发人员快速地发现和定位问题。因此,日志系统的学习和使用是提高开发效率的一种手段之一。
1.JDK Logger
优点:不需要集成任何类库,只要有JVM的运行环境,就可以直接使用,使用起来比较方便。
缺点:JDK自带的,耦合性比较高,扩展性较差。
JDK Logger将日志分为9个级别:all、finest、finer、fine、config、info、warning、severe、off,级别依次升高。
使用例子:
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class JDKLoggerDemo {
public static Logger logger = Logger.getLogger(JDKLoggerDemo.class.toString());
static{
Handler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
logger.addHandler(consoleHandler);
}
public static void main(String[] args){
logger.setLevel(Level.INFO);
logger.finest("finest log..");
logger.finer("finer log..");
logger.fine("fine log..");
logger.config("config log..");
logger.info("info log..");
logger.warning("warning log..");
logger.severe("severe log..");
}
}
运行结果:
通过运行结果可以看出,日志级别越高,打印的日志就越少,只有设定的级别以及高于设定级别的日志才会被输出。通过setLevel()来设定级别。
2.Apache Commons Logging
优点:采用了门面模式,只提供了日志接口,具体的实现则在运行时根据配置动态查找日志的实现框架,它的出现避免了和具体的日志实现框架的直接耦合。
缺点:Apache Commons Logging通过配置来动态地找到具体的实现类,如果具体的实现类不在类路径中或者被限制使用,则无法加载,例如在OSGI环境下类被分组后,就有可能出现加载不到底层实现类的情况。
实践例子:
首先在pom.xml文件中添加依赖:
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
代码:
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CommonsLoggingDemo {
private static Log log = LogFactory.getLog(CommonsLoggingDemo.class);
public static void main(String[] args){
log.debug("debug log..");
log.info("info log..");
log.warn("warn log..");
log.error("error log..");
log.fatal("fatal log..");
}
}
配置文件commons-logging.properties:
org.apache.commons.logging.log = org.apache.commons.logging.impl.Jdk14Logger
org.apache.commons.logging.LogFactory = org.apache.commons.logging.impl.LogFactoryImpl
运行结果如下:
3.Apache Log4j
优点:通过日志配置文件使得记录日志更加灵活简单,不需要更改应用层代码,耦合性低。
缺点:配置文件繁琐
实践例子:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
代码:
import org.apache.log4j.Logger;
public class Log4jDemo {
private static Logger log = Logger.getLogger(Log4jDemo.class);
public static void main(String[] args){
log.trace("trace log..");
log.debug("debug log..");
log.info("info log..");
log.warn("warn log..");
log.error("error log..");
log.fatal("fetal log..");
}
}
配置文件:
log4j.rootLogger = INFO, FILE, CONSOLE
log4j.appender.FILE = org.apache.log4j.FileAppender
log4j.appender.FILE.File = /home/robert/Log4jDemo.log
log4j.appender.FILE.ImmediateFlush = true
log4j.appender.FILE.Threshold = DEBUG
log4j.appender.FILE.Append = true
log4j.appender.FILE.layout = org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.conversionPattern = %d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.appender.CONSOLE = org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Target = System.out
log4j.appender.CONSOLE.ImmediateFlush = true
log4j.appender.CONSOLE.Threshold = DEBUG
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.encoding = UTF-8
log4j.appender.CONSOLE.layout.conversionPattern = %d{ABSOLUTE} %5p %c{1}:%L %m%n
运行结果:
Log4j通过同步变异步提升了性能,日志的收集作为一个辅助操作。
4.Slf4j
优点:门面模式,相对于Commons Logging做了一些修改和优化,在编译时确定底层的日志实现框架,而不是通过配置文件动态地装载底层的实现类,因此,只要底层的日志实现Jar包和Slf4j的静态编译转接包在类路径即可。Slf4j通过增加日志的中间转接层来转换相应的实现,能够有效避免在特殊的类加载环境下Commons Logging无法加载具体日志框架实现类的问题。
实现例子:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jLog4jDemo {
public static Logger logger = LoggerFactory.getLogger(Slf4jLog4jDemo.class);
public static void main(String[] args){
logger.error("error log..");
logger.warn("warn log..");
logger.info("info log..");
logger.debug("debug log..");
logger.trace("trace log..");
}
}
运行结果:
5.Logback
优点:该组件是针对Log4j进行的优化,相对于Log4j最大的提升就是效率,Logback对Log4j的内核进行了重写和优化,在一些关键执行路径上性能提升了至少10倍,初始化内存加载也变得更小了。
实现例子:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.20</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.1.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.1.7</version>
</dependency>
代码:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Slf4jLogbackDemo {
static Logger logger = LoggerFactory.getLogger(Slf4jLogbackDemo.class);
public static void main(String[] args){
logger.debug("debug log..");
logger.info("info log..");
logger.warn("warning log..");
logger.error("error log..");
logger.warn("login error..");
}
}
配置文件:
configuration>
<!-- 设置自定义pattern属性-->
<property name="pattern" value="%d{HH:mm:ss.SSS} [%-5level] [%thread][%logger] %msg%n"/>
<!-- 控制台输出日志-->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 设置控制台输出日志的格式-->
<encoder>
<pattern>${pattern}</pattern>
</encoder>
</appender>
<!-- 滚动记录日志文件:-->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/robert/log/log.out</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>testLog-%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${pattern}</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>
运行结果:
6.Apache Log4j2
优点:Apache Log4j 2是Log4j的升级版本,不但提供了高性能,而且提供了对Log4j1.2、Slf4j、Commons Logging和Java Logger的支持,通过log4j-to-slf4j的兼容模式,使用Log4j 2API的应用完全可以转接到Slf4j支持的任何日志框架上。与Logback一样,Log4j2 可以动态地加载修改过的配置,在动态加载的过程中不会丢失日志。
实现例子:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.5</version>
</dependency>
代码:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class Log4j2Demo {
public static void main(String[] args){
Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
logger.trace("trace log..");
logger.debug("debug log..");
logger.info("info log..");
logger.warn("warn log..");
logger.error("error log..");
logger.fatal("fatal log..");
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<Loggers>
<Root level="debug">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
运行结果:
综上所述,Log4j2、Logback和Slf4j三种具有更好的性能,而在异步性能上,Log4j2具有优势。