背景
经常会为log定位而烦恼。比如:同一个类,一样的log输出,无法定位到Log输出的行。
方案
1.java StackTraceElement
通过java StackTraceElement获取类名,以及log输出行
2. 具体实现
@NonNull
private static String getSourcePoint()
{
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
assert stackTrace.length > CALL_STACK_INDEX : "Synthetic stacktrace doesn't have enough elements";
final StackTraceElement st = stackTrace[CALL_STACK_INDEX];
StringBuilder sb = new StringBuilder(80);
final String fileName = st.getFileName();
if (fileName != null)
{
sb.append(fileName);
final int lineNumber = st.getLineNumber();
if (lineNumber >= 0)
sb.append(':').append(lineNumber);
sb.append(' ');
}
sb.append(st.getMethodName()).append("()");
return sb.toString();
}
3. logger.java实现
package com.app.test.util.log;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.app.test.BuildConfig;
import net.jcip.annotations.ThreadSafe;
@ThreadSafe
public final class Logger
{
private static final String TAG = Logger.class.getSimpleName();
private static final String CORE_TAG = "APP";
private static final String FILENAME = "app.log";
public static void v(String tag)
{
log(Log.VERBOSE, tag, "", null);
}
public static void v(String tag, String msg)
{
log(Log.VERBOSE, tag, msg, null);
}
public static void v(String tag, String msg, Throwable tr)
{
log(Log.VERBOSE, tag, msg, tr);
}
public static void d(String tag)
{
log(Log.DEBUG, tag, "", null);
}
public static void d(String tag, String msg)
{
log(Log.DEBUG, tag, msg, null);
}
public static void d(String tag, String msg, Throwable tr)
{
log(Log.DEBUG, tag, msg, tr);
}
public static void i(String tag)
{
log(Log.INFO, tag, "", null);
}
public static void i(String tag, String msg)
{
log(Log.INFO, tag, msg, null);
}
public static void i(String tag, String msg, Throwable tr)
{
log(Log.INFO, tag, msg, tr);
}
public static void w(String tag, String msg)
{
log(Log.WARN, tag, msg, null);
}
public static void w(String tag, String msg, Throwable tr)
{
log(Log.WARN, tag, msg, tr);
}
public static void e(String tag, String msg)
{
log(Log.ERROR, tag, msg, null);
}
public static void e(String tag, String msg, Throwable tr)
{
log(Log.ERROR, tag, msg, tr);
}
// Index of stacktrace depth where the original log method call resides.
private static final int CALL_STACK_INDEX = 3;
@NonNull
private static String getSourcePoint()
{
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
assert stackTrace.length > CALL_STACK_INDEX : "Synthetic stacktrace doesn't have enough elements";
final StackTraceElement st = stackTrace[CALL_STACK_INDEX];
StringBuilder sb = new StringBuilder(80);
final String fileName = st.getFileName();
if (fileName != null)
{
sb.append(fileName);
final int lineNumber = st.getLineNumber();
if (lineNumber >= 0)
sb.append(':').append(lineNumber);
sb.append(' ');
}
sb.append(st.getMethodName()).append("()");
return sb.toString();
}
// Also called from JNI to proxy native code logging (with tag == null).
@Keep
private static void log(int level, @Nullable String tag, @NonNull String msg, @Nullable Throwable tr)
{
if (BuildConfig.DEBUG || level >= Log.INFO)
{
final StringBuilder sb = new StringBuilder(180);
// Add source point info for file logging, debug builds and ERRORs if its not from core.
if (tag != null && (BuildConfig.DEBUG || level == Log.ERROR))
sb.append(getSourcePoint()).append(": ");
sb.append(msg);
if (tr != null)
sb.append('\n').append(Log.getStackTraceString(tr));
if (tag == null)
tag = CORE_TAG;
if (logsFolder == null || BuildConfig.DEBUG)
Log.println(level, tag, sb.toString());
}
}
private static char getLevelChar(int level)
{
switch (level)
{
case Log.VERBOSE:
return 'V';
case Log.DEBUG:
return 'D';
case Log.INFO:
return 'I';
case Log.WARN:
return 'W';
case Log.ERROR:
return 'E';
}
assert false : "Unknown log level " + level;
return '_';
}
}
4. 结果:
如上图,可以看到log输出java的类名,以及行。
总结
略