栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

1、LogBack入门案例

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

1、LogBack入门案例

Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好。
官方网站:https://logback.qos.ch/index.html
Logback主要分为三个模块:

logback-core:其它两个模块的基础模块logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j APIlogback-access:访问模块与Servlet容器集成提供通过Http来访问日志的功能 后续的日志代码都是通过SLF4J日志门面搭建日志系统,所以在代码是没有区别,主要是通过修改配置文件和pom.xml依赖

项目中无需单独引入slf4j,因为logback-classic依赖包里引用了slf4j

入门案例 第一步:创建maven项目,添加依赖

	4.0.0
	com.example
	logging-test
	0.0.1-SNAPSHOT

	
		8
		8
	

	
		
			junit
			junit
			4.12
		

		
			ch.qos.logback
			logback-classic
			1.2.10
		

	

	
		
			
				org.apache.maven.plugins
				maven-compiler-plugin
				3.8.1
				
					${maven.compiler.source}
					${maven.compiler.target}
					UTF-8
				
			
		
	

第二步:测试代码
package com.example.test;

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestLogback {

	private static final Logger logger = LoggerFactory.getLogger(TestLogback.class);

	@Test
	public void testLogback() {
		logger.error("error");
		logger.warn("warn");
		logger.info("info");
		logger.debug("debug");
		logger.trace("trace");
	}
}

源码解读 1、我们从日志工厂的常见看起,这里是slf4j的实现
private static final Logger logger = LoggerFactory.getLogger(TestLogback.class);

核心方法只有一句

public static Logger getLogger(Class clazz) {
        Logger logger = getLogger(clazz.getName());
       	....省略
        return logger;
    }

看一下getLogger方法,这里是先获取日志工厂,在从工厂中提取日志对象,我们不考虑日志对象,主要看看日志工厂的环境怎么初始化的

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

进入getILoggerFactory方法看:

public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == 0) {
            Class var0 = LoggerFactory.class;
            synchronized(LoggerFactory.class) {
                if (INITIALIZATION_STATE == 0) {
                    INITIALIZATION_STATE = 1;
                    //重要方法
                    performInitialization();
                }
            }
        }
        ...省略
    }

进入performInitialization方法

private static final void performInitialization() {
		//一看bind就知道slf4j绑定logback的重要方法
        bind();
        if (INITIALIZATION_STATE == 3) {
            versionSanityCheck();
        }

    }

进入bind方法:

private final static void bind() {
        try {
            Set staticLoggerBinderPathSet = null;
            // skip check under android, see also
            // http://jira.qos.ch/browse/SLF4J-328
            if (!isAndroid()) {
                staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
                reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
            }
            // the next line does the binding
            //这一行做绑定操作,重要
            StaticLoggerBinder.getSingleton();
            ....省略
    }

进入getSingleton方法,此时已经进入桥接包的StaticLoggerBinder类了,log4j桥接包和jul桥接包中都有这个StaticLoggerBinder类:

 public static StaticLoggerBinder getSingleton() {
        return SINGLETON;
    }

我们翻下可以看到它有个静态代码块:

static {
        SINGLETON.init();
    }

进入init方法

void init() {
        try {
            try {
            	//感觉autoConfig是重要方法
                (new ContextInitializer(this.defaultLoggerContext)).autoConfig();
            ...省略

    }

进入autoConfig方法

 public void autoConfig() throws JoranException {
        StatusListenerConfigHelper.installIfAsked(this.loggerContext);
        //生成URL通过默认配置文件
        URL url = this.findURLOfDefaultConfigurationFile(true);
        if (url != null) {
            this.configureByResource(url);
        } else {
        	//spi机制获取配置类
            Configurator c = (Configurator)EnvUtil.loadFromServiceLoader(Configurator.class);
            if (c != null) {
                try {
                    c.setContext(this.loggerContext);
                    c.configure(this.loggerContext);
                } catch (Exception var4) {
                    throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass().getCanonicalName() : "null"), var4);
                }
            } else {
            	//当没有配置文件时,默认的配置
                BasicConfigurator basicConfigurator = new BasicConfigurator();
                basicConfigurator.setContext(this.loggerContext);
                basicConfigurator.configure(this.loggerContext);
            }
        }

    }

我们可以看下findConfigFileURLFromSystemProperties方法:

    public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }

        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
        if (url != null) {
            return url;
        }
    
        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
    }

我们发现,它读取配置文件有优先级,先读取classpath下是否有logback-test.xml,没有则读取classpath下是否有logback.xml

debug发现Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);返回为null。
然后进入到BasicConfigurator,然后发现basicConfigurator.configure(loggerContext);比较重要

public void configure(LoggerContext lc) {
        addInfo("Setting up default configuration.");
        
        ConsoleAppender ca = new ConsoleAppender();
        ca.setContext(lc);
        ca.setName("console");
        LayoutWrappingEncoder encoder = new LayoutWrappingEncoder();
        encoder.setContext(lc);
        
 
        // same as 
        // PatternLayout layout = new PatternLayout();
        // layout.setPattern("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n");
        TTLLLayout layout = new TTLLLayout();
 
        layout.setContext(lc);
        layout.start();
        encoder.setLayout(layout);
        
        ca.setEncoder(encoder);
        ca.start();
        
        Logger rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME);
        rootLogger.addAppender(ca);
    }

结果一看,rootLogger指向appender,appender指向encoder,encoder指向layout,比log4j多了encoder,但大致一样

我们在看TTLLLayout类

package ch.qos.logback.classic.layout;

import ch.qos.logback.classic.pattern.ThrowableProxyConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.Layoutbase;
import ch.qos.logback.core.util.CachingDateFormatter;


public class TTLLLayout extends Layoutbase {

    CachingDateFormatter cachingDateFormatter = new CachingDateFormatter("HH:mm:ss.SSS");
    ThrowableProxyConverter tpc = new ThrowableProxyConverter();

    @Override
    public void start() {
        tpc.start();
        super.start();
    }

    @Override
    public String doLayout(ILoggingEvent event) {
        if (!isStarted()) {
            return CoreConstants.EMPTY_STRING;
        }
        StringBuilder sb = new StringBuilder();

        long timestamp = event.getTimeStamp();

        sb.append(cachingDateFormatter.format(timestamp));
        sb.append(" [");
        sb.append(event.getThreadName());
        sb.append("] ");
        sb.append(event.getLevel().toString());
        sb.append(" ");
        sb.append(event.getLoggerName());
        sb.append(" - ");
        sb.append(event.getFormattedMessage());
        sb.append(CoreConstants.LINE_SEPARATOR);
        IThrowableProxy tp = event.getThrowableProxy();
        if (tp != null) {
            String stackTrace = tpc.convert(event);
            sb.append(stackTrace);
        }
        return sb.toString();
    }

}

发现doLayout做的操作跟打印的出来格式一模一样的

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/703840.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号