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");
}
static Set findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
// linkedHashSet appropriate here because it preserves insertion order during iteration
Set staticLoggerBinderPathSet = new linkedHashSet();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
private final static void versionSanityCheck() {
try {
String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
boolean match = false;
for (String aAPI_COMPATIBILITY_LIST : API_COMPATIBILITY_LIST) {
if (requested.startsWith(aAPI_COMPATIBILITY_LIST)) {
match = true;
}
}
if (!match) {
Util.report("The requested version " + requested + " by your slf4j binding is not compatible with "
+ Arrays.asList(API_COMPATIBILITY_LIST).toString());
Util.report("See " + VERSION_MISMATCH + " for further details.");
}
} catch (java.lang.NoSuchFieldError nsfe) {
// given our large user base and SLF4J's commitment to backward
// compatibility, we cannot cry here. only for implementations
// which willingly declare a REQUESTED_API_VERSION field do we
// emit compatibility warnings.
} catch (Throwable e) {
// we should never reach here
Util.report("Unexpected problem occured during version sanity check", e);
}
}
9 StaticLoggerBinder.init()
静态日志绑定器的初始化
代码:
void init() {
try {
try {
new ContextInitializer(defaultLoggerContext).autoConfig();
} catch (JoranException je) {
Util.report("Failed to auto configure default logger context", je);
}
// logback-292
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);
}
}
核心过程
序号
步骤
1
新建上下文初始化器,然后自动配置; new ContextInitializer(defaultLoggerContext).autoConfig**()**;
2
如果没有配置状态监听器,则打印出警告
3
上下文选择绑定器初始化
10 ContextInitializer.autoConfig**()**;
自动配置上下文
代码:
public void autoConfig() throws JoranException {
StatusListenerConfigHelper.installIfAsked(loggerContext);
URL url = findURLOfDefaultConfigurationFile(true);
if (url != null) {
configureByResource(url);
} else {
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);
}
}
}
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();
}
package com.lifesense.opensource.spring;
import ch.qos.logback.classic.BasicConfigurator;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.util.StatusPrinter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import javax.servlet.ServletContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
public class LogbackLoader {
private static final String DEFAULT_LOG_BACK_XML = "" +
"" +
"" +
"%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg %X{THREAD_ID} %n" +
"" +
"" +
"" +
"" +
"";
public static void initLogbackWithoutConfigFile(ServletContext servletContext) {
initLogbackConfigFromXmlString(servletContext, DEFAULT_LOG_BACK_XML);
}
public static void initLogbackConfigFromXmlString(ServletContext servletContext, String xmlStr) {
System.out.println("Initializing Logback from [n" + xmlStr + "n]");
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Assert.notNull(loggerContext, "获取不到LoggerContext");
loggerContext.getStatusManager().clear();
loggerContext.reset();
//安装默认的日志配置
if (StringUtils.isBlank(xmlStr)) {
BasicConfigurator basicConfigurator = new BasicConfigurator();
basicConfigurator.setContext(loggerContext);
basicConfigurator.configure(loggerContext);
return;
}
//按照传入的配置文件来配置
JoranConfigurator configurator = new JoranConfigurator();
configurator.setContext(loggerContext);
InputStream in = new ByteArrayInputStream(xmlStr.getBytes());
try {
configurator.doConfigure(in);
} catch (JoranException e) {
System.out.println("初始化配置logback发生错误");
e.printStackTrace();
}
//If SLF4J's java.util.logging bridge is available in the classpath, install it. This will direct any messages
//from the Java Logging framework into SLF4J. When logging is terminated, the bridge will need to be uninstalled
try {
Class> julBridge = ClassUtils.forName("org.slf4j.bridge.SLF4JBridgeHandler", ClassUtils.getDefaultClassLoader());
Method removeHandlers = ReflectionUtils.findMethod(julBridge, "removeHandlersForRootLogger");
if (removeHandlers != null) {
servletContext.log("Removing all previous handlers for JUL to SLF4J bridge");
ReflectionUtils.invokeMethod(removeHandlers, null);
}
Method install = ReflectionUtils.findMethod(julBridge, "install");
if (install != null) {
servletContext.log("Installing JUL to SLF4J bridge");
ReflectionUtils.invokeMethod(install, null);
}
} catch (ClassNotFoundException ignored) {
//Indicates the java.util.logging bridge is not in the classpath. This is not an indication of a problem.
servletContext.log("JUL to SLF4J bridge is not available on the classpath");
}
StatusPrinter.print(loggerContext);
}
}