1. 程式人生 > >SpringBoot Logback 配置引數遷移到配置中心 Apollo

SpringBoot Logback 配置引數遷移到配置中心 Apollo

 

 

專案中吧所有的配置檔案都移植到配置中心了,這樣後面釋出版本不需要想著改配置檔案,直接發包即可了,但是logback.xml 中間的日誌路徑,logstash host  ,以及日誌級別線上和開發環境肯定不同,為了一勞永逸,故想辦法將logback的相關引數移動到配置中心去。

     

 

1   使用springProperty 來代替Property  定義變數


其中source 裡面的是spring yml 或者properties 或者配置中心的變數key


<springProperty scope="context" name="log_dir" source="logback.file.dir "/>

 如果是僅僅配置上面這個還是不行,因為載入logback.xml程式碼會比 Apollo的 去配置中心讀取配置引數的程式碼 早執行,會報找不到 

logback.file.dir ,於是第二部需要將 logback.xml換個其他的名字,我叫logback_fhs.xml,這樣spring 沒辦法預設載入此檔案。

然後在配置中心定義一個key 

logging.config==classpath:logback_fhs.xml

這樣spring會乖乖的等Apollo 把配置引數載入完成之後執行載入logback.xml的程式碼。

如果你以為到了這裡就大吉大利晚上吃雞你就錯了,springBoot如果預設讀取不到 logback.xml 會使用預設的引數去初始化logger,當你讓spring去載入logback_fhs.xml的時候,spring只判斷logback_fhs.xml 是否存在,其實是不會載入的,因為logger已經存在了。

2  使用自定義LogBackConfigListener去初始化logger。

    為了看文章舒服,我吧程式碼貼到了最後面,程式碼是在載入logback_fhs.xml 的時候執行了一些clear方法,把預設的一些配置幹掉,然後自己在初始化一個logger配置進去。到了這裡,正常啟動和記錄日誌沒有問題了。

 

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package  org.springframework.boot.logging;

import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

/**
 * by jackwang
 * 解決logback 從配置中心讀取不起做用的問題
 */
public class LogBackConfigListener implements GenericApplicationListener {
    public static final int DEFAULT_ORDER = -2147483628;
    public static final String CONFIG_PROPERTY = "logging.config";
    public static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = "logging.register-shutdown-hook";
    /** @deprecated */
    @Deprecated
    public static final String PATH_PROPERTY = "logging.path";
    /** @deprecated */
    @Deprecated
    public static final String FILE_PROPERTY = "logging.file";
    public static final String PID_KEY = "PID";
    public static final String EXCEPTION_CONVERSION_WORD = "LOG_EXCEPTION_CONVERSION_WORD";
    public static final String LOG_FILE = "LOG_FILE";
    public static final String LOG_PATH = "LOG_PATH";
    public static final String CONSOLE_LOG_PATTERN = "CONSOLE_LOG_PATTERN";
    public static final String FILE_LOG_PATTERN = "FILE_LOG_PATTERN";
    public static final String LOG_LEVEL_PATTERN = "LOG_LEVEL_PATTERN";
    public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem";
    private static MultiValueMap<LogLevel, String> LOG_LEVEL_LOGGERS = new LinkedMultiValueMap();
    private static AtomicBoolean shutdownHookRegistered = new AtomicBoolean(false);
    private static Class<?>[] EVENT_TYPES;
    private static Class<?>[] SOURCE_TYPES;
    private final Log logger = LogFactory.getLog(this.getClass());
    private LoggingSystem loggingSystem;
    private int order = -2147483628;
    private boolean parseArgs = true;
    private LogLevel springBootLogging = null;

    public LogBackConfigListener() {
    }

    public boolean supportsEventType(ResolvableType resolvableType) {
        return this.isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
    }

    public boolean supportsSourceType(Class<?> sourceType) {
        return this.isAssignableFrom(sourceType, SOURCE_TYPES);
    }

    private boolean isAssignableFrom(Class<?> type, Class... supportedTypes) {
        if (type != null) {
            Class[] var3 = supportedTypes;
            int var4 = supportedTypes.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                Class<?> supportedType = var3[var5];
                if (supportedType.isAssignableFrom(type)) {
                    return true;
                }
            }
        }

        return false;
    }

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
        }
    }

    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());
        }

        this.initialize(event.getEnvironment(), event.getSpringApplication().getClassLoader());
    }

    private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
        ConfigurableListableBeanFactory beanFactory = event.getApplicationContext().getBeanFactory();
        if (!beanFactory.containsBean("springBootLoggingSystem")) {
            beanFactory.registerSingleton("springBootLoggingSystem", this.loggingSystem);
        }

    }

    private void onContextClosedEvent() {
        if (this.loggingSystem != null) {
            this.loggingSystem.cleanUp();
        }

    }

    private void onApplicationFailedEvent() {
        if (this.loggingSystem != null) {
            this.loggingSystem.cleanUp();
        }

    }

    protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
        (new LoggingSystemProperties(environment)).apply();
        LogFile logFile = LogFile.get(environment);
        if (logFile != null) {
            logFile.applyToSystemProperties();
        }

        this.initializeEarlyLoggingLevel(environment);
        this.initializeSystem(environment, this.loggingSystem, logFile);
        this.initializeFinalLoggingLevels(environment, this.loggingSystem);
        this.registerShutdownHookIfNecessary(environment, this.loggingSystem);
    }

    private void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) {
        if (this.parseArgs && this.springBootLogging == null) {
            if (this.isSet(environment, "debug")) {
                this.springBootLogging = LogLevel.DEBUG;
            }

            if (this.isSet(environment, "trace")) {
                this.springBootLogging = LogLevel.TRACE;
            }
        }

    }

    private boolean isSet(ConfigurableEnvironment environment, String property) {
        String value = environment.getProperty(property);
        return value != null && !value.equals("false");
    }

    private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, LogFile logFile) {
        LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
        String logConfig = environment.getProperty("logging.config");
        if (this.ignoreLogConfig(logConfig)) {
            system.initialize(initializationContext, (String)null, logFile);
        } else {
            try {
                system.cleanUp();
                ResourceUtils.getURL(logConfig).openStream().close();
                system.initialize(initializationContext, logConfig, logFile);
            } catch (Exception var7) {
                System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
                var7.printStackTrace(System.err);
                throw new IllegalStateException(var7);
            }
        }

    }

    private boolean ignoreLogConfig(String logConfig) {
        return !StringUtils.hasLength(logConfig) || logConfig.startsWith("-D");
    }

    private void initializeFinalLoggingLevels(ConfigurableEnvironment environment, LoggingSystem system) {
        if (this.springBootLogging != null) {
            this.initializeLogLevel(system, this.springBootLogging);
        }

        this.setLogLevels(system, environment);
    }

    protected void initializeLogLevel(LoggingSystem system, LogLevel level) {
        List<String> loggers = (List)LOG_LEVEL_LOGGERS.get(level);
        if (loggers != null) {
            Iterator var4 = loggers.iterator();

            while(var4.hasNext()) {
                String logger = (String)var4.next();
                system.setLogLevel(logger, level);
            }
        }

    }

    protected void setLogLevels(LoggingSystem system, Environment environment) {
        Map<String, Object> levels = (new RelaxedPropertyResolver(environment)).getSubProperties("logging.level.");
        boolean rootProcessed = false;
        Iterator var5 = levels.entrySet().iterator();

        while(true) {
            Entry entry;
            String name;
            while(true) {
                if (!var5.hasNext()) {
                    return;
                }

                entry = (Entry)var5.next();
                name = (String)entry.getKey();
                if (!name.equalsIgnoreCase("ROOT")) {
                    break;
                }

                if (!rootProcessed) {
                    name = null;
                    rootProcessed = true;
                    break;
                }
            }

            this.setLogLevel(system, environment, name, entry.getValue().toString());
        }
    }

    private void setLogLevel(LoggingSystem system, Environment environment, String name, String level) {
        try {
            level = environment.resolvePlaceholders(level);
            system.setLogLevel(name, this.coerceLogLevel(level));
        } catch (RuntimeException var6) {
            this.logger.error("Cannot set level: " + level + " for '" + name + "'");
        }

    }

    private LogLevel coerceLogLevel(String level) {
        return "false".equalsIgnoreCase(level) ? LogLevel.OFF : LogLevel.valueOf(level.toUpperCase(Locale.ENGLISH));
    }

    private void registerShutdownHookIfNecessary(Environment environment, LoggingSystem loggingSystem) {
        boolean registerShutdownHook = ((Boolean)(new RelaxedPropertyResolver(environment)).getProperty("logging.register-shutdown-hook", Boolean.class, false)).booleanValue();
        if (registerShutdownHook) {
            Runnable shutdownHandler = loggingSystem.getShutdownHandler();
            if (shutdownHandler != null && shutdownHookRegistered.compareAndSet(false, true)) {
                this.registerShutdownHook(new Thread(shutdownHandler));
            }
        }

    }

    void registerShutdownHook(Thread shutdownHook) {
        Runtime.getRuntime().addShutdownHook(shutdownHook);
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public int getOrder() {
        return this.order;
    }

    public void setSpringBootLogging(LogLevel springBootLogging) {
        this.springBootLogging = springBootLogging;
    }

    public void setParseArgs(boolean parseArgs) {
        this.parseArgs = parseArgs;
    }

    static {
        LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.springframework.boot");
        LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.springframework");
        LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.tomcat");
        LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.apache.catalina");
        LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.eclipse.jetty");
        LOG_LEVEL_LOGGERS.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl");
        LOG_LEVEL_LOGGERS.add(LogLevel.DEBUG, "org.hibernate.SQL");
        EVENT_TYPES = new Class[]{ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class, ApplicationFailedEvent.class};
        SOURCE_TYPES = new Class[]{SpringApplication.class, ApplicationContext.class};
    }
}