tutorial starter springboot mkyong logger log debug java spring spring-mvc spring-boot logback

starter - spring java log



Mostrar Banner de arranque con Root-Logger WARN (3)

En el entorno de desarrollo y prueba, el nivel de registro ROOT es DEBUG o INFO. El banner de inicio de primavera se muestra al inicio de la aplicación:

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

Pero cuando se ejecuta en un entorno de producción, mi nivel de registrador ROOT normalmente es WARN. Esto hace que el banner no se imprima.

¿Cómo configurar logback para que el banner se muestre también en producción?

Mi suposición era agregar otro registrador, pero la siguiente (y la misma configuración) no funcionó:

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

Aquí mi configuración

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 mostrado)

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 no mostrado)

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>


Esto es, lo que se me ocurrió. Se ajusta a la idea de simplemente reemplazar el registrador en la implementación regular.

El problema con el uso de la implementación de registro predeterminada es la forma en que el registro de recursos comunes se adapta a través del puente slf4j.

Este es probablemente uno de los códigos más feos, por lo que esperamos ver una solución en las próximas versiones de arranque de primavera ...

Paso 1: registrar un nuevo oyente de la aplicación

/META-INF/spring.factory

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

Paso 2: Implemente el oyente de la aplicación

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


Durante la impresión, un banner Spring Boot utiliza el registrador de la clase org.springframework.boot.SpringApplication con el nivel INFO .

La solución más simple sería habilitar el nivel INFO para esta clase en particular:

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


Primero, debo admitir que no lo he probado, pero al menos puede darte algunas ideas.

Puede eliminar spring.main.banner-mode=log y proporcionar su propia implementación de contenedor que usará el registrador en lugar del flujo de salida proporcionado. El código debería verse más o menos así:

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

Puede reemplazar logger.info con logger.warn en esta clase o puede crear configuraciones adicionales específicamente para este registrador:

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

De acuerdo con la documentación , puede configurar Spring Boot para usar su implementación de Banner usando SpringApplication.setBanner(…​) .