LoggingApplicationListener Class — spring-boot Architecture
Architecture documentation for the LoggingApplicationListener class in LoggingApplicationListener.java from the spring-boot codebase.
Entity Profile
Relationship Graph
Source Code
core/spring-boot/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java lines 96–493
public class LoggingApplicationListener implements GenericApplicationListener {
private static final ConfigurationPropertyName LOGGING_LEVEL = ConfigurationPropertyName.of("logging.level");
private static final ConfigurationPropertyName LOGGING_GROUP = ConfigurationPropertyName.of("logging.group");
private static final Bindable<Map<String, LogLevel>> STRING_LOGLEVEL_MAP = Bindable.mapOf(String.class,
LogLevel.class);
private static final Bindable<Map<String, List<String>>> STRING_STRINGS_MAP = Bindable
.of(ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class).asMap());
/**
* The default order for the LoggingApplicationListener.
*/
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20;
/**
* The name of the Spring property that contains a reference to the logging
* configuration to load.
*/
public static final String CONFIG_PROPERTY = "logging.config";
/**
* The name of the Spring property that controls the registration of a shutdown hook
* to shut down the logging system when the JVM exits.
* @see LoggingSystem#getShutdownHandler
*/
public static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = "logging.register-shutdown-hook";
/**
* The name of the {@link LoggingSystem} bean.
*/
public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem";
/**
* The name of the {@link LogFile} bean.
* @since 2.2.0
*/
public static final String LOG_FILE_BEAN_NAME = "springBootLogFile";
/**
* The name of the {@link LoggerGroups} bean.
* @since 2.2.0
*/
public static final String LOGGER_GROUPS_BEAN_NAME = "springBootLoggerGroups";
/**
* The name of the {@link Lifecycle} bean used to handle cleanup.
*/
private static final String LOGGING_LIFECYCLE_BEAN_NAME = "springBootLoggingLifecycle";
private static final Map<String, List<String>> DEFAULT_GROUP_LOGGERS;
static {
MultiValueMap<String, String> loggers = new LinkedMultiValueMap<>();
loggers.add("web", "org.springframework.core.codec");
loggers.add("web", "org.springframework.http");
loggers.add("web", "org.springframework.web");
loggers.add("web", "org.springframework.boot.actuate.endpoint.web");
loggers.add("web", "org.springframework.boot.web.servlet.ServletContextInitializerBeans");
loggers.add("sql", "org.springframework.jdbc.core");
loggers.add("sql", "org.hibernate.SQL");
loggers.add("sql", "org.jooq.tools.LoggerListener");
DEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers);
}
private static final Map<LogLevel, List<String>> SPRING_BOOT_LOGGING_LOGGERS;
static {
MultiValueMap<LogLevel, String> loggers = new LinkedMultiValueMap<>();
loggers.add(LogLevel.DEBUG, "sql");
loggers.add(LogLevel.DEBUG, "web");
loggers.add(LogLevel.DEBUG, "org.springframework.boot");
loggers.add(LogLevel.TRACE, "org.springframework");
loggers.add(LogLevel.TRACE, "org.apache.tomcat");
loggers.add(LogLevel.TRACE, "org.apache.catalina");
loggers.add(LogLevel.TRACE, "org.eclipse.jetty");
loggers.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl");
SPRING_BOOT_LOGGING_LOGGERS = Collections.unmodifiableMap(loggers);
}
private static final Class<?>[] EVENT_TYPES = { ApplicationStartingEvent.class,
ApplicationEnvironmentPreparedEvent.class, ApplicationPreparedEvent.class, ContextClosedEvent.class,
ApplicationFailedEvent.class };
private static final Class<?>[] SOURCE_TYPES = { SpringApplication.class, ApplicationContext.class };
private static final AtomicBoolean shutdownHookRegistered = new AtomicBoolean();
private final Log logger = LogFactory.getLog(getClass());
private @Nullable LoggingSystem loggingSystem;
private @Nullable LogFile logFile;
private @Nullable LoggerGroups loggerGroups;
private int order = DEFAULT_ORDER;
private boolean parseArgs = true;
private @Nullable LogLevel springBootLogging;
@Override
public boolean supportsEventType(ResolvableType resolvableType) {
return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES);
}
@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
return isAssignableFrom(sourceType, SOURCE_TYPES);
}
private boolean isAssignableFrom(@Nullable Class<?> type, Class<?>... supportedTypes) {
if (type != null) {
for (Class<?> supportedType : supportedTypes) {
if (supportedType.isAssignableFrom(type)) {
return true;
}
}
}
return false;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationStartingEvent startingEvent) {
onApplicationStartingEvent(startingEvent);
}
else if (event instanceof ApplicationEnvironmentPreparedEvent environmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(environmentPreparedEvent);
}
else if (event instanceof ApplicationPreparedEvent preparedEvent) {
onApplicationPreparedEvent(preparedEvent);
}
else if (event instanceof ContextClosedEvent contextClosedEvent) {
onContextClosedEvent(contextClosedEvent);
}
else if (event instanceof ApplicationFailedEvent) {
onApplicationFailedEvent();
}
}
private void onApplicationStartingEvent(ApplicationStartingEvent event) {
this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader());
this.loggingSystem.beforeInitialize();
}
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
SpringApplication springApplication = event.getSpringApplication();
if (this.loggingSystem == null) {
this.loggingSystem = LoggingSystem.get(springApplication.getClassLoader());
}
initialize(event.getEnvironment(), springApplication.getClassLoader());
}
private void onApplicationPreparedEvent(ApplicationPreparedEvent event) {
ConfigurableApplicationContext applicationContext = event.getApplicationContext();
ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) {
Assert.state(this.loggingSystem != null, "loggingSystem is not set");
beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem);
}
if (this.logFile != null && !beanFactory.containsBean(LOG_FILE_BEAN_NAME)) {
beanFactory.registerSingleton(LOG_FILE_BEAN_NAME, this.logFile);
}
if (this.loggerGroups != null && !beanFactory.containsBean(LOGGER_GROUPS_BEAN_NAME)) {
beanFactory.registerSingleton(LOGGER_GROUPS_BEAN_NAME, this.loggerGroups);
}
if (!beanFactory.containsBean(LOGGING_LIFECYCLE_BEAN_NAME) && applicationContext.getParent() == null) {
beanFactory.registerSingleton(LOGGING_LIFECYCLE_BEAN_NAME, new Lifecycle());
}
}
private void onContextClosedEvent(ContextClosedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
if (applicationContext.getParent() != null || applicationContext.containsBean(LOGGING_LIFECYCLE_BEAN_NAME)) {
return;
}
cleanupLoggingSystem();
}
void cleanupLoggingSystem() {
if (this.loggingSystem != null) {
this.loggingSystem.cleanUp();
}
}
private void onApplicationFailedEvent() {
cleanupLoggingSystem();
}
/**
* Initialize the logging system according to preferences expressed through the
* {@link Environment} and the classpath.
* @param environment the environment
* @param classLoader the classloader
*/
protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) {
getLoggingSystemProperties(environment).apply();
this.logFile = LogFile.get(environment);
if (this.logFile != null) {
this.logFile.applyToSystemProperties();
}
this.loggerGroups = new LoggerGroups(DEFAULT_GROUP_LOGGERS);
initializeEarlyLoggingLevel(environment);
Assert.state(this.loggingSystem != null, "loggingSystem is not set");
initializeSystem(environment, this.loggingSystem, this.logFile);
initializeFinalLoggingLevels(environment, this.loggingSystem);
registerShutdownHookIfNecessary(environment, this.loggingSystem);
}
private LoggingSystemProperties getLoggingSystemProperties(ConfigurableEnvironment environment) {
return (this.loggingSystem != null) ? this.loggingSystem.getSystemProperties(environment)
: new LoggingSystemProperties(environment);
}
private void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) {
if (this.parseArgs && this.springBootLogging == null) {
if (isSet(environment, "debug")) {
this.springBootLogging = LogLevel.DEBUG;
}
if (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,
@Nullable LogFile logFile) {
String logConfig = environment.getProperty(CONFIG_PROPERTY);
if (StringUtils.hasLength(logConfig)) {
logConfig = logConfig.strip();
}
try {
LoggingInitializationContext initializationContext = new LoggingInitializationContext(environment);
if (ignoreLogConfig(logConfig)) {
system.initialize(initializationContext, null, logFile);
}
else {
system.initialize(initializationContext, logConfig, logFile);
}
}
catch (Throwable ex) {
Throwable exceptionToReport = ex;
while (exceptionToReport != null && !(exceptionToReport instanceof FileNotFoundException)) {
exceptionToReport = exceptionToReport.getCause();
}
exceptionToReport = (exceptionToReport != null) ? exceptionToReport : ex;
// NOTE: We can't use the logger here to report the problem
System.err.println("Logging system failed to initialize using configuration from '" + logConfig + "'");
exceptionToReport.printStackTrace(System.err);
throw new IllegalStateException(ex);
}
}
private boolean ignoreLogConfig(@Nullable String logConfig) {
return !StringUtils.hasLength(logConfig) || logConfig.startsWith("-D");
}
private void initializeFinalLoggingLevels(ConfigurableEnvironment environment, LoggingSystem system) {
bindLoggerGroups(environment);
if (this.springBootLogging != null) {
initializeSpringBootLogging(system, this.springBootLogging);
}
setLogLevels(system, environment);
}
private void bindLoggerGroups(ConfigurableEnvironment environment) {
if (this.loggerGroups != null) {
Binder binder = Binder.get(environment);
binder.bind(LOGGING_GROUP, STRING_STRINGS_MAP).ifBound(this.loggerGroups::putAll);
}
}
/**
* Initialize loggers based on the {@link #setSpringBootLogging(LogLevel)
* springBootLogging} setting. By default this implementation will pick an appropriate
* set of loggers to configure based on the level.
* @param system the logging system
* @param springBootLogging the spring boot logging level requested
* @since 2.2.0
*/
protected void initializeSpringBootLogging(LoggingSystem system, LogLevel springBootLogging) {
BiConsumer<String, @Nullable LogLevel> configurer = getLogLevelConfigurer(system);
SPRING_BOOT_LOGGING_LOGGERS.getOrDefault(springBootLogging, Collections.emptyList())
.forEach((name) -> configureLogLevel(name, springBootLogging, configurer));
}
/**
* Set logging levels based on relevant {@link Environment} properties.
* @param system the logging system
* @param environment the environment
* @since 2.2.0
*/
protected void setLogLevels(LoggingSystem system, ConfigurableEnvironment environment) {
BiConsumer<String, @Nullable LogLevel> customizer = getLogLevelConfigurer(system);
Binder binder = Binder.get(environment);
Map<String, LogLevel> levels = binder.bind(LOGGING_LEVEL, STRING_LOGLEVEL_MAP).orElseGet(Collections::emptyMap);
levels.forEach((name, level) -> configureLogLevel(name, level, customizer));
}
private void configureLogLevel(String name, LogLevel level, BiConsumer<String, @Nullable LogLevel> configurer) {
if (this.loggerGroups != null) {
LoggerGroup group = this.loggerGroups.get(name);
if (group != null && group.hasMembers()) {
group.configureLogLevel(level, configurer);
return;
}
}
configurer.accept(name, level);
}
private BiConsumer<String, @Nullable LogLevel> getLogLevelConfigurer(LoggingSystem system) {
return (name, level) -> {
try {
name = name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME) ? null : name;
system.setLogLevel(name, level);
}
catch (RuntimeException ex) {
this.logger.error(LogMessage.format("Cannot set level '%s' for '%s'", level, name));
}
};
}
private void registerShutdownHookIfNecessary(Environment environment, LoggingSystem loggingSystem) {
if (environment.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, true)) {
Runnable shutdownHandler = loggingSystem.getShutdownHandler();
if (shutdownHandler != null && shutdownHookRegistered.compareAndSet(false, true)) {
registerShutdownHook(shutdownHandler);
}
}
}
void registerShutdownHook(Runnable shutdownHandler) {
SpringApplication.getShutdownHandlers().add(shutdownHandler);
}
public void setOrder(int order) {
this.order = order;
}
@Override
public int getOrder() {
return this.order;
}
/**
* Sets a custom logging level to be used for Spring Boot and related libraries.
* @param springBootLogging the logging level
*/
public void setSpringBootLogging(LogLevel springBootLogging) {
this.springBootLogging = springBootLogging;
}
/**
* Sets if initialization arguments should be parsed for {@literal debug} and
* {@literal trace} properties (usually defined from {@literal --debug} or
* {@literal --trace} command line args). Defaults to {@code true}.
* @param parseArgs if arguments should be parsed
*/
public void setParseArgs(boolean parseArgs) {
this.parseArgs = parseArgs;
}
private final class Lifecycle implements SmartLifecycle {
private volatile boolean running;
@Override
public void start() {
this.running = true;
}
@Override
public void stop() {
this.running = false;
cleanupLoggingSystem();
}
@Override
public boolean isRunning() {
return this.running;
}
@Override
public int getPhase() {
// Shutdown late and always after WebServerStartStopLifecycle
return Integer.MIN_VALUE + 1;
}
}
}
Domain
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free