本文来自 csdn lidp 转载著名出处。
上篇文章介绍了Android mk文件的编写,本篇举个具体例子,此程序的功能为对android 提供的log功能进行封装,提供统一的接口函数
droid_log(LOG_DEBUG,,,,,);
可以根据开关决定log的打印级别(修改logger.h 中的LOGLEVEL 宏),从低到高为五个:
LOG_VERBOSE, LOG_DEBUG,LOG_NOTICE, LOG_WARNING, LOG_ERROR。
通过logcat可以看到打印级别,时间戳,函数名,文件名,以及根据不同级别的语法高亮显示。
使用例子:
droid_log(LOG_DEBUG, "test debug\n");
第一个参数为上面提到的五个level, 后面为可变参数列表,与printf类似。
此功能在android上编译,把源码包放在external/下面,mm即可编译。
目录结构:
/android/external/hello
├── Android.mk
├── CleanSpec.mk
├── include
│ └── logger.h
└── src
├── Android.mk
├── hello.cpp
└── logger.cpp
源码:
logger.h
/*! \file * * \brief Logging routines,Support for logging to console. * * \author openser <[email protected]> * * \extref android/log.h * * * - this is a wraper for android log, user may see log in logcat. * - utility-related API functions, used by internal. * - * * \ref none */ #ifndef _LOGGER_H_ #define _LOGGER_H_ #include <android/log.h> #include <stdio.h> #include <unistd.h> #include <sys/time.h> #include <time.h> #include <stdarg.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #define LOGLEVEL 5 #define ESC 0x1b #define ATTR_RESET 0 #define ATTR_BRIGHT 1 #define ATTR_DIM 2 #define ATTR_UNDER 4 #define ATTR_BLINK 5 #define ATTR_REVER 7 #define ATTR_HIDDEN 8 /* termanal color define */ #define COLOR_BLACK 30 #define COLOR_GRAY (30 | 128) #define COLOR_RED 31 #define COLOR_BRRED (31 | 128) #define COLOR_GREEN 32 #define COLOR_BRGREEN (32 | 128) #define COLOR_BROWN 33 #define COLOR_YELLOW (33 | 128) #define COLOR_BLUE 34 #define COLOR_BRBLUE (34 | 128) #define COLOR_MAGENTA 35 #define COLOR_BRMAGENTA (35 | 128) #define COLOR_CYAN 36 #define COLOR_BRCYAN (36 | 128) #define COLOR_WHITE 37 #define COLOR_BRWHITE (37 | 128) /* log level define */ #define _LOG_ __FILE__, __LINE__ ,__PRETTY_FUNCTION__ #ifdef LOG_VERBOSE #undef LOG_VERBOSE #endif #ifdef LOG_VERBOSE #undef LOG_VERBOSE #endif #define LOG_VERBOSE 0 #define LOGGER_VERBOSE LOG_VERBOSE, _LOG_ #ifdef LOG_DEBUG #undef LOG_DEBUG #endif #ifdef LOG_DEBUG #undef LOG_DEBUG #endif #define LOG_DEBUG 1 #define LOGGER_DEBUG LOG_DEBUG, _LOG_ #ifdef LOG_NOTICE #undef LOG_NOTICE #endif #define LOG_NOTICE 2 #define LOGGER_NOTICE LOG_NOTICE, _LOG_ #ifdef LOG_WARNING #undef LOG_WARNING #endif #ifdef LOG_WARNING #undef LOG_WARNING #endif #define LOG_WARNING 3 #define LOGGER_WARNING LOG_WARNING, _LOG_ #ifdef LOG_ERROR #undef LOG_ERROR #endif #ifdef LOG_ERROR #undef LOG_ERROR #endif #define LOG_ERROR 4 #define LOGGER_ERROR LOG_ERROR, _LOG_ extern const char *loglevels[]; extern int colors[]; extern char dateformat[256]; /* out put time in a format */ void print_time(); /* fileter special sequeces ,such as ESC */ void term_filter_escapes(char *line); /* copy string , This is similar to strncpy, with two important differences: - the destination buffer will always be null-terminated - the destination buffer is not filled with zeros past the copied string length */ void tsk_copy_string(char *dst, const char *src, size_t size); /* format the input sring to specific color */ char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout); /* out put log to console in diff level the level is : LOG_DEBUG, LOG_NOTICE, LOG_VERBOSE, LOG_ERROR, LOG_WARNING an out put example :[Jan 2 04:55:55] DEBUG[1604]: src/transactions/tsip_transac_layer.c:282 tsip_transac_layer */ void _droid_log(int level, const char *file, int line, const char *function, const char *fmt, ...); /*put a sring to console*/ void tsk_console_puts(char *str); /*! * \brief Log a DEBUG message * \param level The minimum value of LOGLEVEL for this message * to get logcat */ #define droid_log(level, ...) do { \ if (level <= (LOGLEVEL) ) { \ if(level == 0) \ _droid_log(LOGGER_VERBOSE, __VA_ARGS__); \ else if( level == 1) \ _droid_log(LOGGER_DEBUG, __VA_ARGS__); \ else if(level == 2) \ _droid_log(LOGGER_NOTICE, __VA_ARGS__); \ else if(level == 3) \ _droid_log(LOGGER_WARNING, __VA_ARGS__); \ else if(level == 4) \ _droid_log(LOGGER_ERROR, __VA_ARGS__); \ else \ _droid_log(LOGGER_DEBUG, __VA_ARGS__); \ } \ } while (0) #endif
logger.cpp
/*! \file * * \brief Logging routines,Support for logging to console. * * \author openser <[email protected]> * * \extref android/log.h * * * - this is a wraper for android log, user may see log in logcat. * - utility-related API functions, used by internal ccdt. * - * * \ref none */ #include "logger.h" #include <android/log.h> /* log level definition */ const char *loglevels[] = { "VERBOSE", "DEBUG", "NOTICE", "WARNING", "ERROR", }; /* used by term_color */ int colors[] = { COLOR_GREEN, COLOR_BRGREEN, COLOR_YELLOW, COLOR_BRRED, COLOR_RED, COLOR_BRBLUE, COLOR_BRGREEN, }; /* date format , example : Jan 2 04:55:55*/ char dateformat[256] = "%b %e %T"; void print_time() { struct timeval tv; struct tm* ptm; char time_str[128]; long milliseconds; gettimeofday(&tv, NULL); ptm = localtime(&tv.tv_sec); strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", ptm); milliseconds = tv.tv_sec/1000; printf("%s.%03ld\n", time_str, milliseconds); } void tsk_copy_string(char *dst, const char *src, size_t size) { while(*src && size) { *dst++ = *src++; size--; } if(__builtin_expect(!size, 0)) dst--; *dst = '\0'; } void tsk_console_puts(char *str) { fprintf(stderr,"%s", str); fflush(stderr); } void term_filter_escapes(char *line) { int i; int len = strlen(line); for (i = 0; i < len; i++) { if (line[i] != ESC) continue; if ((i < (len - 2)) && (line[i + 1] == 0x5B)) { switch (line[i + 2]) { case 0x30: case 0x31: case 0x33: continue; } } /* replace ESC with a space */ line[i] = ' '; } } char *term_color(char *outbuf, const char *inbuf, int fgcolor, int bgcolor, int maxout) { int attr=0; char tmp[40]; memset(outbuf, 0, maxout); if (!fgcolor && !bgcolor) { tsk_copy_string(outbuf, inbuf, maxout); return outbuf; } if ((fgcolor & 128) && (bgcolor & 128)) { /* Can't both be highlighted */ tsk_copy_string(outbuf, inbuf, maxout); return outbuf; } if (!bgcolor) bgcolor =COLOR_BLACK; if (bgcolor) { bgcolor &= ~128; bgcolor += 10; } if (fgcolor & 128) { attr = ATTR_BRIGHT; fgcolor &= ~128; } if (fgcolor && bgcolor) { snprintf(tmp, sizeof(tmp), "%d;%d", fgcolor, bgcolor); } else if (bgcolor) { snprintf(tmp, sizeof(tmp), "%d", bgcolor); } else if (fgcolor) { snprintf(tmp, sizeof(tmp), "%d", fgcolor); } if (attr) { snprintf(outbuf, maxout, "%c[%d;%sm%s%c[0;%d;%dm", ESC, attr, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10); } else { snprintf(outbuf, maxout, "%c[%sm%s%c[0;%d;%dm", ESC, tmp, inbuf, ESC, COLOR_WHITE, COLOR_BLACK + 10); } return outbuf; } void _droid_log(int level, const char *file, int line, const char *function, const char *fmt, ...) { if(level > LOGLEVEL){ return; } time_t t; struct tm *tm; char date[64]; char linestr[64]; char tmp1[64]; char buf[256]; char buf1[256]; char msg[512]; int res; va_list ap; t = time(NULL); tm = localtime(&t); memset(date, 0, sizeof(date)); memset(buf, 0, sizeof(buf)); memset(buf1, 0, sizeof(buf1)); memset(msg, 0, sizeof(msg)); strftime(date, sizeof(date), dateformat, tm); snprintf(linestr,sizeof(linestr),"%d", line); snprintf(buf,sizeof(buf),"[%s] %s[%ld]: %s %s: ",date,term_color(tmp1, loglevels[level], colors[level], 0, sizeof(tmp1)),(long)getpid(), linestr, function); term_filter_escapes(buf); va_start(ap, fmt); res = vsnprintf(buf1,sizeof(buf1) - 1,fmt, ap); va_end(ap); snprintf(msg, sizeof(msg) -1, "%s%s",buf,buf1); __android_log_print(ANDROID_LOG_DEBUG, "%s",msg); }
#include "logger.h" int main(int argc, char **argv) { droid_log(LOG_DEBUG, "test debug\n"); return 0; }
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ hello.cpp logger.cpp LOCAL_MODULE_TAGS:= optional LOCAL_C_INCLUDES := external/hello/include LOCAL_MODULE:= hello LOCAL_SYSTEM_SHARED_LIBRARIES := libc libstdc++ libutils include $(BUILD_EXECUTABLE)
LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional include $(call all-makefiles-under,$(LOCAL_PATH))
logcat 可看到打印。
谢绝转载。