【问题标题】:Display Spring-Boot Banner with Root-Logger WARN使用 Root-Logger WARN 显示 Spring-Boot 横幅
【发布时间】:2017-08-16 03:01:33
【问题描述】:

在开发和测试环境下,ROOT logger 级别为 DEBUG 或 INFO。 spring-boot 横幅在应用程序启动时显示:

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 记录器级别通常为 WARN。这会导致无法打印出横幅。

如何配置 logback 以便在生产中也显示横幅?

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

<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

应用程序生产属性:

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

logging-devel.xml(显示横幅)

        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(不显示横幅)

        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>

【问题讨论】:

    标签: java spring spring-mvc spring-boot logback


    【解决方案1】:

    我有同样的问题,只是在application.properties中设置了这个属性:

    spring.main.banner-mode=LOG
    

    现在它打印到控制台和文件,日志级别为 INFO。只要您将根日志级别和附加程序设置为接受 INFO,您就会看到它。

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

    【讨论】:

      【解决方案2】:

      在打印横幅时,Spring Boot 使用 org.springframework.boot.SpringApplication 类和 INFO 级别的记录器。

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

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

      【讨论】:

      • 如您所说,更改一个类的日志记录级别是最好的方法。为 Spring Boot 执行此操作的另一种方法是通过 Environment 属性,我将其作为 JVM 参数传递,例如-Dlogging.level.org.springframework.boot.SpringApplication=INFO
      • 作品 :) 非常感谢。
      【解决方案3】:

      首先,我必须承认我没有测试过这个,但至少它可以给你一些想法。

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

      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 name="your.package.name.BannerLoggerWrapper" level="INFO" additivity="false">
          <appender-ref ref="FILE"/>
      </logger>
      

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

      【讨论】:

        【解决方案4】:

        这就是我想出的。它围绕着在常规实现中替换记录器的想法。

        使用默认日志实现的问题在于 commons-logging 通过 slf4j 桥适配的方式。

        这可能是最丑陋的代码之一,所以希望我们能在即将发布的 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;
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2023-01-31
          • 2018-11-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-29
          相关资源
          最近更新 更多