1919import ch .qos .logback .classic .Logger ;
2020import ch .qos .logback .classic .spi .ILoggingEvent ;
2121import ch .qos .logback .core .Appender ;
22+ import ch .qos .logback .core .ConsoleAppender ;
2223import ch .qos .logback .core .filter .Filter ;
2324import nl .altindag .log .appender .InMemoryAppender ;
24- import nl .altindag .log .appender .NOPAppender ;
2525import nl .altindag .log .model .LogEvent ;
26+ import nl .altindag .log .util .AppenderUtils ;
2627import nl .altindag .log .util .JavaUtilLoggingLoggerUtils ;
2728import nl .altindag .log .util .LogbackUtils ;
2829import nl .altindag .log .util .Mappers ;
2930
3031import java .util .Arrays ;
3132import java .util .Collections ;
3233import java .util .HashMap ;
34+ import java .util .Iterator ;
3335import java .util .List ;
3436import java .util .Map ;
3537import java .util .Objects ;
@@ -50,17 +52,50 @@ public final class LogCaptor implements AutoCloseable {
5052 private static final List <String > CONSOLE_APPENDER_NAMES = Arrays .asList ("console" , "CONSOLE" );
5153
5254 private final Logger logger ;
53- private final Appender <ILoggingEvent > appender ;
55+ private final InMemoryAppender <ILoggingEvent > inMemoryAppender ;
56+ private final ConsoleAppender <ILoggingEvent > consoleAppender ;
5457 private final List <ILoggingEvent > eventsCollector = new CopyOnWriteArrayList <>();
5558
5659 private LogCaptor (String loggerName ) {
5760 logger = LogbackUtils .getLogger (loggerName );
58- appender = new InMemoryAppender <>("log-captor" , eventsCollector );
59- appender .start ();
60- logger .addAppender (appender );
61+ inMemoryAppender = new InMemoryAppender <>("log-captor" , eventsCollector );
62+ inMemoryAppender .start ();
63+ logger .addAppender (inMemoryAppender );
6164
6265 JavaUtilLoggingLoggerUtils .redirectToSlf4j (loggerName );
6366 logLevelContainer .putIfAbsent (logger .getName (), logger .getEffectiveLevel ());
67+ consoleAppender = configureConsoleAppender (loggerName );
68+ }
69+
70+ private ConsoleAppender <ILoggingEvent > configureConsoleAppender (String loggerName ) {
71+ Optional <ConsoleAppender <ILoggingEvent >> consoleAppender ;
72+ if (ROOT_LOGGER_NAME .equals (loggerName )) {
73+ Logger rootLogger = getRootLogger ();
74+ consoleAppender = getConsoleAppender (rootLogger );
75+ } else {
76+ logger .setAdditive (false ); // prevent log messages to be propagated to the root logger
77+ consoleAppender = getConsoleAppender (logger );
78+ }
79+
80+ if (!consoleAppender .isPresent ()) {
81+ consoleAppender = Optional .of (AppenderUtils .createConsoleAppender (logger .getLoggerContext ()));
82+ }
83+
84+ if (!ROOT_LOGGER_NAME .equals (loggerName )) {
85+ boolean containsRootConsoleAppender = false ;
86+ Iterator <Appender <ILoggingEvent >> rootAppenders = getRootLogger ().iteratorForAppenders ();
87+ while (rootAppenders .hasNext ()) {
88+ if (rootAppenders .next () instanceof ConsoleAppender ) {
89+ containsRootConsoleAppender = true ;
90+ }
91+ }
92+
93+ if (containsRootConsoleAppender ) {
94+ logger .addAppender (consoleAppender .get ());
95+ }
96+ }
97+
98+ return consoleAppender .get ();
6499 }
65100
66101 /**
@@ -163,7 +198,7 @@ private boolean hasMessage(Level level, String message) {
163198 }
164199
165200 public void addFilter (Filter <ILoggingEvent > filter ) {
166- appender .addFilter (filter );
201+ inMemoryAppender .addFilter (filter );
167202 filter .start ();
168203 }
169204
@@ -214,23 +249,30 @@ public void disableLogs() {
214249 * LogCaptor will still be capturing the log entries.
215250 */
216251 public void disableConsoleOutput () {
217- logger .setAdditive (false );
218- logger .addAppender (new NOPAppender <>(logger .getLoggerContext ()));
252+ Optional .ofNullable (consoleAppender ).ifPresent (logger ::detachAppender );
253+ if (!logger .iteratorForAppenders ().hasNext ()) {
254+ logger .addAppender (AppenderUtils .createNopAppender (logger .getLoggerContext ()));
255+ }
219256 }
220257
221258 /**
222259 * The output of the log entries to the console are enabled by default but can be re-enabled if
223260 * they are disabled earlier by {@link LogCaptor#disableConsoleOutput()}
224261 */
225262 public void enableConsoleOutput () {
226- logger .setAdditive (true );
227- logger .detachAppender (NOPAppender .APPENDER_NAME );
263+ logger .detachAppender (AppenderUtils .NOP_APPENDER_NAME );
264+ logger .addAppender (consoleAppender );
265+ if (!consoleAppender .isStarted ()) {
266+ consoleAppender .start ();
267+ }
228268 }
229269
230- Optional <Appender <ILoggingEvent >> getConsoleAppender (Logger logger ) {
270+ Optional <ConsoleAppender <ILoggingEvent >> getConsoleAppender (Logger logger ) {
231271 return CONSOLE_APPENDER_NAMES .stream ()
232272 .map (logger ::getAppender )
233273 .filter (Objects ::nonNull )
274+ .filter (ConsoleAppender .class ::isInstance )
275+ .map (consoleAppender -> (ConsoleAppender <ILoggingEvent >) consoleAppender )
234276 .findFirst ();
235277 }
236278
@@ -257,8 +299,12 @@ public void clearLogs() {
257299
258300 @ Override
259301 public void close () {
260- logger .detachAppender (appender );
261- appender .stop ();
302+ logger .detachAppender (inMemoryAppender );
303+ inMemoryAppender .stop ();
304+ if (!ROOT_LOGGER_NAME .equals (logger .getName ())) {
305+ logger .setAdditive (true );
306+ logger .detachAppender (consoleAppender );
307+ }
262308 }
263309
264310 @ Override
0 commit comments