扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
Spring Boot 默认使用的是 Logback 的日志框架、Logback 的组件主要通过 Spring Boot ApplicationListener 启动的
创新互联是专业的西市网站建设公司,西市接单;提供网站设计、成都网站制作,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行西市网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!// LoggingApplicationListener
@Override
public void onApplicationEvent(ApplicationEvent event) {if (event instanceof ApplicationStartingEvent) { onApplicationStartingEvent((ApplicationStartingEvent) event);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent) { onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
}
else if (event instanceof ApplicationPreparedEvent) { onApplicationPreparedEvent((ApplicationPreparedEvent) event);
}
else if (event instanceof ContextClosedEvent
&& ((ContextClosedEvent) event).getApplicationContext().getParent() == null) { onContextClosedEvent();
}
else if (event instanceof ApplicationFailedEvent) { onApplicationFailedEvent();
}
}
onApplicationStartingEvent创建 LoggingSystem
private void onApplicationStartingEvent(ApplicationStartingEvent event) {this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
this.loggingSystem.beforeInitialize();
}
LoggingSystem 是 Spring Boot 抽象的日志系统接口
public static LoggingSystem get(ClassLoader classLoader) {String loggingSystem = System.getProperty(SYSTEM_PROPERTY);
if (StringUtils.hasLength(loggingSystem)) { if (NONE.equals(loggingSystem)) { return new NoOpLoggingSystem();
}
return get(classLoader, loggingSystem);
}
return SYSTEMS.entrySet().stream().filter((entry) ->ClassUtils.isPresent(entry.getKey(), classLoader))
.map((entry) ->get(classLoader, entry.getValue())).findFirst()
.orElseThrow(() ->new IllegalStateException("No suitable logging system located"));
}
private static LoggingSystem get(ClassLoader classLoader, String loggingSystemClass) {try {Class>systemClass = ClassUtils.forName(loggingSystemClass, classLoader);
Constructor>constructor = systemClass.getDeclaredConstructor(ClassLoader.class);
constructor.setAccessible(true);
return (LoggingSystem) constructor.newInstance(classLoader);
}
catch (Exception ex) {throw new IllegalStateException(ex);
}
}
SYSTEMS
的值如下、默认情况下创建的就是 LogbackLoggingSystem
private static final MapSYSTEMS;
static {Mapsystems = new LinkedHashMap<>();
systems.put("ch.qos.logback.classic.LoggerContext",
"org.springframework.boot.logging.logback.LogbackLoggingSystem");
systems.put("org.apache.logging.log4j.core.impl.Log4jContextFactory",
"org.springframework.boot.logging.log4j2.Log4J2LoggingSystem");
systems.put("java.util.logging.LogManager", "org.springframework.boot.logging.java.JavaLoggingSystem");
SYSTEMS = Collections.unmodifiableMap(systems);
}
接下来进入到 LogbackLoggingSystem#beforeInitialize 方法
@Override
public void beforeInitialize() {LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) { return;
}
super.beforeInitialize();
loggerContext.getTurboFilterList().add(FILTER);
}
通过 StaticLoggerBinder.getSingleton() 创建 LoggerContext
private LoggerContext getLoggerContext() {ILoggerFactory factory = StaticLoggerBinder.getSingleton().getLoggerFactory();
Assert.isInstanceOf(LoggerContext.class, factory,
String.format(
"LoggerFactory is not a Logback LoggerContext but Logback is on "
+ "the classpath. Either remove Logback or the competing "
+ "implementation (%s loaded from %s). If you are using "
+ "WebLogic you will need to add 'org.slf4j' to "
+ "prefer-application-packages in WEB-INF/weblogic.xml",
factory.getClass(), getLocation(factory)));
return (LoggerContext) factory;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UzJLNIVn-1652367835486)(https://tva1.sinaimg.cn/large/e6c9d24egy1h0k3conp2qj214x0u0jvx.jpg)]
进入到静态代码块的 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);
}
}
最终会执行下面的代码、尝试获取默认配置文件、如果不存在则通过 SPI 获取 Configurator 实现类、如果还是没有、则使用默认的配置 BasicConfigurator
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);
}
}
}
onApplicationEnvironmentPreparedEvent初始化阶段
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {if (this.loggingSystem == null) { this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
}
initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
}
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {new LoggingSystemProperties(environment).apply();
this.logFile = LogFile.get(environment);
if (this.logFile != null) { this.logFile.applyToSystemProperties();
}
this.loggerGroups = new LoggerGroups(DEFAULT_GROUP_LOGGERS);
initializeEarlyLoggingLevel(environment);
initializeSystem(environment, this.loggingSystem, this.logFile);
initializeFinalLoggingLevels(environment, this.loggingSystem);
registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
主要就是从 environment 对象中设置相关属性值到 System 中、然后判断是否设置了 log file
最主要的 initializeSystem
private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
String logConfig = environment.getProperty(CONFIG_PROPERTY);
if (ignoreLogConfig(logConfig)) { system.initialize(initializationContext, null, logFile);
}
else { try { system.initialize(initializationContext, logConfig, logFile);
}
catch (Exception ex) { Throwable exceptionToReport = ex;
while (exceptionToReport != null && !(exceptionToReport instanceof FileNotFoundException)) {exceptionToReport = exceptionToReport.getCause();
}
exceptionToReport = (exceptionToReport != null) ? exceptionToReport : ex;
// NOTE: We can't use the logger here to report the problem
System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
exceptionToReport.printStackTrace(System.err);
throw new IllegalStateException(ex);
}
}
}
正常情况下、我们都没有配置 logConfig 进入到下面的方法
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {LoggerContext loggerContext = getLoggerContext();
if (isAlreadyInitialized(loggerContext)) { return;
}
super.initialize(initializationContext, configLocation, logFile);
loggerContext.getTurboFilterList().remove(FILTER);
markAsInitialized(loggerContext);
if (StringUtils.hasText(System.getProperty(CONFIGURATION_FILE_PROPERTY))) { getLogger(LogbackLoggingSystem.class.getName()).warn("Ignoring '" + CONFIGURATION_FILE_PROPERTY
+ "' system property. Please use 'logging.config' instead.");
}
}
进入到父类的 initialize 方法中
@Override
public void initialize(LoggingInitializationContext initializationContext, String configLocation, LogFile logFile) {if (StringUtils.hasLength(configLocation)) { initializeWithSpecificConfig(initializationContext, configLocation, logFile);
return;
}
initializeWithConventions(initializationContext, logFile);
}
private void initializeWithConventions(LoggingInitializationContext initializationContext, LogFile logFile) {String config = getSelfInitializationConfig();
if (config != null && logFile == null) { // self initialization has occurred, reinitialize in case of property changes
reinitialize(initializationContext);
return;
}
if (config == null) { config = getSpringInitializationConfig();
}
if (config != null) { loadConfiguration(initializationContext, config, logFile);
return;
}
loadDefaults(initializationContext, logFile);
}
正常建议使用的是 xxx-spring.xml 的配置文件、那么我们进入到 loadConfiguration 中
@Override
protected void loadConfiguration(LoggingInitializationContext initializationContext, String location,
LogFile logFile) {super.loadConfiguration(initializationContext, location, logFile);
LoggerContext loggerContext = getLoggerContext();
stopAndReset(loggerContext);
try { configureByResourceUrl(initializationContext, loggerContext, ResourceUtils.getURL(location));
}
catch (Exception ex) { throw new IllegalStateException("Could not initialize Logback logging from " + location, ex);
}
Liststatuses = loggerContext.getStatusManager().getCopyOfStatusList();
StringBuilder errors = new StringBuilder();
for (Status status : statuses) { if (status.getLevel() == Status.ERROR) { errors.append((errors.length() >0) ? String.format("%n") : "");
errors.append(status.toString());
}
}
if (errors.length() >0) { throw new IllegalStateException(String.format("Logback configuration error detected: %n%s", errors));
}
}
private void configureByResourceUrl(LoggingInitializationContext initializationContext, LoggerContext loggerContext,
URL url) throws JoranException {if (url.toString().endsWith("xml")) { JoranConfigurator configurator = new SpringBootJoranConfigurator(initializationContext);
configurator.setContext(loggerContext);
configurator.doConfigure(url);
}
else { new ContextInitializer(loggerContext).configureByResource(url);
}
我们发现了一个 SpringBootJoranConfigurator 这个配置一看就是 Spring Boot 相关的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-st2p63uA-1652367835487)(https://tva1.sinaimg.cn/large/e6c9d24egy1h0k3nimm0uj21el0u043j.jpg)]
增加了一些 Spring Boot 的规则、非常明显、用于从 environment 中获取属性填充到 logback 配置文件中
一起看下 logback-spring.xml 文件就能感受到了
logs/${logName}.log true logs/${logName}-%d{yyyy-MM-dd}.%i.log.zip 100MB 7 3GB [%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n DEBUG [ %-5level] [%date{yyyy-MM-dd HH:mm:ss}] %logger{96} [%line] - %msg%n
UTF-8 DEBUG
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流