简易版本的处理 Log 日志工具类,可以快速定位到出现问题的类和方法。
一、案例代码实现
第01节 java代码
java
import android.util.Log;
import androidx.annotation.Nullable;
/****
*
* @apiNote 日志工具类
*/
public class CommonLogUtil {
public static final int LEVEL_OPEN = 1; // 开启
public static final int LEVEL_VERBOSE = 2; // 冗长
public static final int LEVEL_DEBUG = 3; // 调试
public static final int LEVEL_INFO = 4; // 信息
public static final int LEVEL_WARN = 5; // 警告
public static final int LEVEL_ERROR = 6; // 错误
public static final int LEVEL_CLOSE = 7; // 关闭
private static final int HEAD_NONE = 0; // 没有头部信息
private static final int HEAD_VERSION = 1; // 只有版本信息
private static final int HEAD_VERSION_CLASS = 2; // 只有版本和类信息
private static final int HEAD_VERSION_METHOD = 3; // 只有版本和类方法信息
private static final int HEAD_ALL = 4; // 完整的头部信息
// 初始化默认的 TAG
private static final String FIX_TAG = "cosmo";
// 获取当前调用栈的索引
private static final int STACK_INDEX = 3;
// 开启头信息
private static final boolean isOpenHead = true;
// 初始化默认的等级
private static final int currentLevel = LEVEL_OPEN;
// 初始化默认的头信息
private static final int currentHead = HEAD_ALL;
public static void v(String TAG, String message) {
if (currentLevel > LEVEL_VERBOSE) {
return;
}
if (isOpenHead) {
message = formatLogHead() + message;
}
Log.v(TAG, message);
}
public static void v(String message) {
v(FIX_TAG, message);
}
public static void d(String TAG, String message) {
if (currentLevel > LEVEL_DEBUG) {
return;
}
if (isOpenHead) {
message = formatLogHead() + message;
}
Log.d(TAG, message);
}
public static void d(String message) {
d(FIX_TAG, message);
}
public static void i(String TAG, String message) {
if (currentLevel > LEVEL_INFO) {
return;
}
if (isOpenHead) {
message = formatLogHead() + message;
}
Log.i(TAG, message);
}
public static void i(String message) {
i(FIX_TAG, message);
}
public static void w(String TAG, String message) {
if (currentLevel > LEVEL_WARN) {
return;
}
if (isOpenHead) {
message = formatLogHead() + message;
}
Log.w(TAG, message);
}
public static void w(String message) {
w(FIX_TAG, message);
}
public static void e(String TAG, String message) {
if (currentLevel > LEVEL_ERROR) {
return;
}
if (isOpenHead) {
message = formatLogHead() + message;
}
Log.e(TAG, message);
}
public static void e(String message) {
e(FIX_TAG, message);
}
public static String appBuildContent() {
return FIX_TAG + "." + BuildConfig.VERSION_TIME;
}
/**
* 格式化日志头部信息
* 该方法通过获取当前调用栈来动态生成包含类名、行号和方法名的日志头部信息
* 根据调用者是Java类还是Kotlin类来选择不同的格式
*
* @return 格式化的日志头部字符串,格式为 "[构建信息][类名.扩展名:行号][方法名]: "
*/
private static String formatLogHead() {
String result = "";
switch (currentHead) {
case HEAD_VERSION:
result = getHeadVersion(result);
break;
case HEAD_VERSION_CLASS:
result = getHeadVersionAndClass(result);
break;
case HEAD_VERSION_METHOD:
result = getHeadAndMethodName(result);
break;
case HEAD_ALL:
result = getHeadAll(result);
break;
}
if (result == null) {
return "[UNKNOWN]";
}
return result;
}
/**
* 获取版本信息
* 该方法通过获取当前调用栈来动态生成包含构建信息的日志头部信息
*
* @return 包含构建信息的日志头部字符串,格式为 "[构建信息]: "
*/
@Nullable
private static String getHeadVersion(String result) {
try {
String pattern = "[%s]: ";
result = String.format(pattern, appBuildContent());
} catch (Exception exception) {
Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
}
return result;
}
/**
* 获取版本和类信息
* 该方法通过获取当前调用栈来动态生成包含构建信息和类名的日志头部信息
*
* @return 包含构建信息和类名的日志头部字符串,格式为 "[构建信息][类名.java:行号]: "
*/
@Nullable
private static String getHeadVersionAndClass(String result) {
try {
String pattern;
String patternJava = "[%s][%s.java:%d]: ";
String patternKotlin = "[%s][%s.kt:%d]: ";
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
int targetIndex = 0;
for (int i = 0; i < stackTrace.length; i++) {
if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
targetIndex = i;
break;
}
}
targetIndex += STACK_INDEX;
if (targetIndex >= stackTrace.length) {
return null;
}
StackTraceElement targetElement = stackTrace[targetIndex];
// 判断是否是 kotlin 类
if (isKotlinClass(targetElement)) {
pattern = patternKotlin;
} else {
pattern = patternJava;
}
String[] classNameInfo = targetElement.getClassName().split("\\.");
String className = classNameInfo[classNameInfo.length - 1];
className = className.contains("$") ? className.split("\\$")[0] : className;
int lineNumber = targetElement.getLineNumber();
result = String.format(pattern, appBuildContent(), className, lineNumber);
} catch (Exception exception) {
Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
}
return result;
}
/**
* 获取类名和方法名信息
* 该方法通过获取当前调用栈来动态生成包含类名和方法名的日志头部信息
*
* @return 包含类名和方法名的日志头部字符串,格式为 "[构建信息][类名.java:行号][方法名]: "
*/
@Nullable
private static String getHeadAndMethodName(String result) {
try {
String pattern;
String patternJava = "[%s][%s]: ";
String patternKotlin = "[%s][%s]: ";
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
int targetIndex = 0;
for (int i = 0; i < stackTrace.length; i++) {
if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
targetIndex = i;
break;
}
}
targetIndex += STACK_INDEX;
if (targetIndex >= stackTrace.length) {
return null;
}
StackTraceElement targetElement = stackTrace[targetIndex];
// 判断是否是 kotlin 类
if (isKotlinClass(targetElement)) {
pattern = patternKotlin;
} else {
pattern = patternJava;
}
String methodName = targetElement.getMethodName();
String[] methodArray = methodName.split("\\$");
methodName = methodName.contains("$") ? methodArray[methodArray.length - 1] : methodName;
result = String.format(pattern, appBuildContent(), methodName);
} catch (Exception exception) {
Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
}
return result;
}
/**
* 获取完整的日志头部信息
* 该方法通过获取当前调用栈来动态生成包含类名、行号和方法名的日志头部信息
*
* @return 完整的日志头部字符串,格式为 "[构建信息][类名.java:行号][方法名]: "
*/
@Nullable
private static String getHeadAll(String result) {
try {
String pattern;
String patternJava = "[%s][%s.java:%d][%s]: ";
String patternKotlin = "[%s][%s.kt:%d][%s]: ";
StackTraceElement[] stackTrace = new Throwable().getStackTrace();
int targetIndex = 0;
for (int i = 0; i < stackTrace.length; i++) {
if (!stackTrace[i].getMethodName().equals("formatLogHead")) {
targetIndex = i;
break;
}
}
targetIndex += STACK_INDEX;
if (targetIndex >= stackTrace.length) {
return null;
}
StackTraceElement targetElement = stackTrace[targetIndex];
// 判断是否是 kotlin 类
if (isKotlinClass(targetElement)) {
pattern = patternKotlin;
} else {
pattern = patternJava;
}
String[] classNameInfo = targetElement.getClassName().split("\\.");
String className = classNameInfo[classNameInfo.length - 1];
className = className.contains("$") ? className.split("\\$")[0] : className;
int lineNumber = targetElement.getLineNumber();
String methodName = targetElement.getMethodName();
String[] methodArray = methodName.split("\\$");
methodName = methodName.contains("$") ? methodArray[methodArray.length - 1] : methodName;
result = String.format(pattern, appBuildContent(), className, lineNumber, methodName);
} catch (Exception exception) {
Log.e(FIX_TAG, "CommonLogUtil.formatLogHead...exception: " + exception);
}
return result;
}
/**
* 判断指定的堆栈元素是否为Kotlin类
* 通过检查类上是否存在Kotlin元数据注解来判断
*
* @param element 要检查的堆栈跟踪元素
* @return 如果是Kotlin类返回true,否则返回false
*/
private static boolean isKotlinClass(StackTraceElement element) {
try {
Class<?> clazz = Class.forName(element.getClassName());
return clazz.getAnnotation(kotlin.Metadata.class) != null;
} catch (ClassNotFoundException e) {
return false;
}
}
}
第02节 groovy语法
groovy
static def buildSimpleTime() {
def df = new SimpleDateFormat("yyyy-MMdd-HHmm")
df.setTimeZone(TimeZone.getTimeZone("GMT+8:00"))
return df.format(new Date())
}
android {
buildTypes {
release {
buildConfigField "String", "VERSION_TIME", "\"${buildSimpleTime()}\""
}
debug {
buildConfigField "String", "VERSION_TIME", "\"${buildSimpleTime()}\""
}
}
}