Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
How to replace Spring boot's default logback config from a library? (see
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.logging.LoggingApplicationListener;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.logging.logback.LogbackLoggingSystem;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.GenericApplicationListener;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import static org.springframework.boot.logging.LoggingApplicationListener.CONFIG_PROPERTY;
* Load {@literal xxx-slog-logback.xml} using {@literal logging.config} if {@literal logging.config} is not set and no
* logback configuration file is found.
* <p>
* Unfortunately, Spring does not allow a "starter" to ship a logback configuration file that would be loaded by default
* if none is provided by the application. By running this listener just before {@link LoggingApplicationListener}, we
* are able to inspect the logback configuration and use {@literal logging.config} to pass our own if none is detected.
* <p>
* This is hacky, but does the job. Getting ride of this listener would mean that we cannot ship our default
* configuration with the starter and require from our user to create a {@literal logback.xml} file (which would include
* our configuration). Doable but not a great developer experience.
public class SLogApplicationListener implements GenericApplicationListener {
private static final Class<?>[] EVENT_TYPES = {ApplicationEnvironmentPreparedEvent.class};
private static final Class<?>[] SOURCE_TYPES = {SpringApplication.class, ApplicationContext.class};
public int getOrder() {
return LoggingApplicationListener.DEFAULT_ORDER - 1;
public boolean supportsEventType(ResolvableType eventType) {
return isAssignableFrom(eventType.getRawClass(), EVENT_TYPES);
public boolean supportsSourceType(Class<?> sourceType) {
return isAssignableFrom(sourceType, SOURCE_TYPES);
private boolean isAssignableFrom(Class<?> type, Class<?>... supportedTypes) {
return -> supportedType.isAssignableFrom(type));
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent aepEvent = (ApplicationEnvironmentPreparedEvent) event;
private void overrideLogbackConfig(ApplicationEnvironmentPreparedEvent event) {
ConfigurableEnvironment env = event.getEnvironment();
String logConfig = env.getProperty(CONFIG_PROPERTY);
if (StringUtils.hasLength(logConfig)) {
return; // Never override user supplied logging.config
// Must be super careful to not initialize the LoggingSystem (ctor does nothing)
ClassLoader classLoader = event.getSpringApplication().getClassLoader();
LogbackLoggingSystem logbackLoggingSystem = getLogbackLoggingSystem(classLoader);
if (logbackLoggingSystem == null) {
return; // Logback is not active, don't touch anything
if (isLogbackConfPresent(logbackLoggingSystem)) {
return; // A config file at well known location has been found, don't touch anything
private LogbackLoggingSystem getLogbackLoggingSystem(ClassLoader classLoader) {
LoggingSystem loggingSystem = LoggingSystem.get(classLoader);
if (loggingSystem instanceof LogbackLoggingSystem) {
return (LogbackLoggingSystem) loggingSystem;
return null;
private boolean isLogbackConfPresent(LogbackLoggingSystem loggingSystem) {
Method method = ReflectionUtils.findMethod(LogbackLoggingSystem.class, "getSpringInitializationConfig");
try {
String ret = (String) method.invoke(loggingSystem);
return ret != null;
} catch (IllegalAccessException | InvocationTargetException e) {
return false;
private void setConfig(MutablePropertySources sources) {
MapPropertySource mapPropertySource = new MapPropertySource(
Collections.singletonMap(CONFIG_PROPERTY, "classpath:xxx-slog-logback.xml"));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment