2020import java .util .Optional ;
2121import java .util .function .Function ;
2222
23+ import org .springframework .util .ClassUtils ;
24+
2325import org .slf4j .ILoggerFactory ;
2426import org .slf4j .Logger ;
2527import org .slf4j .LoggerFactory ;
26- import org .slf4j .impl .StaticLoggerBinder ;
2728
2829import ch .qos .logback .classic .LoggerContext ;
2930import ch .qos .logback .classic .spi .ILoggingEvent ;
4344@ SuppressWarnings ("unused" )
4445public abstract class LogbackSupport {
4546
47+ private static final Class <ch .qos .logback .classic .Logger > LOGBACK_LOGGER_TYPE = ch .qos .logback .classic .Logger .class ;
48+
49+ private static final String STATIC_LOGGER_BINDER_CLASSNAME = "org.slf4j.impl.StaticLoggerBinder" ;
50+
51+ private static final boolean STATIC_LOGGER_BINDER_CLASS_PRESENT =
52+ ClassUtils .isPresent (STATIC_LOGGER_BINDER_CLASSNAME , ClassUtils .getDefaultClassLoader ());
53+
4654 protected static final Function <Logger , Optional <ch .qos .logback .classic .Logger >> slf4jLoggerToLogbackLoggerConverter =
4755 logger -> Optional .ofNullable (logger )
4856 .filter (ch .qos .logback .classic .Logger .class ::isInstance )
@@ -69,26 +77,59 @@ public static void suppressSpringBootLogbackInitialization() {
6977 requireLoggerContext ().putObject (SPRING_BOOT_LOGGING_SYSTEM_CLASS_NAME , new Object ());
7078 }
7179
80+ /**
81+ * Properly stops Logback classic.
82+ *
83+ * @see <a href="https://logback.qos.ch/manual/configuration.html#stopContext">Stopping logback-classic</a>
84+ */
85+ public static void stopLogback () {
86+ resolveLoggerContext ()
87+ .ifPresent (LoggerContext ::stop );
88+ }
89+
7290 /**
7391 * Resets the state of the SLF4J Logback logging provider and system.
7492 */
7593 public static void resetLogback () {
7694
7795 try {
96+ resetLoggerContext ();
97+ resetLoggerFactory ();
98+ resetStaticLoggerBinder ();
99+ }
100+ catch (Throwable cause ) {
101+ throw new IllegalStateException ("Failed to reset Logback" , cause );
102+ }
103+ }
104+
105+ private static void resetLoggerContext () {
106+
107+ resolveLoggerContext ().ifPresent (loggerContext -> {
108+ loggerContext .reset ();
109+ loggerContext .getStatusManager ().clear ();
110+ });
111+ }
78112
79- Method loggerFactoryReset = LoggerFactory .class .getDeclaredMethod ("reset" );
113+ private static void resetLoggerFactory () throws Exception {
114+
115+ Method loggerFactoryReset = LoggerFactory .class .getDeclaredMethod ("reset" );
116+
117+ loggerFactoryReset .setAccessible (true );
118+ loggerFactoryReset .invoke (null );
119+ }
80120
81- loggerFactoryReset .setAccessible (true );
82- loggerFactoryReset .invoke (null );
121+ private static void resetStaticLoggerBinder () throws Exception {
83122
84- Method staticLoggerBinderReset = StaticLoggerBinder .class .getDeclaredMethod ("reset" );
123+ if (STATIC_LOGGER_BINDER_CLASS_PRESENT ) {
124+
125+ Class <?> staticLoggerBinderClass =
126+ ClassUtils .forName (STATIC_LOGGER_BINDER_CLASSNAME , ClassUtils .getDefaultClassLoader ());
127+
128+ Method staticLoggerBinderReset = staticLoggerBinderClass .getDeclaredMethod ("reset" );
85129
86130 staticLoggerBinderReset .setAccessible (true );
87131 staticLoggerBinderReset .invoke (null );
88132 }
89- catch (Throwable cause ) {
90- throw new IllegalStateException ("Failed to reset Logback" , cause );
91- }
92133 }
93134
94135 /**
@@ -146,10 +187,10 @@ public static Optional<Logger> resolveRootLogger() {
146187 public static ch .qos .logback .classic .Logger requireLogbackRootLogger () {
147188
148189 return resolveRootLogger ()
149- .filter (ch . qos . logback . classic . Logger . class ::isInstance )
150- .map (ch . qos . logback . classic . Logger . class ::cast )
190+ .filter (LOGBACK_LOGGER_TYPE ::isInstance )
191+ .map (LOGBACK_LOGGER_TYPE ::cast )
151192 .orElseThrow (() -> new IllegalStateException (String .format (ILLEGAL_LOGGER_TYPE_EXCEPTION_MESSAGE ,
152- ROOT_LOGGER_NAME , nullSafeTypeName (resolveRootLogger ()))));
193+ ROOT_LOGGER_NAME , nullSafeTypeName (resolveRootLogger (). orElse ( null ) ))));
153194 }
154195
155196 /**
@@ -166,7 +207,7 @@ public static ch.qos.logback.classic.Logger requireLogbackRootLogger() {
166207 * @see org.slf4j.Logger
167208 */
168209 public static <E , T extends Appender <E >> Optional <T > resolveAppender (ch .qos .logback .classic .Logger logger ,
169- String appenderName , Class <T > appenderType ) {
210+ String appenderName , Class <T > appenderType ) {
170211
171212 appenderType = nullSafeAppenderType (appenderType );
172213
@@ -192,7 +233,7 @@ public static <E, T extends Appender<E>> Optional<T> resolveAppender(ch.qos.logb
192233 * @see ch.qos.logback.core.Appender
193234 */
194235 public static <E , T extends Appender <E >> T requireAppender (ch .qos .logback .classic .Logger logger ,
195- String appenderName , Class <T > appenderType ) {
236+ String appenderName , Class <T > appenderType ) {
196237
197238 return resolveAppender (logger , appenderName , appenderType )
198239 .orElseThrow (() -> new IllegalStateException (String .format (UNRESOLVABLE_APPENDER_EXCEPTION_MESSAGE ,
0 commit comments