package com.arcao.slf4j.timber;
import org.slf4j.helpers.FormattingTuple;
import org.slf4j.helpers.MarkerIgnoringBase;
import org.slf4j.helpers.MessageFormatter;
import timber.log.Timber;
import timber.log.Timber.Tree;
/**
* <p>A simple implementation that delegates all log requests to the Timber
* logging facilities. Note that this logger does not support {@link org.slf4j.Marker}.
* Methods taking marker data as parameter simply invoke the eponymous method
* without the Marker argument, discarding any marker data in the process.</p>
*
* <p>The logging levels specified for SLF4J can be almost directly mapped to
* the logging method that exist in Timber. The following table
* shows the mapping implemented by this logger.</p>
*
* <table border="1">
* <tr><th><b>SLF4J<b></th><th><b>Timber</b></th></tr>
* <tr><td>TRACE</td><td>Timber.v(...)</td></tr>
* <tr><td>DEBUG</td><td>Timber.d(...)</td></tr>
* <tr><td>INFO</td><td>Timber.i(...)</td></tr>
* <tr><td>WARN</td><td>Timber.w(...)</td></tr>
* <tr><td>ERROR</td><td>Timber.e(...)</td></tr>
* </table>
*
* <p>Use loggers as usual:
* <ul>
* <li>
* Declare a logger<br/>
* <code>private static final Logger logger = LoggerFactory.getLogger(MyClass.class);</code>
* </li>
* <li>
* Invoke logging methods, e.g.,<br/>
* <code>logger.debug("Some log message. Details: {}", someObject);</code><br/>
* <code>logger.debug("Some log message with varargs. Details: {}, {}, {}", someObject1, someObject2, someObject3);</code>
* </li>
* </ul>
* </p>
*
* <p>Logger instances created using the LoggerFactory are named either according to the name
* or the fully qualified class name of the class given as a parameter.
* Each logger name will be used as the tag for Timber if Timber has planted {@link timber.log.Timber.TaggedTree}.
* If tag contains also class package, it will be removed (same way like in {@link timber.log.Timber.DebugTree}).
* </p>
*
* @author Martin Sloup <arcao@arcao.com>
*/
class TimberLoggerAdapter extends MarkerIgnoringBase {
private static final long serialVersionUID = -1227274521521287937L;
private enum LogType {
TRACE,
DEBUG,
INFO,
WARN,
ERROR
}
/**
* Package access allows only {@link AndroidLoggerFactory} to instantiate
* SimpleLogger instances.
*/
TimberLoggerAdapter(String tag) {
this.name = tag;
}
@Override
public boolean isTraceEnabled() {
return true;
}
@Override
public void trace(String msg) {
log(LogType.TRACE, msg, null);
}
@Override
public void trace(String format, Object arg) {
formatAndLog(LogType.TRACE, format, arg);
}
@Override
public void trace(String format, Object arg1, Object arg2) {
formatAndLog(LogType.TRACE, format, arg1, arg2);
}
@Override
public void trace(String format, Object... argArray) {
formatAndLog(LogType.TRACE, format, argArray);
}
@Override
public void trace(String msg, Throwable t) {
log(LogType.TRACE, msg, t);
}
@Override
public boolean isDebugEnabled() {
return true;
}
@Override
public void debug(String msg) {
log(LogType.DEBUG, msg, null);
}
@Override
public void debug(String format, Object arg) {
formatAndLog(LogType.DEBUG, format, arg);
}
@Override
public void debug(String format, Object arg1, Object arg2) {
formatAndLog(LogType.DEBUG, format, arg1, arg2);
}
@Override
public void debug(String format, Object... argArray) {
formatAndLog(LogType.DEBUG, format, argArray);
}
@Override
public void debug(String msg, Throwable t) {
log(LogType.DEBUG, msg, t);
}
@Override
public boolean isInfoEnabled() {
return true;
}
@Override
public void info(String msg) {
log(LogType.INFO, msg, null);
}
@Override
public void info(String format, Object arg) {
formatAndLog(LogType.INFO, format, arg);
}
@Override
public void info(String format, Object arg1, Object arg2) {
formatAndLog(LogType.INFO, format, arg1, arg2);
}
@Override
public void info(String format, Object... argArray) {
formatAndLog(LogType.INFO, format, argArray);
}
@Override
public void info(String msg, Throwable t) {
log(LogType.INFO, msg, t);
}
@Override
public boolean isWarnEnabled() {
return true;
}
@Override
public void warn(String msg) {
log(LogType.WARN, msg, null);
}
@Override
public void warn(String format, Object arg) {
formatAndLog(LogType.WARN, format, arg);
}
@Override
public void warn(String format, Object arg1, Object arg2) {
formatAndLog(LogType.WARN, format, arg1, arg2);
}
@Override
public void warn(String format, Object... argArray) {
formatAndLog(LogType.WARN, format, argArray);
}
@Override
public void warn(String msg, Throwable t) {
log(LogType.WARN, msg, t);
}
@Override
public boolean isErrorEnabled() {
return true;
}
@Override
public void error(String msg) {
log(LogType.ERROR, msg, null);
}
@Override
public void error(String format, Object arg) {
formatAndLog(LogType.ERROR, format, arg);
}
@Override
public void error(String format, Object arg1, Object arg2) {
formatAndLog(LogType.ERROR, format, arg1, arg2);
}
@Override
public void error(String format, Object... argArray) {
formatAndLog(LogType.ERROR, format, argArray);
}
@Override
public void error(String msg, Throwable t) {
log(LogType.ERROR, msg, t);
}
private void formatAndLog(LogType logType, String format, Object... argArray) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
log(logType, ft.getMessage(), ft.getThrowable());
}
private void log(LogType logType, String message, Throwable throwable) {
Tree tree = Timber.tag(name);
switch(logType) {
case TRACE:
if (throwable != null) {
tree.v(throwable, message);
} else {
tree.v(message);
}
break;
case DEBUG:
if (throwable != null) {
tree.d(throwable, message);
} else {
tree.d(message);
}
break;
case INFO:
default:
if (throwable != null) {
tree.i(throwable, message);
} else {
tree.i(message);
}
break;
case WARN:
if (throwable != null) {
tree.w(throwable, message);
} else {
tree.w(message);
}
break;
case ERROR:
if (throwable != null) {
tree.e(throwable, message);
} else {
tree.e(message);
}
break;
}
}
}