logback是log4j团队创建的开源日志组件。与log4j类似,但是比log4j更强大,是log4j的改良版本。主要优势在于:
a) 更快的实现,logback内核重写过,是的性能有了很大的提升,内存占用也更小。
b) logback-classic对slf4j进行了更好的集成
c) 自动重新加载配置文件,当配置文件修改后,logback-classic能自动重新加载配置文件
d) 配置文件能够处理不同的情况,开发人员在不同的环境下(开发,测试,生产)切换的时候,不需要创建多个文件,可以通过
e) 自动压缩已经打出来的日志文件:RollingFileAppender在产生新文件的时候,会自动压缩已经打印出来的日志文件。而且这个压缩的过程是一个异步的过程。
slf4j是一系列的日志接口,而log4j和logback是具体实现了的日志框架。
a) log4j是apache实现的一个开源日志组件
b) logback同样是由log4j的作者实现的,拥有更好的特性,是slf4j的原生实现
参见:详情
logger:作为日志的记录器,把它关联到对应的context后,主要用于存放日志对象,也可以定义日志类型,级别。
appender:主要用于指定日志输出的目的地。目的地可以是控制台,文件,远程套接字服务器,数据库mysql等。
layout:负责把时间转换成字符串,格式化日志信息的输出。
logger的日志级别主要包括:TRACE 定义在ch.qos.logback.classic.Level类中。 此外OFF表示关闭全部日志,ALL表示开启全部日志。 如果logger没有被分配日志级别,它将从有被分别日志级别的父类那里继承,root logger的默认级别是DEBUG 每一个logger都被关联到一个loggerContext中,loggerContext负责生产logger,也负责以树形结构排列各个logger。 logger的获取主要是通过org.slf4j.LoggerFactory的getLogger()方法获取。 getLogger()方法有两种实现方式 a) getLogger(Class Obj)通过传入一个类的形式,来进行logger对象和类的绑定。 b) getLogger(String name)方式是通过传入一个contextName的形式,来指定一个logger。 其中,用同一个名字调用该方法获取的永远都是同一个logger对象。 logback主要有以下三个模块: logback-core:所有logback模块的基础 logback-classic:是log4j的一个改良版本,同时完整的实现了slf4j api logback-access:访问模块和servlet容器集成,提供通过http来访问日志的功能。 我们可以看到@slf4j 的源码 上面的源码注解显示在一个类前加上一个@slf4j 注解,将会在代码中自动生成一个Logger对象。 a) 根节点 scan:此属性为true时,配置文件如果发生改变,将会重新加载,默认为true scanPeriod:设置监测配置文件是否有修改的时间间隔,默认为1分钟,如果没有指定时间单位,默认的单位是毫秒 debug:此属性决定是否打印出logback内部的日志信息,可实时查看logback的运行状态 b) 子节点 c) 子节点 name:用于指定appender的名称 class:用于指定appender全限定名 主要有三种类型:ConsoleAppender、FileAppender、RollingFileAppender ConsoleAppender:把日志输到控制台 FileAppender:把日志输到文件 RollingFileAppender:把日志输到文件并且进行定期的清理 d) 子节点 下面的配置文件摘自其他页面 Logger接口 这个接口需要被log4j或logback来实现。 LoggerFactory类 LoggerFactory是各种各样日志api用来生成Loggers的一个很有用的工厂类,尤其是log4j、logback和jdk的logging。其他的实现像NOPLogger和SimpleLogger也是支持的。 看一下它的getLogger方法,通过logger的name来获得logger实例 这里ILoggerFactory的getLogger(name),也是一个接口中的方法,需要logback去实现 获得ILoggerFactory实例的方法,想当于是初始化的过程 LogContext实现上面提到的ILoggerFactory接口 实现getLogger(name)方法 public static final Level OFF = new Level(OFF_INT, "OFF");
public static final Level ERROR = new Level(ERROR_INT, "ERROR");
public static final Level WARN = new Level(WARN_INT, "WARN");
public static final Level INFO = new Level(INFO_INT, "INFO");
public static final Level DEBUG = new Level(DEBUG_INT, "DEBUG");
public static final Level TRACE = new Level(TRACE_INT, "TRACE");
public static final Level ALL = new Level(ALL_INT, "ALL");
public static final int OFF_INT = Integer.MAX_VALUE;
public static final int ERROR_INT = 40000;
public static final int WARN_INT = 30000;
public static final int INFO_INT = 20000;
public static final int DEBUG_INT = 10000;
public static final int TRACE_INT = 5000;
public static final int ALL_INT = Integer.MIN_VALUE;
5.什么是logback的context上下文?
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//通过LoggerFactory获取
private static final Logger logger = LoggerFactory.getLogger(Blog.class);
6.logback中主要模块有哪些?
7.为什么有@slf4j的注解,就可以调用log实例写入日志?
* Example:
*
* @Slf4j
* public class LogExample {
* }
*
*
* will generate:
*
*
* public class LogExample {
* private static final org.slf4j.Logger log =
org.slf4j.LoggerFactory.getLogger(LogExample.class);
* }
*
8.logback的配置文件详解?
logback源码解析
slf4j
public interface Logger {
// 返回根logger的name
final public String ROOT_LOGGER_NAME = "ROOT";
// 返回当前Logger实例的name
public String getName();
// 判断trace级别是否打印
public boolean isTraceEnabled();
public void trace(String msg);
/**其他trace构造方法*/
// 判断debug级别是否打印
public boolean isDebugEnabled();
public void debug(String msg);
/**其他debug构造方法*/
// 判断info级别是否打印
public boolean isInfoEnabled();
public void info(String msg);
/**其他info构造方法*/
// 判断warn级别是否打印
public boolean isWarnEnabled();
public void warn(String msg);
/**其他warn构造方法*/
// 判断error级别是否打印
public boolean isErrorEnabled();
public void error(String msg);
/**其他error构造方法*/
}
/**
* The
LoggerFactory
is a utility class producing Loggers for
* various logging APIs, most notably for log4j, logback and JDK 1.4 logging.
* Other implementations such as {@link org.slf4j.impl.NOPLogger NOPLogger} and
* {@link org.slf4j.impl.SimpleLogger SimpleLogger} are also supported.
*/ public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public interface ILoggerFactory {
public Logger getLogger(String name);
}
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
logback
public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle
@Override
public final Logger getLogger(final String name) {
if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}
// if we are asking for the root logger, then let us return it without
// wasting time
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}
int i = 0;
Logger logger = root;
// check if the desired logger exists, if it does, return it
// without further ado.
Logger childLogger = (Logger) loggerCache.get(name);
// if we have the child, then let us return it without wasting time
if (childLogger != null) {
return childLogger;
}
// if the desired logger does not exist, them create all the loggers
// in between as well (if they don't already exist)
String childName;
while (true) {
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
// move i left of the last point
i = h + 1;
synchronized (logger) {
childLogger = logger.getChildByName(childName);
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
loggerCache.put(childName, childLogger);
incSize();
}
}
logger = childLogger;
if (h == -1) {
return childLogger;
}
}
}