您好,登錄后才能下訂單哦!
本篇內容介紹了“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包引入 <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> //初始化,查看源碼, 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包, <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.2</version> </dependency> og4j2分成2個部分: log4j-api: 作為日志接口層,用于統一底層日志系統 log4j-core : 作為上述日志接口的實現,是一個實際的日志框架 web.xml 添加如下信息 <listener> <listener-class>org.apache.logging.log4j.web.Log4jServletFilter</listener-class> </listener> <filter> <filter-name>log4jServletFilter</filter-name> <filter-class>org.apache.logging.log4j.web.Log4jServletFilter</filter-class> </filter> <filter-mapping> <filter-name>log4jServletFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> <dispatcher>INCLUDE</dispatcher> <dispatcher>ERROR</dispatcher> </filter-mapping> //創建對象 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依賴 <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.1.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.12</version> </dependency> //或者 <dependency> <groupId>framework.pisces</groupId> <artifactId>pisces-log</artifactId> <version>1.2.3-beta</version> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-jaxb-annotations</artifactId> </exclusion> <exclusion> <!-- Also, XML serialization/deserialization... --> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </exclusion> <exclusion> <!-- also need JAXB annotation support --> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-jaxb-annotations</artifactId> </exclusion> <exclusion> <groupId>com.fasterxml.jackson.jaxrs</groupId> <artifactId>jackson-jaxrs-xml-provider</artifactId> </exclusion> <exclusion> <artifactId>slf4j-log4j12</artifactId> <groupId>org.slf4j</groupId> </exclusion> <exclusion> <groupId>log4j</groupId> <artifactId>log4j</artifactId> </exclusion> </exclusions> </dependency>
//申明變量 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日志源碼分析”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。