/*
This file is part of Project MAXS.
MAXS and its modules is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
MAXS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MAXS. If not, see <http://www.gnu.org/licenses/>.
*/
package org.projectmaxs.shared.global.jul;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringBufferInputStream;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import org.projectmaxs.shared.global.GlobalConstants;
import org.projectmaxs.shared.global.util.Log.DebugLogSettings;
import org.projectmaxs.shared.global.util.SharedStringUtil;
import android.util.Log;
@SuppressWarnings("deprecation")
public class JULHandler extends Handler {
private static final String CLASS_NAME = JULHandler.class.getName();
/**
* The global LogManager configuration.
*
* This configures:
* - JULHandler as the default handler for all log messages
* - A default log level FINEST (300). Meaning that log messages of a level 300 or higher a
* logged
*/
private static final InputStream LOG_MANAGER_CONFIG = new StringBufferInputStream(
// @formatter:off
"handlers = " + CLASS_NAME + '\n' +
".level = FINEST"
);
// @formatter:on
private static final int FINE_INT = Level.FINE.intValue();
private static final int INFO_INT = Level.INFO.intValue();
private static final int WARN_INT = Level.WARNING.intValue();
private static final int SEVE_INT = Level.SEVERE.intValue();
private static final Logger LOGGER = Logger.getLogger(CLASS_NAME);
private static final Set<String> NO_LOG_PKGS = new HashSet<String>();
/**
* Whether or the stacktraces of throwables attached to INFO or FINE* log levels should also be
* logged. Usually these create a log of noise and so, logging them is not really desirable.
*/
private static boolean LOG_INFO_THROWABLES = false;
private static final Formatter FORMATTER = new Formatter() {
@Override
public String format(LogRecord logRecord) {
String message = formatMessage(logRecord);
Throwable thrown = logRecord.getThrown();
if (thrown != null) {
if (logRecord.getLevel().intValue() > INFO_INT || LOG_INFO_THROWABLES) {
// Log the full stacktrace.
String stacktrace = Log.getStackTraceString(thrown);
return message + ' ' + stacktrace;
} else {
// Log only the throwable's message.
return message + " (" + thrown + ")";
}
} else {
return message;
}
}
};
private static DebugLogSettings sDebugLogSettings;
static {
boolean initialized = false;
try {
LogManager.getLogManager().readConfiguration(LOG_MANAGER_CONFIG);
initialized = true;
} catch (IOException e) {
Log.e("JULHandler", "Can not initialize configuration", e);
}
if (initialized) LOGGER.info("Initialzied java.util.logging logger");
}
public static void init(DebugLogSettings debugLogSettings) {
sDebugLogSettings = debugLogSettings;
}
public static void addNoLogPkg(String pkg) {
NO_LOG_PKGS.add(pkg);
}
public static void removeNoLogPkg(String pkg) {
NO_LOG_PKGS.remove(pkg);
}
public JULHandler() {
setFormatter(FORMATTER);
}
@Override
public void close() {}
@Override
public void flush() {}
@Override
public boolean isLoggable(LogRecord record) {
final String sourceClass = record.getSourceClassName();
if (sourceClass != null) {
for (String noLogPkg : NO_LOG_PKGS) {
if (sourceClass.startsWith(noLogPkg)) {
return false;
}
}
}
final boolean debugLog = sDebugLogSettings == null ? true : sDebugLogSettings
.isDebugLogEnabled();
if (record.getLevel().intValue() <= FINE_INT) {
return debugLog;
}
return true;
}
@Override
public void publish(LogRecord record) {
if (!isLoggable(record)) return;
final int priority = getAndroidPriority(record.getLevel());
final String tag = GlobalConstants.MAXS + '/'
+ SharedStringUtil.substringAfterLastDot(record.getSourceClassName());
final String msg = getFormatter().format(record);
Log.println(priority, tag, msg);
}
private static int getAndroidPriority(Level level) {
int value = level.intValue();
if (value >= SEVE_INT) {
return Log.ERROR;
} else if (value >= WARN_INT) {
return Log.WARN;
} else if (value >= INFO_INT) {
return Log.INFO;
} else {
return Log.DEBUG;
}
}
private static final UncaughtExceptionHandler UNCAUGHT_EXCEPTION_HANDLER = new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
LOGGER.log(Level.SEVERE, "Uncaught exception in " + thread, ex);
}
};
public static void setAsDefaultUncaughtExceptionHandler() {
UncaughtExceptionHandler currentUncaughtExceptionHandler = Thread
.getDefaultUncaughtExceptionHandler();
if (currentUncaughtExceptionHandler != UNCAUGHT_EXCEPTION_HANDLER) {
Thread.setDefaultUncaughtExceptionHandler(UNCAUGHT_EXCEPTION_HANDLER);
}
}
}