Skip to content

Commit

Permalink
Provide more control for how log messages are viewed in an application
Browse files Browse the repository at this point in the history
  • Loading branch information
Rylern committed Sep 18, 2023
1 parent 1d32ad3 commit ddf1726
Show file tree
Hide file tree
Showing 14 changed files with 370 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
package qupath.ui.logviewer.api.listener;

import qupath.ui.logviewer.api.LogMessage;
import qupath.ui.logviewer.api.manager.LoggerManager;

import java.util.Optional;
import java.util.ServiceLoader;

/**
* Interface for classes that listen to new log messages.
Expand All @@ -18,22 +14,4 @@ public interface LoggerListener {
* @param logMessage the new log message
*/
void addLogMessage(LogMessage logMessage);

/**
* Get the logger manager chosen by SLF4J.
* This method shouldn't need to be overridden.
*
* @return the logger manager chosen by SLF4J or an empty optional if no logger has been found
*/
default Optional<LoggerManager> getCurrentLoggerManager() {
ServiceLoader<LoggerManager> serviceLoader = ServiceLoader.load(LoggerManager.class);

for (LoggerManager loggerManager : serviceLoader) {
if (loggerManager.isFrameworkActive()) {
return Optional.of(loggerManager);
}
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import qupath.ui.logviewer.api.listener.LoggerListener;
import org.slf4j.event.Level;

import java.util.Optional;
import java.util.ServiceLoader;

/**
* Interface for logging frameworks.
*/
Expand All @@ -17,6 +20,13 @@ public interface LoggerManager {
*/
void addListener(LoggerListener listener);

/**
* Stop forwarding log messages to the provided logger listener.
*
* @param listener the listener which will stop receiving the logged messages
*/
void removeListener(LoggerListener listener);

/**
* Set the log level of the root logger.
*
Expand All @@ -37,4 +47,21 @@ public interface LoggerManager {
* @return true if this logging framework is used by SLF4J
*/
boolean isFrameworkActive();

/**
* Get the logger manager chosen by SLF4J.
*
* @return the logger manager chosen by SLF4J or an empty optional if no logger has been found
*/
static Optional<LoggerManager> getCurrentLoggerManager() {
ServiceLoader<LoggerManager> serviceLoader = ServiceLoader.load(LoggerManager.class);

for (LoggerManager loggerManager : serviceLoader) {
if (loggerManager.isFrameworkActive()) {
return Optional.of(loggerManager);
}
}

return Optional.empty();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Handler;
import java.util.logging.Logger;

/**
Expand All @@ -14,10 +17,23 @@
public class JdkManager implements LoggerManager {

private static final Logger rootLogger = Logger.getLogger("");
private static final Map<LoggerListener, Handler> handlers = new HashMap<>();

@Override
public void addListener(LoggerListener listener) {
rootLogger.addHandler(new JdkHandler(listener));
if (!handlers.containsKey(listener)) {
Handler handler = new JdkHandler(listener);
handlers.put(listener, handler);
rootLogger.addHandler(handler);
}
}

@Override
public void removeListener(LoggerListener listener) {
if (handlers.containsKey(listener)) {
Handler handler = handlers.remove(listener);
rootLogger.removeHandler(handler);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import qupath.ui.logviewer.api.listener.LoggerListener;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -60,6 +61,20 @@ void Check_Message_Forwarded() throws InterruptedException {
assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_Message_Not_Forwarded() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
JdkManager jdkManager = new JdkManager();
LoggerListener loggerListener = logMessage -> latch.countDown();
jdkManager.addListener(loggerListener);
jdkManager.setRootLogLevel(Level.TRACE);
jdkManager.removeListener(loggerListener);

slf4jLogger.info("A log message");

assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_N_Message_Forwarded() throws InterruptedException {
int N = 5;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,47 @@
package qupath.ui.logviewer.logging.logback;

import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import qupath.ui.logviewer.api.listener.LoggerListener;
import qupath.ui.logviewer.api.manager.LoggerManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

import java.util.HashMap;
import java.util.Map;

/**
* Manager setting up and managing the Logback logger.
*/
public class LogbackManager implements LoggerManager {

private static final Logger slf4jLogger = LoggerFactory.getLogger(LogbackManager.class);
private static final ch.qos.logback.classic.Logger logbackRootLogger = getRootLogger();
private static final Map<LoggerListener, Appender<ILoggingEvent>> appenders = new HashMap<>();

@Override
public void addListener(LoggerListener listener) {
if (logbackRootLogger != null) {
var appender = new LogbackAppender(listener);
appender.setName("LogViewer");
appender.setContext(logbackRootLogger.getLoggerContext());
appender.start();
logbackRootLogger.addAppender(appender);
} else {
slf4jLogger.warn("Cannot add appender to root logger using logback!");
if (!appenders.containsKey(listener)) {
if (logbackRootLogger != null) {
Appender<ILoggingEvent> appender = new LogbackAppender(listener);
appender.setName("LogViewer");
appender.setContext(logbackRootLogger.getLoggerContext());
appender.start();
appenders.put(listener, appender);
logbackRootLogger.addAppender(appender);
} else {
slf4jLogger.warn("Cannot add appender to root logger using logback!");
}
}
}

@Override
public void removeListener(LoggerListener listener) {
if (logbackRootLogger != null && appenders.containsKey(listener)) {
Appender<ILoggingEvent> appender = appenders.remove(listener);
logbackRootLogger.detachAppender(appender);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import qupath.ui.logviewer.api.listener.LoggerListener;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -60,6 +62,20 @@ void Check_Message_Forwarded() throws InterruptedException {
assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_Message_Not_Forwarded() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
LogbackManager logbackManager = new LogbackManager();
LoggerListener loggerListener = logMessage -> latch.countDown();
logbackManager.addListener(loggerListener);
logbackManager.setRootLogLevel(Level.TRACE);
logbackManager.removeListener(loggerListener);

slf4jLogger.info("A log message");

assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_N_Message_Forwarded() throws InterruptedException {
int N = 5;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
package qupath.ui.logviewer.logging.reload4j;

import org.apache.log4j.Appender;
import qupath.ui.logviewer.api.listener.LoggerListener;
import qupath.ui.logviewer.api.manager.LoggerManager;
import org.apache.log4j.Logger;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;

import java.util.HashMap;
import java.util.Map;

/**
* Manager setting up and managing the Reload4j logger.
*/
public class Reload4jManager implements LoggerManager {

private static final Logger rootLogger = Logger.getRootLogger();
private static final Map<LoggerListener, Appender> appenders = new HashMap<>();

@Override
public void addListener(LoggerListener listener) {
var appender = new Reload4jAppender(listener);
appender.setName("LogViewer");
rootLogger.addAppender(appender);
if (!appenders.containsKey(listener)) {
Appender appender = new Reload4jAppender(listener);
appender.setName("LogViewer");
appenders.put(listener, appender);
rootLogger.addAppender(appender);
}
}

@Override
public void removeListener(LoggerListener listener) {
if (appenders.containsKey(listener)) {
Appender appender = appenders.remove(listener);
rootLogger.removeAppender(appender);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import qupath.ui.logviewer.api.listener.LoggerListener;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -60,6 +61,20 @@ void Check_Message_Forwarded() throws InterruptedException {
assertTrue(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_Message_Not_Forwarded() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
Reload4jManager reload4jManager = new Reload4jManager();
LoggerListener loggerListener = logMessage -> latch.countDown();
reload4jManager.addListener(loggerListener);
reload4jManager.setRootLogLevel(Level.TRACE);
reload4jManager.removeListener(loggerListener);

slf4jLogger.info("A log message");

assertFalse(latch.await(100, TimeUnit.MILLISECONDS));
}

@Test
void Check_N_Message_Forwarded() throws InterruptedException {
int N = 5;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/**
* Counts the number of LogMessage of each level of an <a href="https://docs.oracle.com/javase/8/javafx/api/javafx/collections/ObservableList.html">ObservableList</a>.
*/
class LogMessageCounts {
public class LogMessageCounts {

private final ReadOnlyIntegerWrapper allMessagesCount = new ReadOnlyIntegerWrapper(0);
private final ReadOnlyIntegerWrapper errorLevelCount = new ReadOnlyIntegerWrapper(0);
Expand Down
Loading

0 comments on commit ddf1726

Please sign in to comment.