package org.ovirt.engine.ui.common.logging;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ovirt.engine.ui.common.system.ApplicationFocusChangeEvent;
import org.ovirt.engine.ui.common.system.ApplicationFocusManager;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.logging.client.SimpleRemoteLogHandler;
import com.google.inject.Inject;
/**
* Bound as GIN eager singleton (and therefore executed just before GWTP's
* {@linkplain com.gwtplatform.mvp.client.Bootstrapper#onBootstrap onBootstrap}),
* it sets up the logging infrastructure.
*/
public class ApplicationLogManager {
private final Logger rootLogger;
private final Logger remoteLogger;
private final ApplicationFocusManager applicationFocusManager;
private Throwable lastError;
private int sameErrorCount = 1;
@Inject
public ApplicationLogManager(EventBus eventBus,
ApplicationFocusManager applicationFocusManager,
final LocalStorageLogHandler localStorageLogHandler) {
this.rootLogger = Logger.getLogger(""); //$NON-NLS-1$
this.remoteLogger = Logger.getLogger("remote"); //$NON-NLS-1$
this.applicationFocusManager = applicationFocusManager;
// Configure root logger
localStorageLogHandler.init();
rootLogger.addHandler(localStorageLogHandler);
// Configure remote logger
remoteLogger.addHandler(new SimpleRemoteLogHandler());
// Enable/disable log handlers when the application window gains/looses its focus
eventBus.addHandler(ApplicationFocusChangeEvent.getType(),
event -> localStorageLogHandler.setActive(event.isInFocus()));
}
/**
* Logs an uncaught exception that would normally escape the application code.
*
* @see com.google.gwt.core.client.GWT.UncaughtExceptionHandler
*/
public void logUncaughtException(Throwable t) {
boolean sameAsLastError = compareWithLastError(t);
if (sameAsLastError) {
sameErrorCount++;
} else {
sameErrorCount = 1;
}
String logMessage = sameAsLastError
? "Uncaught exception (" + sameErrorCount + "x)" //$NON-NLS-1$ //$NON-NLS-2$
: "Uncaught exception"; //$NON-NLS-1$
// Log locally
rootLogger.log(Level.SEVERE, logMessage, t); //$NON-NLS-1$
// Log remotely
if (applicationFocusManager.isInFocus() && !sameAsLastError) {
remoteLogger.log(Level.SEVERE, logMessage, t); //$NON-NLS-1$
}
}
/**
* Returns {@code true} if {@code t} is effectively the same as {@link #lastError}.
*
* @see #compareStackTraces
*/
boolean compareWithLastError(Throwable t) {
if (lastError == null) {
lastError = t;
return false;
}
boolean equalStackTraces = compareStackTraces(lastError, t);
lastError = t;
return equalStackTraces;
}
/**
* Returns {@code true} if {@code t1} and {@code t2} have equal stack traces.
*/
boolean compareStackTraces(Throwable t1, Throwable t2) {
StackTraceElement[] st1 = t1.getStackTrace();
StackTraceElement[] st2 = t2.getStackTrace();
if (st1.length != st2.length) {
return false;
}
for (int i = 0; i < st1.length; i++) {
StackTraceElement e1 = st1[i];
StackTraceElement e2 = st2[i];
if (!e1.toString().equals(e2.toString())) {
return false;
}
}
return true;
}
}