首页 文章

使用Root-Logger WARN显示Spring-Boot Banner

提问于
浏览
9

在开发和测试环境下,ROOT Logger 级别为DEBUG或INFO . 应用程序启动时会显示spring-boot Headers :

2017-03-23 14:31:00,322 [INFO ]                 - 
 :: Spring Boot ::         (v1.5.2.RELEASE)
 :: Application ::         AcMe (v1.0-SNAPSHOT)
 :: Build ::               2017-03-23 09:53

但是在 生产环境 环境中运行时,我的ROOT Logger 级别通常是WARN . 这会导致 Banner 打印不出来 .

如何配置回溯以便 Banner 也将在 生产环境 中显示?

我的猜测是添加另一个 Logger ,但以下(和相似的配置)不起作用:

<logger name="org.springframework.web" level="INFO" additivity="false">
    <appender-ref ref="FILE"/>
</logger>

在这里我的配置

application.properties:

spring.main.banner-mode=log

application-devel.properties:

logging.config=classpath:logging-spring-devel.xml

application-production.properties:

logging.config=classpath:logging-spring-production.xml

logging-devel.xml(显示 Banner )

LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}application.log}"/>
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_FILE}</file>
            ...
        </appender>
        <root level="INFO">
            <appender-ref ref="FILE"/>
        </root>
    </configuration>

logging-production.xml( Banner 未显示)

LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}/}application.log}"/>
        <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <file>${LOG_FILE}</file>
            ...
        </appender>
        <root level="WARN">
            <appender-ref ref="FILE"/>
        </root>
    </configuration>

4 回答

  • 1

    在打印 Banner 时,Spring Boot使用类 org.springframework.boot.SpringApplication 的 Logger ,其级别为 INFO .

    简单的解决方案是为此特定类启用 INFO 级别:

    <logger name="org.springframework.boot.SpringApplication"
            level="INFO" additivity="false">
        <appender-ref ref="FILE"/>
    </logger>
    
  • 0

    我有同样的问题,只需在 application.properties 中设置此属性:

    spring.main.banner-mode=LOG
    

    现在它打印到控制台和文件,具有日志级别INFO . 只要您将根日志级别和追加者设置为接受INFO,您就会看到它 .

    <root level="info">
        <appender-ref ref="RollingFile" />
        <appender-ref ref="Console" />
    </root>
    
  • 0

    这就是我想出的 . 它包含了在常规实现中更换 Logger 的想法 .

    使用默认日志实现的问题是通过slf4j bridge调整commons-logging的方式 .

    这可能是最活跃的代码之一,所以希望我们会在即将发布的spring-boot发行版中看到修复...

    第1步:注册新的应用程序监听器

    /META-INF/spring.factory

    org.springframework.context.ApplicationListener=ac.me.appevents.BannerDisplay
    

    第2步:实现应用程序侦听器

    package ac.me.appevents;
    
    import org.jetbrains.annotations.NotNull;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.slf4j.Marker;
    import org.slf4j.MarkerFactory;
    import org.springframework.boot.ResourceBanner;
    import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.core.env.Environment;
    import org.springframework.core.io.DefaultResourceLoader;
    import org.springframework.core.io.Resource;
    import org.springframework.core.io.ResourceLoader;
    import org.springframework.util.ClassUtils;
    
    import java.io.ByteArrayOutputStream;
    import java.io.PrintStream;
    import java.io.UnsupportedEncodingException;
    
    public class BannerDisplay implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
        /**
         * Banner location property key.
         */
        private static final String BANNER_LOCATION_PROPERTY = "banner.location";
    
        /**
         * Default banner location.
         */
        private static final String BANNER_LOCATION_PROPERTY_VALUE = "banner.txt";
    
        private static final Logger LOG = LoggerFactory.getLogger(BannerDisplay.class);
    
        private static final Marker MRK = MarkerFactory.getMarker("Banner");
    
        private ResourceLoader resourceLoader;
    
        private Class<?> deduceMainApplicationClass() {
            try {
                StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if ("main".equals(stackTraceElement.getMethodName())) {
                        return Class.forName(stackTraceElement.getClassName());
                    }
                }
            }
            catch (ClassNotFoundException ex) {
                // Swallow and continue
            }
            return null;
        }
    
        @Override
        public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
            Environment environment = event.getEnvironment();
    
            String location = environment.getProperty(BANNER_LOCATION_PROPERTY, BANNER_LOCATION_PROPERTY_VALUE);
            ResourceLoader resLoader = getResourceLoader();
            Resource resource = resLoader.getResource(location);
            if (resource.exists()) {
                ResourceBanner banner = new ResourceBanner(resource);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                banner.printBanner(environment, deduceMainApplicationClass(), new PrintStream(baos));
                String charset = environment.getProperty("banner.charset", "UTF-8");
                try {
    
                    LOG.info(MRK, baos.toString(charset));
                }
                catch (UnsupportedEncodingException e) {
                    LOG.warn(MRK, "Unsupported banner charset encoding.", e);
                }
    
            }
        }
    
        @NotNull
        private ResourceLoader getResourceLoader() {
            if (resourceLoader == null) {
                this.resourceLoader = new DefaultResourceLoader(ClassUtils.getDefaultClassLoader());
            }
            return resourceLoader;
        }
    
        public void setResourceLoader(final ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }
    }
    
  • 6

    首先,我必须承认我没有对此进行测试,但至少它可能会给你一些想法 .

    您可以删除 spring.main.banner-mode=log 并提供您自己的包装器实现,该实现将使用 Logger 而不是提供的输出流 . 代码应如下所示:

    public class BannerLoggerWrapper implements Banner {
    
        private static final Log logger = LogFactory.getLog(BannerLoggerWrapper.class);
        private Banner actual;
    
        public BannerLoggerWrapper(Banner actual) {
            this.actual = actual;
        }
    
        @Override
        public void printBanner(Environment environment, Class<?> sourceClass, PrintStream out) {
            try {
                logger.info(createStringFromBanner(environment, sourceClass));
            } catch (UnsupportedEncodingException ex) {
                logger.warn("Failed to create String for banner", ex);
            }
        }
    
        private String createStringFromBanner(Environment environment, Class<?> sourceClass) throws UnsupportedEncodingException {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            actual.printBanner(environment, sourceClass, new PrintStream(baos));
            String charset = environment.getProperty("banner.charset", "UTF-8");
            return baos.toString(charset);
        }
    
    }
    

    您可以在此类中将 logger.info 替换为 logger.warn ,或者您可以为此 Logger 创建特定的其他配置:

    <logger name="your.package.name.BannerLoggerWrapper" level="INFO" additivity="false">
        <appender-ref ref="FILE"/>
    </logger>
    

    根据documentation,您可以使用 SpringApplication.setBanner(…) 配置Spring Boot以使用Banner实现 .

相关问题