十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
本篇内容介绍了“web日志源码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
成都服务器托管,创新互联提供包括服务器租用、成都服务器托管、带宽租用、云主机、机柜租用、主机租用托管、CDN网站加速、申请域名等业务的一体化完整服务。电话咨询:028-86922220
通过本图可以理清楚日志之间的关系,
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包引入//初始化,查看源码, org.apache.log4j.Logger logger1 = org.apache.log4j.Logger.getLogger("class or className"); log4j log4j 1.2.17
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 og4j2分成2个部分: log4j-api: 作为日志接口层,用于统一底层日志系统 log4j-core : 作为上述日志接口的实现,是一个实际的日志框架 web.xml 添加如下信息 org.apache.logging.log4j log4j-core 2.2 org.apache.logging.log4j.web.Log4jServletFilter log4jServletFilter org.apache.logging.log4j.web.Log4jServletFilter //创建对象 Logger logger = LoggerFactory.getLogger(DemeMapping.class); log4jServletFilter /* REQUEST FORWARD INCLUDE ERROR
//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日志源码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!