控制Log
像Java一樣,本地的loggingAPIs僅僅讓你發(fā)出log消息到logger內(nèi)核模塊
。在實際中,你可能既不使用斷言也不使用日志在同樣在你發(fā)布和debug建立
時。不幸的是,這個Android日志API并不提供任何壓縮日志消息的能力
基于他們的優(yōu)先級。它并不和Log4J或者Log4CXX一樣先進的。這個Andoid
的日志框架假定你能夠去除你不需要的日志信息。盡管這能很容易的被做
在Java應(yīng)用程序中依賴Proguard,但是在本地代碼中是不容易的。
? ?日志的封裝:
? 這部分將介紹一個基于這個問題的解決方案的一個預(yù)處理器。為了看到
效果,需要修改這個hello-jni本地項目。jni-》右鍵-》new file-》
my_log.h.
#pragma once
/**
* Basic logging framework for NDK.
*
* @author Onur Cinar
*/
#include <android/log.h>
#define MY_LOG_LEVEL_VERBOSE 1
#define MY_LOG_LEVEL_DEBUG 2
#define MY_LOG_LEVEL_INFO 3
#define MY_LOG_LEVEL_WARNING 4
#define MY_LOG_LEVEL_ERROR 5
#define MY_LOG_LEVEL_FATAL 6
#define MY_LOG_LEVEL_SILENT 7
#ifndef MY_LOG_TAG
# define MY_LOG_TAG __FILE__
#endif
#ifndef MY_LOG_LEVEL
# define MY_LOG_LEVEL MY_LOG_LEVEL_VERBOSE
#endif
#define MY_LOG_NOOP (void) 0
#define MY_LOG_PRINT(level,fmt,...) \
__android_log_print(level, MY_LOG_TAG, "(%s:%u) %s: " fmt, \
__FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#if MY_LOG_LEVEL_VERBOSE >= MY_LOG_LEVEL
# define MY_LOG_VERBOSE(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_VERBOSE, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_VERBOSE(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_DEBUG >= MY_LOG_LEVEL
# define MY_LOG_DEBUG(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_DEBUG, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_DEBUG(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_INFO >= MY_LOG_LEVEL
# define MY_LOG_INFO(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_INFO, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_INFO(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_WARNING >= MY_LOG_LEVEL
# define MY_LOG_WARNING(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_WARN, fmt, ##__VA_ARGS__)
MY_LOG_PRINT(ANDROID_LOG_ERROR, fmt, ##__VA_ARGS__)
# define MY_LOG_FATAL(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_FATAL, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_FATAL(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_FATAL >= MY_LOG_LEVEL
# define MY_LOG_ASSERT(expression, fmt, ...) \
if (!(expression)) \
{ \
__android_log_assert(#expression, MY_LOG_TAG, \
fmt, ##__VA_ARGS__); \
}
#else
# define MY_LOG_ASSERT(...) MY_LOG_NOOP
#endif
通過這一套預(yù)處理命令,這個my_log.h頭文件定義了一個基本的logging
框架對于本地代碼。這些預(yù)處理命令封裝了android日志函數(shù)和運行他們
在編譯時被調(diào)試。
增加日志:
? ?你能夠增加日志語句在本地代碼。使用Project Explorer,在hello-jni.c
點擊右鍵,編輯。為了使用基本的日志框架,這個my_log.h頭文件需要被包含。
不在需要包含android/log.h,因為已經(jīng)通過my_log.h被包含。
? ?#include"my_log.h"
? ?你能增加這日志語句到本地函數(shù),如下:
? ?jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
MY_LOG_VERBOSE("The stringFromJNI is called.");
MY_LOG_DEBUG("env=%p thiz=%p", env, thiz);
MY_LOG_ASSERT(0 != env, "JNIEnv cannot be NULL.");
MY_LOG_INFO("Returning a new string.");
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
更新Android.mk
你可以更新這個Android.mk文件來調(diào)節(jié)這個基本日志框架。編輯Android.mk
日志標(biāo)簽:
? 上面提到,每個日志消息包含了一個日志標(biāo)簽來識別這組件,發(fā)出日志
消息。這個對于模塊的日志標(biāo)簽被定義在Android.mk文件,如下:
? LOCAL_MODULE := hello-jni
? ...
? # Define the log tag
? MY_LOG_TAG := \"hello-jni\"
日志水平:
? ? 基本的日志框架的主要優(yōu)勢是能夠定義一個日志水平.
這Android.mk文件被修改來定義不同的日志水平來調(diào)試和發(fā)布建立,如下:
? ? ?LOCAL_MODULE := hello-jni
...
# Define the log tag
MY_LOG_TAG := \"hello-jni\"
MY_LOG_LEVEL := MY_LOG_LEVEL_ERROR
MY_LOG_LEVEL := MY_LOG_LEVEL_VERBOSE
應(yīng)用這日志配置:
基于定義的MY_LOG_TAG和MY_LOG_LEVEL建立系統(tǒng)變量,這日志
系統(tǒng)配置被應(yīng)用在這模塊,如下:
? LOCAL_MODULE := hello-jni
...
# Define the log tag
MY_LOG_TAG := hello-jni
# Define the default logging level based build type
ifeq ($(APP_OPTIM),release)
MY_LOG_LEVEL := MY_LOG_LEVEL_ERROR
else
MY_LOG_LEVEL := MY_LOG_LEVEL_VERBOSE
endif
# Appending the compiler flags
LOCAL_CFLAGS += ?DMY_LOG_TAG=$(MY_LOG_TAG)
LOCAL_CFLAGS += ?DMY_LOG_LEVEL=$(MY_LOG_LEVEL)
# Dynamically linking with the log library
LOCAL_LDLIBS += ?llog
運行項目觀察。
控制臺日志:
? ?當(dāng)整合第三方的了類庫和(legacy)模塊到Android應(yīng)用程序項目,
改變他們的日志機制到Android-specific可能是不可能的。大部分
日志機制發(fā)出日志信息到一個文件或者直接到這控制臺。
? ? 這控制臺描述符,STDOUT和STDERR,默認(rèn)情況下在Android平臺
是不可見的。為重定位這些日志小到這Android系統(tǒng)日志,打開一個
命令窗口來執(zhí)行ADB命令,如下:
? ?adb shell stop
? ?adb shell setprop log.redirect-stdio true
? ?adb shell start
。在實際中,你可能既不使用斷言也不使用日志在同樣在你發(fā)布和debug建立
時。不幸的是,這個Android日志API并不提供任何壓縮日志消息的能力
基于他們的優(yōu)先級。它并不和Log4J或者Log4CXX一樣先進的。這個Andoid
的日志框架假定你能夠去除你不需要的日志信息。盡管這能很容易的被做
在Java應(yīng)用程序中依賴Proguard,但是在本地代碼中是不容易的。
? ?日志的封裝:
? 這部分將介紹一個基于這個問題的解決方案的一個預(yù)處理器。為了看到
效果,需要修改這個hello-jni本地項目。jni-》右鍵-》new file-》
my_log.h.
#pragma once
/**
* Basic logging framework for NDK.
*
* @author Onur Cinar
*/
#include <android/log.h>
#define MY_LOG_LEVEL_VERBOSE 1
#define MY_LOG_LEVEL_DEBUG 2
#define MY_LOG_LEVEL_INFO 3
#define MY_LOG_LEVEL_WARNING 4
#define MY_LOG_LEVEL_ERROR 5
#define MY_LOG_LEVEL_FATAL 6
#define MY_LOG_LEVEL_SILENT 7
#ifndef MY_LOG_TAG
# define MY_LOG_TAG __FILE__
#endif
#ifndef MY_LOG_LEVEL
# define MY_LOG_LEVEL MY_LOG_LEVEL_VERBOSE
#endif
#define MY_LOG_NOOP (void) 0
#define MY_LOG_PRINT(level,fmt,...) \
__android_log_print(level, MY_LOG_TAG, "(%s:%u) %s: " fmt, \
__FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#if MY_LOG_LEVEL_VERBOSE >= MY_LOG_LEVEL
# define MY_LOG_VERBOSE(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_VERBOSE, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_VERBOSE(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_DEBUG >= MY_LOG_LEVEL
# define MY_LOG_DEBUG(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_DEBUG, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_DEBUG(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_INFO >= MY_LOG_LEVEL
# define MY_LOG_INFO(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_INFO, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_INFO(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_WARNING >= MY_LOG_LEVEL
# define MY_LOG_WARNING(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_WARN, fmt, ##__VA_ARGS__)
MY_LOG_PRINT(ANDROID_LOG_ERROR, fmt, ##__VA_ARGS__)
# define MY_LOG_FATAL(fmt,...) \
MY_LOG_PRINT(ANDROID_LOG_FATAL, fmt, ##__VA_ARGS__)
#else
# define MY_LOG_FATAL(...) MY_LOG_NOOP
#endif
#if MY_LOG_LEVEL_FATAL >= MY_LOG_LEVEL
# define MY_LOG_ASSERT(expression, fmt, ...) \
if (!(expression)) \
{ \
__android_log_assert(#expression, MY_LOG_TAG, \
fmt, ##__VA_ARGS__); \
}
#else
# define MY_LOG_ASSERT(...) MY_LOG_NOOP
#endif
通過這一套預(yù)處理命令,這個my_log.h頭文件定義了一個基本的logging
框架對于本地代碼。這些預(yù)處理命令封裝了android日志函數(shù)和運行他們
在編譯時被調(diào)試。
增加日志:
? ?你能夠增加日志語句在本地代碼。使用Project Explorer,在hello-jni.c
點擊右鍵,編輯。為了使用基本的日志框架,這個my_log.h頭文件需要被包含。
不在需要包含android/log.h,因為已經(jīng)通過my_log.h被包含。
? ?#include"my_log.h"
? ?你能增加這日志語句到本地函數(shù),如下:
? ?jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
MY_LOG_VERBOSE("The stringFromJNI is called.");
MY_LOG_DEBUG("env=%p thiz=%p", env, thiz);
MY_LOG_ASSERT(0 != env, "JNIEnv cannot be NULL.");
MY_LOG_INFO("Returning a new string.");
return (*env)->NewStringUTF(env, "Hello from JNI !");
}
更新Android.mk
你可以更新這個Android.mk文件來調(diào)節(jié)這個基本日志框架。編輯Android.mk
日志標(biāo)簽:
? 上面提到,每個日志消息包含了一個日志標(biāo)簽來識別這組件,發(fā)出日志
消息。這個對于模塊的日志標(biāo)簽被定義在Android.mk文件,如下:
? LOCAL_MODULE := hello-jni
? ...
? # Define the log tag
? MY_LOG_TAG := \"hello-jni\"
日志水平:
? ? 基本的日志框架的主要優(yōu)勢是能夠定義一個日志水平.
這Android.mk文件被修改來定義不同的日志水平來調(diào)試和發(fā)布建立,如下:
? ? ?LOCAL_MODULE := hello-jni
...
# Define the log tag
MY_LOG_TAG := \"hello-jni\"
MY_LOG_LEVEL := MY_LOG_LEVEL_ERROR
MY_LOG_LEVEL := MY_LOG_LEVEL_VERBOSE
應(yīng)用這日志配置:
基于定義的MY_LOG_TAG和MY_LOG_LEVEL建立系統(tǒng)變量,這日志
系統(tǒng)配置被應(yīng)用在這模塊,如下:
? LOCAL_MODULE := hello-jni
...
# Define the log tag
MY_LOG_TAG := hello-jni
# Define the default logging level based build type
ifeq ($(APP_OPTIM),release)
MY_LOG_LEVEL := MY_LOG_LEVEL_ERROR
else
MY_LOG_LEVEL := MY_LOG_LEVEL_VERBOSE
endif
# Appending the compiler flags
LOCAL_CFLAGS += ?DMY_LOG_TAG=$(MY_LOG_TAG)
LOCAL_CFLAGS += ?DMY_LOG_LEVEL=$(MY_LOG_LEVEL)
# Dynamically linking with the log library
LOCAL_LDLIBS += ?llog
運行項目觀察。
控制臺日志:
? ?當(dāng)整合第三方的了類庫和(legacy)模塊到Android應(yīng)用程序項目,
改變他們的日志機制到Android-specific可能是不可能的。大部分
日志機制發(fā)出日志信息到一個文件或者直接到這控制臺。
? ? 這控制臺描述符,STDOUT和STDERR,默認(rèn)情況下在Android平臺
是不可見的。為重定位這些日志小到這Android系統(tǒng)日志,打開一個
命令窗口來執(zhí)行ADB命令,如下:
? ?adb shell stop
? ?adb shell setprop log.redirect-stdio true
? ?adb shell start
總結(jié)