日志
开发者不希望直接与logger内核模块进行交互,Android运行库提供了API调用一边Java和native向logger内核发送日志信息。native通过包含该头文件:
#include "android/log.h"除了添加头文件,还需要在Android,mk中添加库
..
LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog...include $(BUILD_SHARED_LIBRARY)
支持日志的优先级
typedef enum android_LogPriority { ... ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ... } android_LogPriority;
日志函数
__android_log_write(ANDROID_LOG_WARN, "hello-jni", "warning log."); //生成简单的日志信息 __android_log_print(ANDROID_LOG_ERROR, "hello-jni", "Failed with error %s", "NullPointerException"); //生成格式化的日志信息 log_verbose("my name is %s, age %d", "eric", 27); //传递多个参数生产的日志信息,跟__android_log_print功能大致一样
void log_verbose(const char* format,...) { va_list args; va_start(args, format); __android_log_vprint(ANDROID_LOG_VERBOSE, "hello-jni", format, args); va_end(args); }
控制台日志打印结果:
自定义日志管理类
// // Created by liangjiangli on 2017/9/29. // NDK基本日志框架 // #include <android/log.h> /*定义日志优先级*/ #define LOG_LEVEL_VERBOSE 1 #define LOG_LEVEL_DEBUG 2 #define LOG_LEVEL_INFO 3 #define LOG_LEVEL_WARNING 4 #define MLOG_LEVEL_ERROR 5 #define LOG_LEVEL_FATAL 6 #define LOG_LEVEL_SILENT 7 #ifndef LOG_TAG #define LOG_TAG __FILE__ #endif #ifndef LOG_LEVEL #define LOG_LEVEL LOG_LEVEL_VERBOSE #endif #define LOG_NOOP (void) 0 #define LOG_PRINT(level,fmt,...) __android_log_print(level,LOG_TAG,"(%s:%u) %s: " fmt, __FILE__, __LINE__, __PRETTY_FUNCTION__, ##__VA_ARGS__) #if LOG_LEVEL_VERBOSE >= LOG_LEVEL #define LOG_VERBOSE(fmt,...) LOG_PRINT(ANDROID_LOG_VERBOSE,fmt,##__VA_ARGS__) #else #define LOG_VERBOSE(...) LOG_NOOP #endif #if LOG_LEVEL_DEBUG >= LOG_LEVEL #define LOG_DEBUG(fmt,...) LOG_PRINT(ANDROID_LOG_DEBUG,fmt,##__VA_ARGS__) #else #define LOG_DEBUG(...) LOG_NOOP #endif #if LOG_LEVEL_INFO >= LOG_LEVEL #define LOG_INFO(fmt,...) LOG_PRINT(ANDROID_LOG_INFO,fmt,##__VA_ARGS__) #else #define LOG_INFO(...) LOG_NOOP #endif #if LOG_LEVEL_WARNING >= LOG_LEVEL #define LOG_WARNING(fmt,...) LOG_PRINT(ANDROID_LOG_WARN,fmt,##__VA_ARGS__) #else #define LOG_WARNING(...) LOG_NOOP #endif #if LOG_LEVEL_ERROR >= LOG_LEVEL #define LOG_ERROR(fmt,...) LOG_PRINT(ANDROID_LOG_ERROR,fmt,##__VA_ARGS__) #else #define LOG_ERROR(...) LOG_NOOP #endif #if LOG_LEVEL_FATAL >= LOG_LEVEL #define LOG_FATAL(fmt,...) LOG_PRINT(ANDROID_LOG_FATAL,fmt,##__VA_ARGS__) #else #define LOG_FATAL(...) LOG_NOOP #endif #if LOG_LEVEL_FATAL >= LOG_LEVEL #define LOG_ASSERT(expression,fmt,...) if(!(expression)){__android_log_assert(#expression,LOG_TAG,fmt,##__VA_ARGS__);} #else #define LOG_ASSERT(...) LOG_NOOP #endif
更新Android.mk,定义日志标签以及日志等级
... #动态链接日志库 LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog #定义日志标签 LOG_TAG := \"hello-jni\" #定义默认日志等级 ifeq ($(APP_OPTIM), release) LOG_LEVEL := LOG_LEVEL_SILENT else LOG_LEVEL := LOG_LEVEL_VERBOSE endif #追加编译标记 LOCAL_CFLAGS += -DLOG_TAG=$(LOG_TAG) LOCAL_CFLAGS += -DLOG_LEVEL=$(LOG_LEVEL) include $(BUILD_SHARED_LIBRARY)
APP_OTIM变量指定了构建类型是发布还是调试,基于APP_OTIM标识,将LOG_LEVEL设置成匹配的日志等级。
最终在原生函数中应用如下:
#include "LogUtil.h" ...
JNIEXPORT jstring JNICALL Java_com_study_eric_jni_JniTest_getJniString
(JNIEnv *env, jobject object) {
LOG_VERBOSE("The stringFormJNI is called!"); LOG_DEBUG("env=%p thiz=%p",env, object); LOG_INFO("Returning a new string"); LOG_WARNING("Warning"); }
09-29 15:12:27.785 18542-18542/com.study.eric V/hello-jni: (/Users/daredos/Android/Study/app/src/main/jni/com_study_eric_JniTest.c:12) jstring Java_com_study_eric_jni_JniTest_getJniString(JNIEnv *, jobject): The stringFormJNI is called!
09-29 15:12:27.785 18542-18542/com.study.eric D/hello-jni: (/Users/daredos/Android/Study/app/src/main/jni/com_study_eric_JniTest.c:13) jstring Java_com_study_eric_jni_JniTest_getJniString(JNIEnv *, jobject): env=0xb4078be0 thiz=0xbe9b1d7c
09-29 15:12:27.785 18542-18542/com.study.eric I/hello-jni: (/Users/daredos/Android/Study/app/src/main/jni/com_study_eric_JniTest.c:14) jstring Java_com_study_eric_jni_JniTest_getJniString(JNIEnv *, jobject): Returning a new string
09-29 15:12:27.785 18542-18542/com.study.eric W/hello-jni: (/Users/daredos/Android/Study/app/src/main/jni/com_study_eric_JniTest.c:15) jstring Java_com_study_eric_jni_JniTest_getJniString(JNIEnv *, jobject): Warning