實現輸出到Logcat的Log日誌,能夠定位到代碼行數,可跳轉至對應的代碼行,並且可以設置日誌緩存;
比較簡單的實現方式,少囉嗦了:
package com.icbc.utils;
import android.os.Environment;
import android.util.Log;
import com.icbc.emallmobile.BuildConfig;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author windfallsheng
* <p>
* 輸出日誌,且定位代碼行數,可緩存日誌到本地文件;
*/
public class Logger {
private final static String TAG = "Logger";
private static boolean isDebug = BuildConfig.DEBUG ? true : false;
private static boolean sCacheable = true;
/**
* 設置一個總開關,決定是否緩存日誌,前提條件是{@link this#isDebug}爲true;
* <p>
* 如果{@link this#sCacheable}爲false,即使用戶調用了緩存日誌的方法,緩存也不生效;
* <p>
* 如果{@link this#sCacheable}爲true,那麼是否緩存日誌,取決於是否調用了緩存日誌的方法;
*
* @param cacheable
*/
public static void initCacheSwitch( boolean cacheable){
sCacheable = cacheable;
}
/**
* 輸出當前日誌,並且定位代碼行數;
*
* @param content
*/
public static void w(String content) {
if (isDebug) {
log(TAG, content, Log.WARN, false);
}
}
public static void w(String tag, String content) {
if (isDebug) {
log(tag, content, Log.WARN, false);
}
}
/**
* 輸出當前日誌,定位代碼行數,並且將日誌緩存至本地;
*
* @param content
*/
public static void wc(String content) {
if (isDebug) {
log(TAG, content, Log.WARN, true);
}
}
public static void wc(String tag, String content) {
if (isDebug) {
log(tag, content, Log.WARN, true);
}
}
public static void e(String content) {
if (isDebug) {
log(TAG, content, Log.ERROR, false);
}
}
public static void e(String tag, String content) {
if (isDebug) {
log(tag, content, Log.ERROR, false);
}
}
public static void ec(String tag, String content) {
if (isDebug) {
log(tag, content, Log.ERROR, true);
}
}
/**
* 輸出方法調用棧鏈的日誌,並且定位代碼行數;
*
* @param content
*/
public static void wl(String tag, String content) {
if (isDebug) {
logLinked(tag, content, Log.WARN, false);
}
}
public static void wl(String content) {
if (isDebug) {
logLinked(TAG, content, Log.WARN, false);
}
}
public static void el(String tag, String content) {
if (isDebug) {
logLinked(tag, content, Log.ERROR, false);
}
}
public static void el(String content) {
if (isDebug) {
logLinked(TAG, content, Log.ERROR, false);
}
}
/**
* 輸出方法調用棧鏈的日誌,定位代碼行數,並且將日誌緩存到本地;
*
* @param content
*/
public static void wlc(String tag, String content) {
if (isDebug) {
logLinked(tag, content, Log.WARN, true);
}
}
public static void wlc(String content) {
if (isDebug) {
logLinked(TAG, content, Log.WARN, true);
}
}
public static void elc(String tag, String content) {
if (isDebug) {
logLinked(tag, content, Log.ERROR, true);
}
}
public static void elc(String content) {
if (isDebug) {
logLinked(TAG, content, Log.ERROR, true);
}
}
private static void log(String tag, String content, int level, boolean cacheable) {
logAndCache(tag, content, level, false, cacheable);
}
private static void logLinked(String tag, String content, int level, boolean cacheable) {
logAndCache(tag, content, level, true, cacheable);
}
private static void logAndCache(String tag, String content, int level, boolean isLinked, boolean cacheable) {
// logTraceInfo(tag, content, level, isLinked);
String info = logTraceInfo(tag, content, level, isLinked);
if (sCacheable && cacheable) {
cacheLogInfo(info);
}
}
/**
* 獲取相關調用棧的信息,並且打印相關日誌及代碼行數;
* <p>
* <p>
* 相關調用棧的信息,按照:類名,方法名,行號等,這樣的格式拼接,可以用來定位代碼行,
* 如:
* at cn.xx.ui.MainActivity.onCreate(MainActivity.java:23) 定位代碼行;
*
* @param tag
* @param content
* @param level 日誌級別;
* @param isLinked 是否輸出所有相關調用棧的信息;
*/
private static String logTraceInfo(String tag, String content, int level, boolean isLinked) {
StackTraceElement[] stes = Thread.currentThread().getStackTrace();
if (stes == null) {
Log.w(tag, "logTraceLinkInfo#return#stes == null");
return "";
}
StringBuilder result = null;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < stes.length; i++) {
StackTraceElement ste = stes[i];
if (ignorable(ste)) {
continue;
}
sb.append(content).append("[Thread:")
.append(Thread.currentThread().getName())
.append(", at ").append(ste.getClassName())
.append(".").append(ste.getMethodName())
.append("(").append(ste.getFileName())
.append(":").append(ste.getLineNumber())
.append(")]");
String info = sb.toString();
if (isLinked) {
if (result == null) {
result = new StringBuilder();
}
result.append(info).append("\n");
sb.delete(0, info.length());
logInfo(tag, level, info);
} else {
logInfo(tag, level, info);
return info;
}
}
return result.toString();
}
private static boolean ignorable(StackTraceElement ste) {
if (ste.isNativeMethod() ||
ste.getClassName().equals(Thread.class.getName()) ||
ste.getClassName().equals(Logger.class.getName())) {
return true;
}
return false;
}
private static void logInfo(String tag, int level, String info) {
switch (level) {
case Log.ERROR:
Log.e(tag, info);
break;
case Log.INFO:
Log.i(tag, info);
break;
case Log.VERBOSE:
Log.v(tag, info);
break;
case Log.WARN:
Log.w(tag, info);
break;
case Log.DEBUG:
default:
Log.d(tag, info);
break;
}
}
private static void cacheLogInfo(String info) {
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss-SSS");
String savePath = Environment.getExternalStorageDirectory().toString() + File.separator + "ForLog";
File saveFile = new File(savePath);
if (!saveFile.exists()) {
saveFile.mkdir();
}
File file = new File(saveFile, "log.txt");
info = dataFormat.format(new Date()) + ":" + info + "\n\n";
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file, true);
byte[] bytes = info.getBytes();
fos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
由於作者水平有限,語言描述及代碼實現中難免有紕漏,望各位看官多提寶貴意見!
Hello , World !
感謝所有!