今天在Android 开发中Java 调用Native C++实现的 SDK 库log 模块功能时遇到一个问题:Native 代码本身使用LINE, FILE等C++ 宏可以精确定位log 记录位置信息, 但Java 调用处却无法正确体现具体文件、行数等信息,转化为Native log 实现体的信息。于是就准备用Java 封装一层Native log 代码, 实现增加FILE,LINE,FUNCTION等基本信息。那么问题来了:Java 如何实现获取log 发生处的位置信息?
鉴于之前用过著名的log4j 开源库, 既然开源,看看源代码又何妨?! 基本了解了log4j 实现原理: 通过创建一个Throwable 对象, 获取堆栈信息,进一步提取堆栈信息确定log发生的FILE,LINE,FUNCTION , 于是产生了对Native 代码的封装的log:
public final class NLogger {
private static INLogger s_logger = null;
private static boolean debug = false; //NOTICE: debug mode will decrease performance.
static {
if(s_logger ==null)
s_logger = XXX.getNativeLogger(); //获取Native log 实例
}
public staticvoid enableDebug(){
debug = true;
}
public staticvoid disableDebug(){
debug = false;
}
public static void info(String msg){
if(s_logger != null){
if(debug){
StackTraceElement traceElement = (new Throwable()).getStackTrace()[1];
s_logger.info(traceElement.getFileName() +":" + traceElement.getLineNumber() + " " + traceElement.getMethodName() +" " + msg);
}
else{
s_logger.info(msg);
}
}
}
public static void warn(String msg){
if(s_logger != null){
if(debug){
StackTraceElement traceElement = (new Throwable()).getStackTrace()[1];
s_logger.warning(traceElement.getFileName() +":" + traceElement.getLineNumber() + " " + traceElement.getMethodName() +" " + msg);
}
else {
s_logger.warning(msg);
}
}
}
public static void error(String msg){
if(s_logger !=null){
if(debug) {
StackTraceElement traceElement = (new Throwable()).getStackTrace()[1];
s_logger.error(traceElement.getFileName() +":" + traceElement.getLineNumber() + " " + traceElement.getMethodName() +" " + msg);
}
else {
s_logger.error(msg);
}
}
}
}
请注意: 该方法虽然解决了问题, 对于长期写C++代码的人员, 不免觉得效率低下,每条log 都要额外创建一个Throwable对象, 因此log 封装时增加debug 选项开关,正常情况下还是关闭为好。
在未找到更合适的方法前, 不失为解决问题的一种方案。