springboot 默认日志配置源码

版本

2.2.x

日志系统初始化流程

  1. 应用启动时,ApplicationStartingEvent触发,屏蔽所有日志
  2. ApplicationEnvironmentPreparedEvent触发,清空所有日志配置,重新初始化日志系统
  3. 配置变更,EnvironmentChangeEvent触发,重新设置日志级别

源码

  • org.springframework.cloud.bootstrap.LoggingSystemShutdownListener
public class LoggingSystemShutdownListener
		implements ApplicationListener<ApplicationEnvironmentPreparedEvent>, Ordered {
	@Override
	public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
		shutdownLogging();
	}	
	private void shutdownLogging() {
		LoggingSystem loggingSystem = LoggingSystem
				.get(ClassUtils.getDefaultClassLoader());
		loggingSystem.cleanUp();
		loggingSystem.beforeInitialize();
	}
}
  • org.springframework.boot.context.logging.LoggingApplicationListener
// 应用启动时
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
	// 获取日志系统实例
	this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
	// 关闭所有日志
	this.loggingSystem.beforeInitialize();
}
// 应用环境准备完成时
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);
}
  • org.springframework.boot.logging.LoggingSystem
    根据系统属性org.springframework.boot.logging.LoggingSystem的值判断选用何种日志系统
private static final Map<String, String> SYSTEMS;
static {
	Map<String, String> systems = new LinkedHashMap<>();
	systems.put("ch.qos.logback.core.Appender", "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);
}
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);
	}
}
  • org.springframework.boot.logging.AbstractLoggingSystem
@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;
	}
	// 获取spring配置
	if (config == null) {
		config = getSpringInitializationConfig();
	}
	if (config != null) {
		loadConfiguration(initializationContext, config, logFile);
		return;
	}	
	// 不存在配置,加载默认配置
	loadDefaults(initializationContext, logFile);
}
  • org.springframework.boot.logging.logback.LogbackLoggingSystem
public void beforeInitialize() {
	LoggerContext loggerContext = getLoggerContext();
	if (isAlreadyInitialized(loggerContext)) {
		return;
	}
	super.beforeInitialize();
	// 屏蔽所有日志
	loggerContext.getTurboFilterList().add(FILTER);
}
@Override
protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) {
	LoggerContext context = getLoggerContext();
	// 此处重置上下文中原有配置
	stopAndReset(context);
	boolean debug = Boolean.getBoolean("logback.debug");
	if (debug) {
		StatusListenerConfigHelper.addOnConsoleListenerInstance(context, new OnConsoleStatusListener());
	}
	LogbackConfigurator configurator = debug ? new DebugLogbackConfigurator(context)
			: new LogbackConfigurator(context);
	Environment environment = initializationContext.getEnvironment();
	context.putProperty(LoggingSystemProperties.LOG_LEVEL_PATTERN,
			environment.resolvePlaceholders("${logging.pattern.level:${LOG_LEVEL_PATTERN:%5p}}"));
	context.putProperty(LoggingSystemProperties.LOG_DATEFORMAT_PATTERN, environment.resolvePlaceholders(
			"${logging.pattern.dateformat:${LOG_DATEFORMAT_PATTERN:yyyy-MM-dd HH:mm:ss.SSS}}"));
	context.putProperty(LoggingSystemProperties.ROLLING_FILE_NAME_PATTERN, environment
			.resolvePlaceholders("${logging.pattern.rolling-file-name:${LOG_FILE}.%d{yyyy-MM-dd}.%i.gz}"));
	new DefaultLogbackConfiguration(initializationContext, logFile).apply(configurator);
	context.setPackagingDataEnabled(true);
}
  • org.springframework.boot.logging.logback.DefaultLogbackConfiguration
/**
 * Default logback configuration used by Spring Boot. Uses {@link LogbackConfigurator} to
 * improve startup time. See also the {@code defaults.xml}, {@code console-appender.xml}
 * and {@code file-appender.xml} files provided for classic {@code logback.xml} use.
 *
 * @author Phillip Webb
 * @author Madhura Bhave
 * @author Vedran Pavic
 * @author Robert Thornton
 */
class DefaultLogbackConfiguration {

	private static final String CONSOLE_LOG_PATTERN = "%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} "
			+ "%clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} "
			+ "%clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} "
			+ "%clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";

	private static final String FILE_LOG_PATTERN = "%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} "
			+ "${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}";

	private static final DataSize MAX_FILE_SIZE = DataSize.ofMegabytes(10);

	private static final Integer MAX_FILE_HISTORY = 7;

	private final PropertyResolver patterns;

	private final LogFile logFile;

	DefaultLogbackConfiguration(LoggingInitializationContext initializationContext, LogFile logFile) {
		this.patterns = getPatternsResolver(initializationContext.getEnvironment());
		this.logFile = logFile;
	}

	private PropertyResolver getPatternsResolver(Environment environment) {
		if (environment == null) {
			return new PropertySourcesPropertyResolver(null);
		}
		if (environment instanceof ConfigurableEnvironment) {
			PropertySourcesPropertyResolver resolver = new PropertySourcesPropertyResolver(
					((ConfigurableEnvironment) environment).getPropertySources());
			resolver.setIgnoreUnresolvableNestedPlaceholders(true);
			return resolver;
		}
		return environment;
	}

	void apply(LogbackConfigurator config) {
		synchronized (config.getConfigurationLock()) {
			base(config);
			Appender<ILoggingEvent> consoleAppender = consoleAppender(config);
			if (this.logFile != null) {
				Appender<ILoggingEvent> fileAppender = fileAppender(config, this.logFile.toString());
				config.root(Level.INFO, consoleAppender, fileAppender);
			}
			else {
				config.root(Level.INFO, consoleAppender);
			}
		}
	}

	private void base(LogbackConfigurator config) {
		config.conversionRule("clr", ColorConverter.class);
		config.conversionRule("wex", WhitespaceThrowableProxyConverter.class);
		config.conversionRule("wEx", ExtendedWhitespaceThrowableProxyConverter.class);
		config.logger("org.apache.catalina.startup.DigesterFactory", Level.ERROR);
		config.logger("org.apache.catalina.util.LifecycleBase", Level.ERROR);
		config.logger("org.apache.coyote.http11.Http11NioProtocol", Level.WARN);
		config.logger("org.apache.sshd.common.util.SecurityUtils", Level.WARN);
		config.logger("org.apache.tomcat.util.net.NioSelectorPool", Level.WARN);
		config.logger("org.eclipse.jetty.util.component.AbstractLifeCycle", Level.ERROR);
		config.logger("org.hibernate.validator.internal.util.Version", Level.WARN);
	}

	private Appender<ILoggingEvent> consoleAppender(LogbackConfigurator config) {
		ConsoleAppender<ILoggingEvent> appender = new ConsoleAppender<>();
		PatternLayoutEncoder encoder = new PatternLayoutEncoder();
		String logPattern = this.patterns.getProperty("logging.pattern.console", CONSOLE_LOG_PATTERN);
		encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
		config.start(encoder);
		appender.setEncoder(encoder);
		config.appender("CONSOLE", appender);
		return appender;
	}

	private Appender<ILoggingEvent> fileAppender(LogbackConfigurator config, String logFile) {
		RollingFileAppender<ILoggingEvent> appender = new RollingFileAppender<>();
		PatternLayoutEncoder encoder = new PatternLayoutEncoder();
		String logPattern = this.patterns.getProperty("logging.pattern.file", FILE_LOG_PATTERN);
		encoder.setPattern(OptionHelper.substVars(logPattern, config.getContext()));
		appender.setEncoder(encoder);
		config.start(encoder);
		appender.setFile(logFile);
		setRollingPolicy(appender, config, logFile);
		config.appender("FILE", appender);
		return appender;
	}

	private void setRollingPolicy(RollingFileAppender<ILoggingEvent> appender, LogbackConfigurator config,
			String logFile) {
		SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy = new SizeAndTimeBasedRollingPolicy<>();
		rollingPolicy.setCleanHistoryOnStart(
				this.patterns.getProperty("logging.file.clean-history-on-start", Boolean.class, false));
		rollingPolicy.setFileNamePattern(
				this.patterns.getProperty("logging.pattern.rolling-file-name", logFile + ".%d{yyyy-MM-dd}.%i.gz"));
		setMaxFileSize(rollingPolicy, getDataSize("logging.file.max-size", MAX_FILE_SIZE));
		rollingPolicy
				.setMaxHistory(this.patterns.getProperty("logging.file.max-history", Integer.class, MAX_FILE_HISTORY));
		DataSize totalSizeCap = getDataSize("logging.file.total-size-cap",
				DataSize.ofBytes(CoreConstants.UNBOUNDED_TOTAL_SIZE_CAP));
		rollingPolicy.setTotalSizeCap(new FileSize(totalSizeCap.toBytes()));
		appender.setRollingPolicy(rollingPolicy);
		rollingPolicy.setParent(appender);
		config.start(rollingPolicy);
	}

	private void setMaxFileSize(SizeAndTimeBasedRollingPolicy<ILoggingEvent> rollingPolicy, DataSize maxFileSize) {
		try {
			rollingPolicy.setMaxFileSize(new FileSize(maxFileSize.toBytes()));
		}
		catch (NoSuchMethodError ex) {
			// Logback < 1.1.8 used String configuration
			Method method = ReflectionUtils.findMethod(SizeAndTimeBasedRollingPolicy.class, "setMaxFileSize",
					String.class);
			ReflectionUtils.invokeMethod(method, rollingPolicy, String.valueOf(maxFileSize.toBytes()));
		}
	}

	private DataSize getDataSize(String property, DataSize defaultSize) {
		String value = this.patterns.getProperty(property);
		if (value == null) {
			return defaultSize;
		}
		try {
			return DataSize.parse(value);
		}
		catch (IllegalArgumentException ex) {
			FileSize fileSize = FileSize.valueOf(value);
			return DataSize.ofBytes(fileSize.getSize());
		}
	}

}

posted on 2020-09-02 14:55  路过君  阅读(363)  评论(0编辑  收藏  举报

导航