package org.wikipedia.util.log; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; import org.wikipedia.util.ReleaseUtil; /** Logging utility like {@link Log} but with implied tags. */ public final class L { private static final LogLevel LEVEL_V = new LogLevel() { @Override public void logLevel(String tag, String msg, Throwable t) { Log.v(tag, msg, t); } }; private static final LogLevel LEVEL_D = new LogLevel() { @Override public void logLevel(String tag, String msg, Throwable t) { Log.d(tag, msg, t); } }; private static final LogLevel LEVEL_I = new LogLevel() { @Override public void logLevel(String tag, String msg, Throwable t) { Log.i(tag, msg, t); } }; private static final LogLevel LEVEL_W = new LogLevel() { @Override public void logLevel(String tag, String msg, Throwable t) { Log.w(tag, msg, t); } }; private static final LogLevel LEVEL_E = new LogLevel() { @Override public void logLevel(String tag, String msg, Throwable t) { Log.e(tag, msg, t); } }; @Nullable private static RemoteExceptionLogger REMOTE_EXCEPTION_LOGGER; public static void v(CharSequence msg) { LEVEL_V.log(msg, null); } public static void d(CharSequence msg) { LEVEL_D.log(msg, null); } public static void i(CharSequence msg) { LEVEL_I.log(msg, null); } public static void w(CharSequence msg) { LEVEL_W.log(msg, null); } public static void e(CharSequence msg) { LEVEL_E.log(msg, null); } public static void v(Throwable t) { LEVEL_V.log("", t); } public static void d(Throwable t) { LEVEL_D.log("", t); } public static void i(Throwable t) { LEVEL_I.log("", t); } public static void w(Throwable t) { LEVEL_W.log("", t); } public static void e(Throwable t) { LEVEL_E.log("", t); } public static void v(CharSequence msg, Throwable t) { LEVEL_V.log(msg, t); } public static void d(CharSequence msg, Throwable t) { LEVEL_D.log(msg, t); } public static void i(CharSequence msg, Throwable t) { LEVEL_I.log(msg, t); } public static void w(CharSequence msg, Throwable t) { LEVEL_W.log(msg, t); } public static void e(CharSequence msg, Throwable t) { LEVEL_E.log(msg, t); } public static void logRemoteErrorIfProd(@NonNull Throwable t) { if (ReleaseUtil.isProdRelease()) { logRemoteError(t); } else { throw new RuntimeException(t); } } public static void setRemoteLogger(@Nullable RemoteExceptionLogger logger) { REMOTE_EXCEPTION_LOGGER = logger; } // Favor logRemoteErrorIfProd(). If it's worth consuming bandwidth and developer hours, it's // worth crashing on everything but prod public static void logRemoteError(@NonNull Throwable t) { LEVEL_E.log("", t); if (REMOTE_EXCEPTION_LOGGER != null) { REMOTE_EXCEPTION_LOGGER.log(t); } } private abstract static class LogLevel { private static final int STACK_INDEX = 4; public abstract void logLevel(String tag, String msg, Throwable t); public final void log(CharSequence msg, Throwable t) { StackTraceElement element = Thread.currentThread().getStackTrace()[STACK_INDEX]; logLevel(element.getClassName(), stackTraceElementToMessagePrefix(element) + msg, t); } private String stackTraceElementToMessagePrefix(StackTraceElement element) { return element.getMethodName() + "():" + element.getLineNumber() + ": "; } } private L() { } }