• 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());
    		}
    	}
    
    }
    
  • 相关阅读:
    luogu P3398 仓鼠找sugar
    关于lca
    luogu P3374 【模板】树状数组 1
    [NOIp2013普及组]车站分级
    [HDU1598]find the most comfortable road
    [NOI2015]程序自动分析
    [USACO08DEC]Secret Message
    [洛谷3375]【模板】KMP字符串匹配
    [ZJOI2010]网络扩容
    [SCOI2007]修车
  • 原文地址:https://www.cnblogs.com/luguojun/p/14294679.html
Copyright © 2020-2023  润新知