web日志源码分析

本篇内容介绍了“web日志源码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

成都服务器托管,创新互联提供包括服务器租用、成都服务器托管、带宽租用、云主机、机柜租用、主机租用托管、CDN网站加速、申请域名等业务的一体化完整服务。电话咨询:028-86922220

web日志源码分析

通过本图可以理清楚日志之间的关系,

commons-logging和slf4j都是日志的接口,供用户使用,而没有提供实现!

log4j,logback等等才是日志的真正实现。

目前的日志框架有jdk自带的logging,log4j1、log4j2、logback

目前用于实现日志统一的框架apache的commons-logging、slf4j

为了理清它们的关系,与繁杂的各种集成jar包,如下:

  • log4j、log4j-api、log4j-core

  • log4j-1.2-api、log4j-jcl、log4j-slf4j-impl、log4j-jul

  • logback-core、logback-classic、logback-access

  • commons-logging

  • slf4j-api、slf4j-log4j12、slf4j-simple、jcl-over-slf4j、slf4j-jdk14、log4j-over-slf4j、slf4j-jcl

1.jdk 自带的log,

java.util.logging.Logger l = java.util.logging.Logger.getLogger(Deme.class.getName());

查看源码,主要是构建LoggerManage的时候读取配置文件

public static LogManager getLogManager() {
    if (manager != null) {
        manager.ensureLogManagerInitialized();
    }
    return manager;
}

final void ensureLogManagerInitialized() {
    final LogManager owner = this;
//省略
   // Read configuration.
   owner.readPrimordialConfiguration();
}

private void readPrimordialConfiguration() {  
//省略  
readConfiguration();
}

public void readConfiguration() throws IOException, SecurityException {
//省略
//默认是jre目录下的lib/logging.properties文件,也可以自定义修改系统属性"java.util.logging.config.file",源码如下:
     String fname = System.getProperty("java.util.logging.config.file");
        if (fname == null) {
            fname = System.getProperty("java.home");
            if (fname == null) {
                throw new Error("Can't find java.home ??");
            }
            File f = new File(fname, "lib");
            f = new File(f, "logging.properties");
            fname = f.getCanonicalPath();
        }
        try (final InputStream in = new FileInputStream(fname)) {
            final BufferedInputStream bin = new BufferedInputStream(in);
            readConfiguration(bin);
        }
   }

2.1 log4j1 真正实现日志读写

//jar包引入

    log4j
    log4j
    1.2.17


//初始化,查看源码,
org.apache.log4j.Logger logger1 = org.apache.log4j.Logger.getLogger("class or className");
public class Logger extends Category {
  //可以看到 Logger继承了Category 类,这个类打印日志信息的时候有用。
  Logger getLogger(String name) {
    return LogManager.getLogger(name);
  }
}

public class LogManager {
  //主要是 LogManager 的getLogger方法
  Logger getLogger(final String name) {
     // Delegate the actual manufacturing of the logger to the logger repository.
    return getLoggerRepository().getLogger(name);
  }

  //LogManager 类有个静态方法
  static {
    //初始化一个logger仓库Hierarchy,然后绑定到LoggerManager上,主要是通过getLoggerRepository()方法获取。
    // By default we use a DefaultRepositorySelector which always returns 'h'.
    Hierarchy h = new Hierarchy(new RootLogger((Level) Level.DEBUG));
    repositorySelector = new DefaultRepositorySelector(h);

    /** Search for the properties file log4j.properties in the CLASSPATH.  */
    String override =OptionConverter.getSystemProperty(DEFAULT_INIT_OVERRIDE_KEY,
						       null);

    // if there is no default init override, then get the resource
    // specified by the user or the default config file.
    if(override == null || "false".equalsIgnoreCase(override)) {

    String configurationOptionStr = OptionConverter.getSystemProperty(DEFAULT_CONFIGURATION_KEY ,null);
  //省略代码
  // 这里配置文件有个加载顺序
  // log4j.defaultInitOverride > log4j.configuration > log4j.xml > log4j.properties
  }
  //通过查看Hierarchy这个类
}

public class Hierarchy implements LoggerRepository, RendererSupport, ThrowableRendererSupport {
  
  private LoggerFactory defaultFactory;  //创建Logger工厂
  Hashtable ht; //存放工厂创建的Logger
  Logger root; //用于承载解析配置文件的结果,设置级别,同时存放appender
  //省略
  
  //构造方法
  public Hierarchy(Logger root) {
    ht = new Hashtable();
    listeners = new Vector(1);
    this.root = root;
    // Enable all level levels by default.
    setThreshold(Level.ALL);
    this.root.setHierarchy(this);
    rendererMap = new RendererMap();
    defaultFactory = new DefaultCategoryFactory();
  }
}

2.2 log4j2 日志源码解析

//添加jar包,

    org.apache.logging.log4j
    log4j-api
    2.2


	org.apache.logging.log4j
	log4j-core
	2.2


og4j2分成2个部分:
log4j-api: 作为日志接口层,用于统一底层日志系统
log4j-core : 作为上述日志接口的实现,是一个实际的日志框架

web.xml 添加如下信息
    
        org.apache.logging.log4j.web.Log4jServletFilter
    
    
        log4jServletFilter
        org.apache.logging.log4j.web.Log4jServletFilter
    
    
        log4jServletFilter
        /*
        REQUEST
        FORWARD
        INCLUDE
        ERROR
    

//创建对象
Logger logger = LoggerFactory.getLogger(DemeMapping.class);
//LoggerFactory的getlogger方法
public final class LoggerFactory {
    public static Logger getLogger(Class clazz) {
        Logger logger = getLogger(clazz.getName());
        if (DETECT_LOGGER_NAME_MISMATCH) {
            Class autoComputedCallingClass = Util.getCallingClass();
            if (nonMatchingClasses(clazz, autoComputedCallingClass)) {
                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(), autoComputedCallingClass.getName()));
                Util.report("See http://www.slf4j.org/codes.html#loggerNameMismatch for an explanation");
            }
        }

        return logger;
    }
    //获取logger对象
    public static Logger getLogger(String name) {
        //最终获取的是Log4jLoggerFactory对象实现了ILoggerFactory接口
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        //调用的其实是Log4jLoggerFactory这个类
        return iLoggerFactory.getLogger(name);
    }
    public static ILoggerFactory getILoggerFactory() {
        //初始化,并且改变INITIALIZATION_STATE = 3
        performInitialization();
        case 3:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
    }

    //主要看里面bind方法
    private static final void bind() {
        String msg;
        try {
            //这里通过类加载方式找到StaticLoggerBinder对象,
            //代码里面定义路径:"org/slf4j/impl/StaticLoggerBinder.class">

3 logback 日志解析

需要的jar包

  • logback-core

  • logback-classic

  • slf4j-api

//添加maven依赖
 
	ch.qos.logback 
	logback-core 
	1.1.3 
 
 
    ch.qos.logback 
    logback-classic 
    1.1.3 


	org.slf4j
	slf4j-api
	1.7.12


//或者

      
            framework.pisces
            pisces-log
            1.2.3-beta
            
                
                    com.fasterxml.jackson.module
                    jackson-module-jaxb-annotations
                
                
                    
                    com.fasterxml.jackson.dataformat
                    jackson-dataformat-xml
                
                
                    
                    com.fasterxml.jackson.module
                    jackson-module-jaxb-annotations
                
                
                    com.fasterxml.jackson.jaxrs
                    jackson-jaxrs-xml-provider
                
                
                    slf4j-log4j12
                    org.slf4j
                
                
                    log4j
                    log4j
                
            
        
//申明变量
org.slf4j.Logger logger2 = LoggerFactory.getLogger("");
//用到的也是 LoggerFactory来创建
public final class LoggerFactory {

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

//这里的调用和slf4j是一样getILoggerFactory()-> performInitialization(); -> bind(); -> findPossibleStaticLoggerBinderPathSet(); -> 返回LoggerContext对象
//唯一不同是构造StaticLoggerBinder的地址是 "org/slf4j/impl/StaticLoggerBinder.class" ,在调用StaticLoggerBinder.getSingleton(); 用的是 logback-classic-0.9.21.jar包下的StaticLoggerBinder 

public class StaticLoggerBinder implements LoggerFactoryBinder {

  //可以看到这里初始化并赋值 LoggerContext 对象
  private LoggerContext defaultLoggerContext = new LoggerContext();
  static {
    SINGLETON.init();
  }
  void init() {
    try {
     //这里就是初始化并存储值defaultLoggerContext,看看autoConfig()方法,里面主要是findURLOfDefaultConfigurationFile(true); 方法在读取配置文件,
      new ContextInitializer(defaultLoggerContext).autoConfig();
   }

 private static StaticLoggerBinder SINGLETON = new StaticLoggerBinder();

  public static StaticLoggerBinder getSingleton() {
    return SINGLETON;
  }

  private StaticLoggerBinder() {
    defaultLoggerContext.setName(CoreConstants.DEFAULT_CONTEXT_NAME);
  }


}

“web日志源码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!


分享名称:web日志源码分析
分享路径:http://hbruida.cn/article/gsiipg.html