本篇内容介绍了“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日志源码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4079875/blog/3075462