Logback详解

问题/释疑

1.logback是什么?

        logback是log4j团队创建的开源日志组件。与log4j类似,但是比log4j更强大,是log4j的改良版本。主要优势在于:

        a) 更快的实现,logback内核重写过,是的性能有了很大的提升,内存占用也更小。

        b) logback-classic对slf4j进行了更好的集成

        c) 自动重新加载配置文件,当配置文件修改后,logback-classic能自动重新加载配置文件

        d) 配置文件能够处理不同的情况,开发人员在不同的环境下(开发,测试,生产)切换的时候,不需要创建多个文件,可以通过标签来实现

        e) 自动压缩已经打出来的日志文件:RollingFileAppender在产生新文件的时候,会自动压缩已经打印出来的日志文件。而且这个压缩的过程是一个异步的过程。

2.logback与slf4j有什么区别?

        slf4j是一系列的日志接口,而log4j和logback是具体实现了的日志框架。

        a) log4j是apache实现的一个开源日志组件

        b) logback同样是由log4j的作者实现的,拥有更好的特性,是slf4j的原生实现

        参见:详情

3.logback中的logger、appender、layout?

        logger:作为日志的记录器,把它关联到对应的context后,主要用于存放日志对象,也可以定义日志类型,级别。

        appender:主要用于指定日志输出的目的地。目的地可以是控制台,文件,远程套接字服务器,数据库mysql等。

        layout:负责把时间转换成字符串,格式化日志信息的输出。

4.logback的日志级别有哪些?        

        logger的日志级别主要包括:TRACE

        定义在ch.qos.logback.classic.Level类中。

    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;

        此外OFF表示关闭全部日志,ALL表示开启全部日志。

        如果logger没有被分配日志级别,它将从有被分别日志级别的父类那里继承,root logger的默认级别是DEBUG

5.什么是logback的context上下文?

        每一个logger都被关联到一个loggerContext中,loggerContext负责生产logger,也负责以树形结构排列各个logger。

        logger的获取主要是通过org.slf4j.LoggerFactory的getLogger()方法获取。

        getLogger()方法有两种实现方式

        a) getLogger(Class Obj)通过传入一个类的形式,来进行logger对象和类的绑定。

        b) getLogger(String name)方式是通过传入一个contextName的形式,来指定一个logger。

        其中,用同一个名字调用该方法获取的永远都是同一个logger对象。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//通过LoggerFactory获取
private static final Logger logger = LoggerFactory.getLogger(Blog.class);

6.logback中主要模块有哪些?

        logback主要有以下三个模块:

        logback-core:所有logback模块的基础

        logback-classic:是log4j的一个改良版本,同时完整的实现了slf4j api

        logback-access:访问模块和servlet容器集成,提供通过http来访问日志的功能。

7.为什么有@slf4j的注解,就可以调用log实例写入日志?

我们可以看到@slf4j 的源码

 * Example:
 * 
 * @Slf4j
 * public class LogExample {
 * }
 * 
* * will generate: * *
 * public class LogExample {
 *     private static final org.slf4j.Logger log = 
               org.slf4j.LoggerFactory.getLogger(LogExample.class);
 * }
 * 

上面的源码注解显示在一个类前加上一个@slf4j 注解,将会在代码中自动生成一个Logger对象。

8.logback的配置文件详解?

        a) 根节点主要包含三个属性

scan:此属性为true时,配置文件如果发生改变,将会重新加载,默认为true

scanPeriod:设置监测配置文件是否有修改的时间间隔,默认为1分钟,如果没有指定时间单位,默认的单位是毫秒

debug:此属性决定是否打印出logback内部的日志信息,可实时查看logback的运行状态


        b) 子节点主要用来设置上下文的名称,前面说到,每个logger都会关联到logger上下文,默认的上下文名称为default。这里可进行配置用来区分不同应用的名称

demo

        c) 子节点用于配置写日志的组件。有两个必要的属性,name和class

name:用于指定appender的名称

class:用于指定appender全限定名

主要有三种类型:ConsoleAppender、FileAppender、RollingFileAppender

ConsoleAppender:把日志输到控制台

FileAppender:把日志输到文件

RollingFileAppender:把日志输到文件并且进行定期的清理

        d) 子节点是说有logger的上级,只有一个level属性,level属性用来设置打印级别。



	
		
			
			%d ------ %level [%thread] %caller{1} - %msg%n
			
		
	
	
	
		
			ERROR
			DENY
			ACCEPT
		
		
			
				%d ------ %level [%thread] %caller{1} - %msg%n
			
		
		
		
		
			/opt/log/dev_manage/dev-manage-info.%d-%i.log
			
        		100MB
        	       
		
		     
	
	
	
		
			ERROR
		
		
			
				%d ------ %level [%thread] %caller{1} - %msg%n
			
		
		
			/opt/log/dev_manage/dev-manage-error.%d-%i.log
			
        		100MB
        	      
		
	
	
	
		
		
		
	

下面的配置文件摘自其他页面










	
	
	
	
	
	
	
	
	
	
	
	
		
		
			
			${log.pattern}
		
	
	
	
	
		
		${log.filePath}/debug.log
		
		
			
			
				${log.filePath}/debug/debug.%d{yyyy-MM-dd}.log
			
			
			${log.maxHistory}
		
		
		
			${log.pattern}
		
		
		
		
			
			DEBUG
			
			ACCEPT
			
			DENY
		
	
	
	
	
		
		${log.filePath}/info.log
		
		
			
			
				${log.filePath}/info/info.%d{yyyy-MM-dd}.log.gz
			
			
			${log.maxHistory}
		
		
			${log.pattern}
		
		
		
			
			INFO
			
			ACCEPT
			
			DENY
		
	
	
	
	
		
		${log.filePath}/error.log
		
		
			
			
				${log.filePath}/error/error.%d{yyyy-MM-dd}.log.gz
			
			
			${log.maxHistory}
		
		
			${log.pattern}
		
		
		
			
			ERROR
			
			ACCEPT
			
			DENY
		
	
	
	
	
	
	
	
	
		
		
		
	
	
	
	
		
		
	

logback源码解析

slf4j

Logger接口

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构造方法*/

}

这个接口需要被log4j或logback来实现。

LoggerFactory类

/**
 * 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.
 */

LoggerFactory是各种各样日志api用来生成Loggers的一个很有用的工厂类,尤其是log4j、logback和jdk的logging。其他的实现像NOPLogger和SimpleLogger也是支持的。

看一下它的getLogger方法,通过logger的name来获得logger实例

    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

这里ILoggerFactory的getLogger(name),也是一个接口中的方法,需要logback去实现

public interface ILoggerFactory {
    public Logger getLogger(String name);
}

获得ILoggerFactory实例的方法,想当于是初始化的过程

    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

LogContext实现上面提到的ILoggerFactory接口

public class LoggerContext extends ContextBase implements ILoggerFactory, LifeCycle

实现getLogger(name)方法

    @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;
            }
        }
    }

你可能感兴趣的:(Java)