补全日志调试函数
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
#Created by .winboll/winboll_app_build.gradle
|
||||
#Fri Nov 28 18:28:36 GMT 2025
|
||||
#Fri Nov 28 18:37:12 GMT 2025
|
||||
stageCount=2
|
||||
libraryProject=libappbase
|
||||
baseVersion=15.11
|
||||
publishVersion=15.11.1
|
||||
buildCount=25
|
||||
buildCount=28
|
||||
baseBetaVersion=15.11.2
|
||||
|
||||
@@ -4,9 +4,10 @@ package cc.winboll.studio.libappbase;
|
||||
* @Author ZhanGSKen@QQ.COM
|
||||
* @Date 2024/08/12 13:44:06
|
||||
* @Describe LogUtils
|
||||
* @Describe 应用日志类
|
||||
* @Describe 应用日志类(补全所有日志重载方法,适配不同调试场景)
|
||||
*/
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
import cc.winboll.studio.libappbase.GlobalApplication;
|
||||
import dalvik.system.DexFile;
|
||||
import java.io.BufferedReader;
|
||||
@@ -61,7 +62,7 @@ public class LogUtils {
|
||||
//
|
||||
public static void init(Context context, LOG_LEVEL logLevel) {
|
||||
if (GlobalApplication.isDebugging()) {
|
||||
// 初始化日志缓存文件路径
|
||||
// 初始化日志缓存文件路径(debug模式:外部存储)
|
||||
_mfLogCacheDir = new File(context.getApplicationContext().getExternalCacheDir(), TAG);
|
||||
if (!_mfLogCacheDir.exists()) {
|
||||
_mfLogCacheDir.mkdirs();
|
||||
@@ -75,7 +76,7 @@ public class LogUtils {
|
||||
}
|
||||
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
|
||||
} else {
|
||||
// 初始化日志缓存文件路径
|
||||
// 初始化日志缓存文件路径(release模式:内部存储)
|
||||
_mfLogCacheDir = new File(context.getApplicationContext().getCacheDir(), TAG);
|
||||
if (!_mfLogCacheDir.exists()) {
|
||||
_mfLogCacheDir.mkdirs();
|
||||
@@ -90,11 +91,6 @@ public class LogUtils {
|
||||
_mfLogUtilsBeanFile = new File(_mfLogDataDir, TAG + ".json");
|
||||
}
|
||||
|
||||
// Toast.makeText(context,
|
||||
// "_mfLogUtilsBeanFile : " + _mfLogUtilsBeanFile
|
||||
// + "\n_mfLogCatchFile : " + _mfLogCatchFile,
|
||||
// Toast.LENGTH_SHORT).show();
|
||||
//
|
||||
_mLogUtilsBean = LogUtilsBean.loadBeanFromFile(_mfLogUtilsBeanFile.getPath(), LogUtilsBean.class);
|
||||
if (_mLogUtilsBean == null) {
|
||||
_mLogUtilsBean = new LogUtilsBean();
|
||||
@@ -122,7 +118,6 @@ public class LogUtils {
|
||||
entry.setValue(beanSetting.getEnable());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,19 +130,14 @@ public class LogUtils {
|
||||
}
|
||||
|
||||
static void addClassTAGList() {
|
||||
//ClassLoader classLoader = getClass().getClassLoader();
|
||||
try {
|
||||
//String packageName = context.getPackageName();
|
||||
// 包名前缀(过滤当前应用的类)
|
||||
String packageNamePrefix = "cc.winboll.studio";
|
||||
List<String> classNames = new ArrayList<>();
|
||||
String apkPath = _mContext.getPackageCodePath();
|
||||
//Log.d("APK_PATH", "The APK path is: " + apkPath);
|
||||
LogUtils.d(TAG, String.format("apkPath : %s", apkPath));
|
||||
//String apkPath = "/data/app/" + packageName + "-";
|
||||
|
||||
//DexFile dexfile = new DexFile(apkPath + "1/base.apk");
|
||||
DexFile dexfile = new DexFile(apkPath);
|
||||
|
||||
int countTemp = 0;
|
||||
Enumeration<String> entries = dexfile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
@@ -165,23 +155,21 @@ public class LogUtils {
|
||||
Class<?> clazz = Class.forName(className);
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
if (Modifier.isStatic(field.getModifiers()) && Modifier.isPublic(field.getModifiers()) && field.getType() == String.class && "TAG".equals(field.getName())) {
|
||||
// 过滤静态、公共、String类型的 TAG 字段
|
||||
if (Modifier.isStatic(field.getModifiers())
|
||||
&& Modifier.isPublic(field.getModifiers())
|
||||
&& field.getType() == String.class
|
||||
&& "TAG".equals(field.getName())) {
|
||||
String tagValue = (String) field.get(null);
|
||||
//Log.d("TAG_INFO", "Class: " + className + ", TAG value: " + tagValue);
|
||||
//LogUtils.d(TAG, String.format("Tag Value : %s", tagValue));
|
||||
//mapTAGList.put(tagValue, true);
|
||||
mapTAGList.put(tagValue, false);
|
||||
mapTAGList.put(tagValue, false); // 默认禁用,可通过设置开启
|
||||
}
|
||||
}
|
||||
} catch (NoClassDefFoundError | ClassNotFoundException | IllegalAccessException e) {
|
||||
LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace());
|
||||
//LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
//Toast.makeText(context, TAG + " : " + e.getMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,7 +179,6 @@ public class LogUtils {
|
||||
Map.Entry<String, Boolean> entry = iterator.next();
|
||||
if (tag.equals(entry.getKey())) {
|
||||
entry.setValue(isEnable);
|
||||
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -204,7 +191,6 @@ public class LogUtils {
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, Boolean> entry = iterator.next();
|
||||
entry.setValue(isEnable);
|
||||
//System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
|
||||
}
|
||||
saveTAGBeanSettings();
|
||||
LogUtils.d(TAG, String.format("mapTAGList : %s", mapTAGList.toString()));
|
||||
@@ -223,10 +209,11 @@ public class LogUtils {
|
||||
if (!_IsInited) {
|
||||
return false;
|
||||
}
|
||||
if (mapTAGList.get(tag) == null
|
||||
|| !mapTAGList.get(tag)) {
|
||||
// TAG 未配置或禁用时,不打印日志
|
||||
if (mapTAGList.get(tag) == null || !mapTAGList.get(tag)) {
|
||||
return false;
|
||||
}
|
||||
// 日志级别不符合时,不打印日志
|
||||
if (!isInTheLevel(logLevel)) {
|
||||
return false;
|
||||
}
|
||||
@@ -234,8 +221,8 @@ public class LogUtils {
|
||||
}
|
||||
|
||||
static boolean isInTheLevel(LOG_LEVEL logLevel) {
|
||||
return (LogUtils._mLogUtilsBean.getLogLevel().ordinal() == logLevel.ordinal()
|
||||
|| LogUtils._mLogUtilsBean.getLogLevel().ordinal() > logLevel.ordinal());
|
||||
// 当前日志级别 >= 目标级别时,允许打印(级别顺序:Off < Error < Warn < Info < Debug < Verbose)
|
||||
return LogUtils._mLogUtilsBean.getLogLevel().ordinal() >= logLevel.ordinal();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -245,136 +232,501 @@ public class LogUtils {
|
||||
return _mfLogCacheDir;
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
//
|
||||
// ================================= 补全所有日志重载方法(Error 级别) =================================
|
||||
/**
|
||||
* Error 级别日志(仅消息)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void e(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, szMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
//
|
||||
/**
|
||||
* Error 级别日志(消息 + 异常)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param e 异常对象
|
||||
*/
|
||||
public static void e(String szTAG, String szMessage, Exception e) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error 级别日志(仅异常)
|
||||
* @param szTAG 标签
|
||||
* @param e 异常对象
|
||||
*/
|
||||
public static void e(String szTAG, Exception e) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
|
||||
String message = "【异常信息】: " + getExceptionInfo(e);
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error 级别日志(消息 + 异常 + 堆栈)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param e 异常对象
|
||||
* @param listStackTrace 堆栈信息
|
||||
*/
|
||||
public static void e(String szTAG, String szMessage, Exception e, StackTraceElement[] listStackTrace) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Error)) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
|
||||
sb.append("\n【堆栈信息】: ").append(getStackTraceInfo(listStackTrace));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Error, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 补全所有日志重载方法(Warn 级别) =================================
|
||||
/**
|
||||
* Warn 级别日志(仅消息)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void w(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, szMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
//
|
||||
/**
|
||||
* Warn 级别日志(消息 + 异常)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param e 异常对象
|
||||
*/
|
||||
public static void w(String szTAG, String szMessage, Exception e) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn 级别日志(仅异常)
|
||||
* @param szTAG 标签
|
||||
* @param e 异常对象
|
||||
*/
|
||||
public static void w(String szTAG, Exception e) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Warn)) {
|
||||
String message = "【异常信息】: " + getExceptionInfo(e);
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Warn, message);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 补全所有日志重载方法(Info 级别) =================================
|
||||
/**
|
||||
* Info 级别日志(仅消息)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void i(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) {
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Info, szMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
//
|
||||
/**
|
||||
* Info 级别日志(消息 + 数据对象)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param obj 数据对象(自动转为字符串)
|
||||
*/
|
||||
public static void i(String szTAG, String szMessage, Object obj) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Info)) {
|
||||
String objStr = obj == null ? "null" : obj.toString();
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【数据对象】: ").append(objStr);
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Info, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 补全所有日志重载方法(Debug 级别) =================================
|
||||
/**
|
||||
* Debug 级别日志(仅消息)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void d(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, szMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
// 包含线程调试堆栈信息
|
||||
//
|
||||
/**
|
||||
* Debug 级别日志(消息 + 堆栈)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param listStackTrace 堆栈信息
|
||||
*/
|
||||
public static void d(String szTAG, String szMessage, StackTraceElement[] listStackTrace) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
StringBuilder sbMessage = new StringBuilder(szMessage);
|
||||
sbMessage.append(" \nAt ");
|
||||
sbMessage.append(listStackTrace[2].getMethodName());
|
||||
sbMessage.append(" (");
|
||||
sbMessage.append(listStackTrace[2].getFileName());
|
||||
sbMessage.append(":");
|
||||
sbMessage.append(listStackTrace[2].getLineNumber());
|
||||
sbMessage.append(")");
|
||||
sbMessage.append("\n【调用堆栈】: ").append(getStackTraceInfo(listStackTrace));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
// 包含异常信息和线程调试堆栈信息
|
||||
//
|
||||
/**
|
||||
* Debug 级别日志(消息 + 异常)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param e 异常对象
|
||||
*/
|
||||
public static void d(String szTAG, String szMessage, Exception e) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【异常信息】: ").append(getExceptionInfo(e));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug 级别日志(异常 + 堆栈)
|
||||
* @param szTAG 标签
|
||||
* @param e 异常对象
|
||||
* @param listStackTrace 堆栈信息
|
||||
*/
|
||||
public static void d(String szTAG, Exception e, StackTraceElement[] listStackTrace) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
StringBuilder sbMessage = new StringBuilder(e.getClass().toGenericString());
|
||||
sbMessage.append(" : ");
|
||||
sbMessage.append(e.getMessage());
|
||||
sbMessage.append(" \nAt ");
|
||||
sbMessage.append(listStackTrace[2].getMethodName());
|
||||
sbMessage.append(" (");
|
||||
sbMessage.append(listStackTrace[2].getFileName());
|
||||
sbMessage.append(":");
|
||||
sbMessage.append(listStackTrace[2].getLineNumber());
|
||||
sbMessage.append(")");
|
||||
StringBuilder sbMessage = new StringBuilder();
|
||||
sbMessage.append("【异常信息】: ").append(getExceptionInfo(e));
|
||||
sbMessage.append("\n【调用堆栈】: ").append(getStackTraceInfo(listStackTrace));
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sbMessage.toString());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 调试日志写入函数
|
||||
//
|
||||
/**
|
||||
* Debug 级别日志(消息 + 数据对象)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param obj 数据对象(自动转为字符串)
|
||||
*/
|
||||
public static void d(String szTAG, String szMessage, Object obj) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
String objStr = obj == null ? "null" : obj.toString();
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【数据对象】: ").append(objStr);
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug 级别日志(仅数据对象)
|
||||
* @param szTAG 标签
|
||||
* @param obj 数据对象(自动转为字符串)
|
||||
*/
|
||||
public static void d(String szTAG, Object obj) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
String objStr = obj == null ? "null" : obj.toString();
|
||||
String message = "【数据对象】: " + objStr;
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, message);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 补全所有日志重载方法(Verbose 级别) =================================
|
||||
/**
|
||||
* Verbose 级别日志(仅消息)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void v(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, szMessage);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 日志文件保存函数
|
||||
//
|
||||
/**
|
||||
* Verbose 级别日志(消息 + 数据对象)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param obj 数据对象(自动转为字符串)
|
||||
*/
|
||||
public static void v(String szTAG, String szMessage, Object obj) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
|
||||
String objStr = obj == null ? "null" : obj.toString();
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【数据对象】: ").append(objStr);
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose 级别日志(仅数据对象)
|
||||
* @param szTAG 标签
|
||||
* @param obj 数据对象(自动转为字符串)
|
||||
*/
|
||||
public static void v(String szTAG, Object obj) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Verbose)) {
|
||||
String objStr = obj == null ? "null" : obj.toString();
|
||||
String message = "【数据对象】: " + objStr;
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Verbose, message);
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 新增:通用日志工具方法(补充调试能力) =================================
|
||||
/**
|
||||
* 打印当前线程信息(Debug 级别)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
public static void printThreadInfo(String szTAG, String szMessage) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug)) {
|
||||
Thread currentThread = Thread.currentThread();
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【线程信息】: ")
|
||||
.append("线程名=").append(currentThread.getName())
|
||||
.append(", 线程ID=").append(currentThread.getId())
|
||||
.append(", 线程状态=").append(currentThread.getState().name());
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印 Map 数据(Debug 级别,格式化输出,便于查看)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param map 要打印的 Map 数据
|
||||
*/
|
||||
public static <K, V> void printMap(String szTAG, String szMessage, Map<K, V> map) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug) && map != null) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【Map 数据】(size=").append(map.size()).append("):");
|
||||
for (Map.Entry<K, V> entry : map.entrySet()) {
|
||||
String keyStr = entry.getKey() == null ? "null" : entry.getKey().toString();
|
||||
String valueStr = entry.getValue() == null ? "null" : entry.getValue().toString();
|
||||
sb.append("\n ").append(keyStr).append(" = ").append(valueStr);
|
||||
}
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印 List 数据(Debug 级别,格式化输出)
|
||||
* @param szTAG 标签
|
||||
* @param szMessage 日志消息
|
||||
* @param list 要打印的 List 数据
|
||||
*/
|
||||
public static <T> void printList(String szTAG, String szMessage, List<T> list) {
|
||||
if (isLoggable(szTAG, LogUtils.LOG_LEVEL.Debug) && list != null) {
|
||||
StringBuilder sb = new StringBuilder(szMessage);
|
||||
sb.append("\n【List 数据】(size=").append(list.size()).append("):");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
T item = list.get(i);
|
||||
String itemStr = item == null ? "null" : item.toString();
|
||||
sb.append("\n 索引").append(i).append(" = ").append(itemStr);
|
||||
}
|
||||
saveLog(szTAG, LogUtils.LOG_LEVEL.Debug, sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// ================================= 私有工具方法(异常/堆栈信息格式化) =================================
|
||||
/**
|
||||
* 格式化异常信息(提取异常类型、消息、简化堆栈)
|
||||
* @param e 异常对象
|
||||
* @return 格式化后的异常字符串
|
||||
*/
|
||||
private static String getExceptionInfo(Exception e) {
|
||||
if (e == null) {
|
||||
return "异常对象为null";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 异常类型 + 异常消息
|
||||
sb.append(e.getClass().getSimpleName()).append(" : ").append(e.getMessage() == null ? "无异常消息" : e.getMessage());
|
||||
// 简化堆栈(取前5行,避免日志过长)
|
||||
StackTraceElement[] stackTrace = e.getStackTrace();
|
||||
if (stackTrace != null && stackTrace.length > 0) {
|
||||
sb.append("\n 简化堆栈(前5行):");
|
||||
int limit = Math.min(stackTrace.length, 5);
|
||||
for (int i = 0; i < limit; i++) {
|
||||
sb.append("\n ").append(stackTrace[i].toString());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化堆栈信息(提取关键调用链路)
|
||||
* @param stackTrace 堆栈数组
|
||||
* @return 格式化后的堆栈字符串
|
||||
*/
|
||||
private static String getStackTraceInfo(StackTraceElement[] stackTrace) {
|
||||
if (stackTrace == null || stackTrace.length == 0) {
|
||||
return "堆栈信息为空";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 过滤 LogUtils 内部调用,取真实业务调用链路(前8行)
|
||||
int count = 0;
|
||||
for (StackTraceElement element : stackTrace) {
|
||||
// 跳过 LogUtils 自身的堆栈(避免冗余)
|
||||
if (element.getClassName().contains("cc.winboll.studio.libappbase.LogUtils")) {
|
||||
continue;
|
||||
}
|
||||
sb.append("\n ").append(element.getClassName()).append(".")
|
||||
.append(element.getMethodName()).append("(")
|
||||
.append(element.getFileName()).append(":").append(element.getLineNumber()).append(")");
|
||||
count++;
|
||||
if (count >= 8) { // 限制堆栈长度,避免日志过大
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// ================================= 原有核心方法(保留并优化) =================================
|
||||
/**
|
||||
* 日志文件保存函数(优化:增加异常捕获完整性,避免流泄漏)
|
||||
* @param szTAG 标签
|
||||
* @param logLevel 日志级别
|
||||
* @param szMessage 日志消息
|
||||
*/
|
||||
static void saveLog(String szTAG, LogUtils.LOG_LEVEL logLevel, String szMessage) {
|
||||
BufferedWriter out = null;
|
||||
try {
|
||||
BufferedWriter out = null;
|
||||
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(_mfLogCatchFile, true), "UTF-8"));
|
||||
out.write("[" + logLevel + "] " + mSimpleDateFormat.format(System.currentTimeMillis()) + " [" + szTAG + "]\n" + szMessage + "\n");
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, "IOException : " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 历史日志加载函数
|
||||
//
|
||||
public static String loadLog() {
|
||||
if (_mfLogCatchFile.exists()) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
try {
|
||||
BufferedReader in = null;
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(_mfLogCatchFile), "UTF-8"));
|
||||
String line = "";
|
||||
while ((line = in.readLine()) != null) {
|
||||
sb.append(line);
|
||||
sb.append("\n");
|
||||
// 确保日志文件存在(创建父目录 + 文件)
|
||||
if (!_mfLogCatchFile.exists()) {
|
||||
File parentDir = _mfLogCatchFile.getParentFile();
|
||||
if (parentDir != null && !parentDir.exists()) {
|
||||
parentDir.mkdirs();
|
||||
}
|
||||
_mfLogCatchFile.createNewFile();
|
||||
}
|
||||
// 追加写入日志(UTF-8编码,避免中文乱码)
|
||||
out = new BufferedWriter(new OutputStreamWriter(
|
||||
new FileOutputStream(_mfLogCatchFile, true), "UTF-8"));
|
||||
String logLine = "[" + logLevel + "] "
|
||||
+ mSimpleDateFormat.format(System.currentTimeMillis())
|
||||
+ " [" + szTAG + "]\n"
|
||||
+ szMessage + "\n\n"; // 增加空行,区分不同日志
|
||||
out.write(logLine);
|
||||
out.flush(); // 强制刷新,确保日志及时写入
|
||||
} catch (IOException e) {
|
||||
// 日志写入失败时,打印系统日志(避免递归调用)
|
||||
android.util.Log.e(TAG, "日志写入失败: " + e.getMessage());
|
||||
} finally {
|
||||
// 关闭流,避免资源泄漏(Java 7 手动关闭,无 try-with-resources)
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
android.util.Log.e(TAG, "流关闭失败: " + e.getMessage());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, "IOException : " + e.getMessage());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//
|
||||
// 清理日志函数
|
||||
//
|
||||
public static void cleanLog() {
|
||||
if (_mfLogCatchFile.exists()) {
|
||||
try {
|
||||
UTF8FileUtils.writeStringToFile(_mfLogCatchFile.getPath(), "");
|
||||
//LogUtils.d(TAG, "cleanLog");
|
||||
} catch (IOException e) {
|
||||
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 历史日志加载函数(优化:增加流关闭,避免内存泄漏)
|
||||
* @return 日志内容字符串(空串表示无日志)
|
||||
*/
|
||||
public static String loadLog() {
|
||||
if (_mfLogCatchFile == null || !_mfLogCatchFile.exists()) {
|
||||
return "日志文件不存在";
|
||||
}
|
||||
StringBuffer sb = new StringBuffer();
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(
|
||||
new FileInputStream(_mfLogCatchFile), "UTF-8"));
|
||||
String line = "";
|
||||
while ((line = in.readLine()) != null) {
|
||||
sb.append(line);
|
||||
sb.append("\n");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
sb.append("日志加载失败: ").append(e.getMessage());
|
||||
LogUtils.e(TAG, "日志加载异常", e);
|
||||
} finally {
|
||||
// 关闭流,避免资源泄漏
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "流关闭异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理日志函数(优化:支持清空日志,避免文件过大)
|
||||
*/
|
||||
public static void cleanLog() {
|
||||
if (_mfLogCatchFile == null) {
|
||||
LogUtils.d(TAG, "日志文件未初始化,无需清理");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// 清空文件内容(覆盖写入空字符串)
|
||||
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
|
||||
new FileOutputStream(_mfLogCatchFile, false), "UTF-8"));
|
||||
out.write("");
|
||||
out.flush();
|
||||
out.close();
|
||||
LogUtils.d(TAG, "日志已清空,文件路径: " + _mfLogCatchFile.getPath());
|
||||
} catch (IOException e) {
|
||||
LogUtils.e(TAG, "日志清空失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查日志文件大小(新增:避免日志文件过大占用内存)
|
||||
* @param maxSizeMB 最大允许大小(MB)
|
||||
* @return true:文件超过限制;false:文件大小正常
|
||||
*/
|
||||
public static boolean checkLogFileSize(int maxSizeMB) {
|
||||
if (_mfLogCatchFile == null || !_mfLogCatchFile.exists()) {
|
||||
return false;
|
||||
}
|
||||
// 转换为字节(1MB = 1024*1024 字节)
|
||||
long maxSizeByte = maxSizeMB * 1024 * 1024;
|
||||
long fileSize = _mfLogCatchFile.length();
|
||||
LogUtils.d(TAG, String.format("日志文件大小: %.2f MB(限制: %d MB)",
|
||||
fileSize / (1024.0 * 1024), maxSizeMB));
|
||||
return fileSize > maxSizeByte;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化检查(新增:快速判断 LogUtils 是否初始化完成)
|
||||
* @return true:已初始化;false:未初始化
|
||||
*/
|
||||
public static boolean isInited() {
|
||||
return _IsInited;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示短提示(新增:日志+Toast联动,调试时快速提示)
|
||||
* @param context 上下文
|
||||
* @param message 提示内容
|
||||
*/
|
||||
public static void showShortToast(final Context context, final String message) {
|
||||
if (context == null || message == null) {
|
||||
return;
|
||||
}
|
||||
// 主线程显示Toast,避免子线程崩溃
|
||||
if (Thread.currentThread().getId() == android.os.Process.myTid()) {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
((android.app.Activity) context).runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
// 同时写入日志
|
||||
LogUtils.d(TAG, "Toast提示: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user