今天在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 選項開關,正常情況下還是關閉爲好。
在未找到更合適的方法前, 不失爲解決問題的一種方案。