package net.i2p.util;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.util.Locale;
import net.i2p.I2PAppContext;
/**
* Wrapper class for whatever logging system I2P uses. This class should be
* instantiated and kept as a variable for each class it is used by, ala:
* <code>private final Log _log = context.logManager().getLog(MyClassName.class);</code>
*
* If there is anything in here that doesn't make sense, turn off your computer
* and go fly a kite.
*
*
* @author jrandom
*/
public class Log {
private final Class<?> _class;
private final String _className;
private final String _name;
private int _minPriority;
private final LogScope _scope;
private final LogManager _manager;
public final static int DEBUG = 10;
public final static int INFO = 20;
public final static int WARN = 30;
public final static int ERROR = 40;
public final static int CRIT = 50;
public final static String STR_DEBUG = "DEBUG";
public final static String STR_INFO = "INFO";
public final static String STR_WARN = "WARN";
public final static String STR_ERROR = "ERROR";
public final static String STR_CRIT = "CRIT";
public static int getLevel(String level) {
if (level == null) return Log.CRIT;
level = level.toUpperCase(Locale.US);
if (STR_DEBUG.startsWith(level)) return DEBUG;
if (STR_INFO.startsWith(level)) return INFO;
if (STR_WARN.startsWith(level)) return WARN;
if (STR_ERROR.startsWith(level)) return ERROR;
if (STR_CRIT.startsWith(level)) return CRIT;
return CRIT;
}
public static String toLevelString(int level) {
switch (level) {
case DEBUG:
return STR_DEBUG;
case INFO:
return STR_INFO;
case WARN:
return STR_WARN;
case ERROR:
return STR_ERROR;
case CRIT:
return STR_CRIT;
}
return (level > CRIT ? STR_CRIT : STR_DEBUG);
}
/**
* Warning - not recommended.
* Use I2PAppContext.getGlobalContext().logManager().getLog(cls)
*/
public Log(Class<?> cls) {
this(I2PAppContext.getGlobalContext().logManager(), cls, null);
_manager.addLog(this);
}
/**
* Warning - not recommended.
* Use I2PAppContext.getGlobalContext().logManager().getLog(name)
*/
public Log(String name) {
this(I2PAppContext.getGlobalContext().logManager(), null, name);
_manager.addLog(this);
}
Log(LogManager manager, Class<?> cls) {
this(manager, cls, null);
}
Log(LogManager manager, String name) {
this(manager, null, name);
}
Log(LogManager manager, Class<?> cls, String name) {
_manager = manager;
_class = cls;
_className = cls != null ? cls.getName() : null;
_name = name;
_minPriority = DEBUG;
_scope = new LogScope(name, cls);
//_manager.addRecord(new LogRecord(Log.class, null, Thread.currentThread().getName(), Log.DEBUG,
// "Log created with manager " + manager + " for class " + cls, null));
}
public void log(int priority, String msg) {
if (priority >= _minPriority) {
_manager.addRecord(new LogRecord(_class, _name,
Thread.currentThread().getName(), priority,
msg, null));
}
}
public void log(int priority, String msg, Throwable t) {
// Boost the priority of NPE and friends so they get seen and reported
//if (t != null && t instanceof RuntimeException && !(t instanceof IllegalArgumentException))
// priority = CRIT;
if (priority >= _minPriority) {
_manager.addRecord(new LogRecord(_class, _name,
Thread.currentThread().getName(), priority,
msg, t));
}
}
/**
* Always log this messge with the given priority, ignoring current minimum priority level.
* This allows an INFO message about changing port numbers, for example, to always be logged.
* @since 0.8.2
*/
public void logAlways(int priority, String msg) {
_manager.addRecord(new LogRecord(_class, _name,
Thread.currentThread().getName(), priority,
msg, null));
}
public void debug(String msg) {
log(DEBUG, msg);
}
public void debug(String msg, Throwable t) {
log(DEBUG, msg, t);
}
public void info(String msg) {
log(INFO, msg);
}
public void info(String msg, Throwable t) {
log(INFO, msg, t);
}
public void warn(String msg) {
log(WARN, msg);
}
public void warn(String msg, Throwable t) {
log(WARN, msg, t);
}
public void error(String msg) {
log(ERROR, msg);
}
public void error(String msg, Throwable t) {
log(ERROR, msg, t);
}
public int getMinimumPriority() {
return _minPriority;
}
public void setMinimumPriority(int priority) {
_minPriority = priority;
//_manager.addRecord(new LogRecord(Log.class, null, Thread.currentThread().getName(), Log.DEBUG,
// "Log with manager " + _manager + " for class " + _class
// + " new priority " + toLevelString(priority), null));
}
public boolean shouldLog(int priority) {
return priority >= _minPriority;
}
/** @since 0.9.20 */
public boolean shouldDebug() {
return shouldLog(DEBUG);
}
/** @since 0.9.20 */
public boolean shouldInfo() {
return shouldLog(INFO);
}
/** @since 0.9.20 */
public boolean shouldWarn() {
return shouldLog(WARN);
}
/** @since 0.9.20 */
public boolean shouldError() {
return shouldLog(ERROR);
}
/**
* logs a loop when closing a resource with level DEBUG
* This method is for debugging purposes only and
* is subject to change or removal w/o notice.
* NOT a supported API.
* @param desc vararg description
* @since 0.9.8
*/
public void logCloseLoop(Object... desc) {
logCloseLoop(Log.DEBUG, desc);
}
/**
* Logs a close loop when closing a resource
* This method is for debugging purposes only and
* is subject to change or removal w/o notice.
* NOT a supported API.
* @param desc vararg description of the resource
* @param level level at which to log
* @since 0.9.8
*/
public void logCloseLoop(int level, Object... desc) {
if (!shouldLog(level))
return;
// catenate all toString()s
StringBuilder builder = new StringBuilder();
builder.append("close() loop in");
for (Object o : desc) {
builder.append(" ");
builder.append(String.valueOf(o));
}
Exception e = new Exception("check stack trace");
log(level,builder.toString(),e);
}
public String getName() {
if (_className != null) return _className;
return _name;
}
/** @return the LogScope (private class) */
public Object getScope() { return _scope; }
static String getScope(String name, Class<?> cls) {
if ( (name == null) && (cls == null) ) return "f00";
if (cls == null) return name;
if (name == null) return cls.getName();
return name + "" + cls.getName();
}
private static final class LogScope {
private final String _scopeCache;
public LogScope(String name, Class<?> cls) {
_scopeCache = getScope(name, cls);
}
@Override
public int hashCode() {
return _scopeCache.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj instanceof LogScope) {
LogScope s = (LogScope)obj;
return s._scopeCache.equals(_scopeCache);
} else if (obj instanceof String) {
return obj.equals(_scopeCache);
}
return false;
}
}
}