logback源码分析
从一个Logger获取说起
public static Logger getLogger(Class<?> clazz) {
//获取Logger
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
autoComputedCallingClass.getName()));
Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
}
2
3
4
5
6
7
8
9
10
11
12
13
在跟进Logger logger = getLogger(clazz.getName());方法
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
2
3
4
这个方法就是初始化LoggerContext,如果没有初始化则调用performInitialization进行初始化,初始化了就直接返回
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
再看看performInitialization()方法,里面就一个绑定和校验
private final static void performInitialization() {
bind();
if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
versionSanityCheck();
}
}
2
3
4
5
6
比较核心的方法bind():
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = null;
//这里通过findPossibleStaticLoggerBinderPathSet查找类路径下的org/slf4j/impl/StaticLoggerBinder.class
//如果有多个或者没有则记录错误信息
if (!isAndroid()) {
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
//这个是直接引入StaticLoggerBinder方式进行加注,这个初始化的时候会在static代码块中执行init方式加载配置
//如果Jar包中没有这个类则会报错NoClassDefFoundError,多个的话Jvm优先选择先被加载的那个实现。
StaticLoggerBinder.getSingleton();
//初始化成功
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
//显示真实选择的实现类
reportActualBinding(staticLoggerBinderPathSet);
fixSubstituteLoggers();
replayEvents();
// release all resources in SUBST_FACTORY
SUBST_FACTORY.clear();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
StaticLoggerBinder.getSingleton();看看具体做了些什么
//静态代码块初始化
static {
SINGLETON.init();
}
void init() {
try {
try {
//执行真正的配置自动选择与加载
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.report("Failed to auto configure default logger context", je);
}
//这里判断如果没有监听状态信息的话就 查看状态列表有没有warn以上的日志,有就打印到控制台
if (!StatusUtil.contextHasStatusListener(defaultLoggerContext)) {
StatusPrinter.printInCaseOfErrorsOrWarnings(defaultLoggerContext);
}
contextSelectorBinder.init(defaultLoggerContext, KEY);
initialized = true;
} catch (Exception t) { // see LOGBACK-1159
Util.report("Failed to instantiate [" + LoggerContext.class.getName() + "]", t);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
看看 new ContextInitializer(defaultLoggerContext).autoConfig();到底是怎么做的
public void autoConfig() throws JoranException {
StatusListenerConfigHelper.installIfAsked(loggerContext);
//找到具体的配置文件 logback-test.xml>logback.groovy>logback.xml
URL url = findURLOfDefaultConfigurationFile(true);
if (url != null) {
//执行装载配置
configureByResource(url);
} else {
//如果没有上面的xml、groovy配置到执行则查询SPI,找Configurator的实现类
Configurator c = EnvUtil.loadFromServiceLoader(Configurator.class);
if (c != null) {
try {
c.setContext(loggerContext);
c.configure(loggerContext);
} catch (Exception e) {
throw new LogbackException(String.format("Failed to initialize Configurator: %s using ServiceLoader", c != null ? c.getClass()
.getCanonicalName() : "null"), e);
}
} else {
//确实没有用户自定义配置,使用默认配置
BasicConfigurator basicConfigurator = new BasicConfigurator();
basicConfigurator.setContext(loggerContext);
basicConfigurator.configure(loggerContext);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
配置完成之后回到init方法,回去执行contextSelectorBinder.init(defaultLoggerContext, KEY);
这里面主要是解决日志分离问题,通过VM参数指定logback.ContextSelector来配置ContextSelector实现日志分离
public void init(LoggerContext defaultLoggerContext, Object key) throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
if (this.key == null) {
this.key = key;
} else if (this.key != key) {
throw new IllegalAccessException("Only certain classes can access this method.");
}
String contextSelectorStr = OptionHelper.getSystemProperty(ClassicConstants.LOGBACK_CONTEXT_SELECTOR);
if (contextSelectorStr == null) {
contextSelector = new DefaultContextSelector(defaultLoggerContext);
} else if (contextSelectorStr.equals("JNDI")) {
// if jndi is specified, let's use the appropriate class
contextSelector = new ContextJNDISelector(defaultLoggerContext);
} else {
contextSelector = dynamicalContextSelector(defaultLoggerContext, contextSelectorStr);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
到这里就初始化完成了。状态也变为了SUCCESSFUL_INITIALIZATION,performInitialization方法执行完成。返回了StaticLoggerBinder.getSingleton().getLoggerFactory();
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
synchronized (LoggerFactory.class) {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
}
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
case ONGOING_INITIALIZATION:
// support re-entrant behavior.
// See also http://jira.qos.ch/browse/SLF4J-97
return SUBST_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
返回了指定的logback自定义ILoggerFactory的实现类LoggerContext
public ILoggerFactory getLoggerFactory() {
if (!initialized) {
return defaultLoggerContext;
}
if (contextSelectorBinder.getContextSelector() == null) {
throw new IllegalStateException("contextSelector cannot be null. See also " + NULL_CS_URL);
}
return contextSelectorBinder.getContextSelector().getLoggerContext();
}
2
3
4
5
6
7
8
9
10
在执行了LoggerContext.getLogger()方法,可以看到他在创建Logger的时候会根据.分割的,从左到右依次查找,如果不存在就创建并保存,存在直接返回
@Override
public final Logger getLogger(final String name) {
if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}
//名字为ROOT直接返回 根LOGGER
if (Logger.ROOT_LOGGER_NAME.equalsIgnoreCase(name)) {
return root;
}
int i = 0;
Logger logger = root;
//查询已经创建了的Logger
Logger childLogger = (Logger) loggerCache.get(name);
// 存在直接返回
if (childLogger != null) {
return childLogger;
}
//不存在则按照规则创建,配置日志等级,继承祖先配置
String childName;
while (true) {
//通过 . 分割Logger等级 划分父子节点
int h = LoggerNameUtil.getSeparatorIndexOf(name, i);
if (h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
// 记录当前的分割位置(祖先节点到哪里了)
i = h + 1;
synchronized (logger) {
//这里是遍历子节点,拿到Logger,只找一级
childLogger = logger.getChildByName(childName);
//没有子节点了,创建Logger
if (childLogger == null) {
childLogger = logger.createChildByName(childName);
//添加缓存
loggerCache.put(childName, childLogger);
incSize();
}
}
//返回logger
logger = childLogger;
if (h == -1) {
return childLogger;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
到这里就拿到了Logger进行了打印日志了,但是注意日志记录加载过程中,会经过turbofilter进行初步过滤,再经过RegularFilter进行过滤Appender,如果Appender都通过了再通过layout格式化日志,在经过Encoder把日志写入输出流显示。