1
0
Fork 0
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

705 lines
21 KiB

/* --------------------------------------------------------------------------------------------------------
* File: custom_log.h
*
* Desc: ChenZhen 偏好的, 对 Android log 机构的定制配置.
*
* -----------------------------------------------------------------------------------
* < 习语 和 缩略语 > :
*
* -----------------------------------------------------------------------------------
*
* Usage: 调用本 log 机构的 .c or .h 文件, 若要使能这里的 log 机制,
* 则必须在 inclue 本文件之前, "#define ENABLE_DEBUG_LOG" 先.
*
* 同 log.h 一样, client 文件在 inclue 本文件之前, "最好" #define LOG_TAG <module_tag>
* "module_tag" 是当前待调试的 模块的标识.
*
* 另外, 可以使用 V() 来输出 verbose 的 log, 但必须先 "#define ENABLE_VERBOSE_LOG".
*
* 若用户要 dump 大量 mem 数据, 此时有大量快速的 log 输出, 可能导致 host 端接收来不及,
* 此时用户可以定义宏 MASSIVE_LOG, 通过在特定 log 接口中延时, 保证 host 端接收到完整 log.
*
* Note:
*
* Author: ChenZhen
*
* --------------------------------------------------------------------------------------------------------
* Version:
* v1.0
* --------------------------------------------------------------------------------------------------------
* Log:
----Tue Mar 02 21:30:33 2010 v.10
*
* --------------------------------------------------------------------------------------------------------
*/
#ifndef __CUSTOM_LOG_H__
#define __CUSTOM_LOG_H__
#ifdef __cplusplus
extern "C" {
#endif
/* ---------------------------------------------------------------------------------------------------------
* Include Files
* ---------------------------------------------------------------------------------------------------------
*/
#include <log/log.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* ---------------------------------------------------------------------------------------------------------
* Macros Definition
* ---------------------------------------------------------------------------------------------------------
*/
/**
* 若下列 macro 有被定义, dump 内存块的 log 接口每次执行之后将 sleep 若干时间.
*/
// #define MASSIVE_LOG
/**
* 若定义有 MASSIVE_LOG, dump 内存块的 log 接口每次 sleep 的时间 us 为单位.
*/
#define RESPITE_TIME_FOR_MASSIVE_LOG_IN_US (1 * 10)
/** 若下列 macro 有被定义, 才 使能 log 输出 : 参见 "Usage". */
// #define ENABLE_DEBUG_LOG
/** .! : 若需要全局地关闭 D log, 可以使能下面的代码. */
/*
#undef ENABLE_DEBUG_LOG
#warning "debug log is disabled globally!"
*/
/** 是否 log 源文件 路径信息. */
#define LOG_FILE_PATH
/*-----------------------------------*/
#ifndef LOGV
#define LOGV ALOGV
#endif
#ifndef LOGD
#define LOGD ALOGD
#endif
#ifndef LOGI
#define LOGI ALOGI
#endif
#ifndef LOGW
#define LOGW ALOGW
#endif
#ifndef LOGE
#define LOGE ALOGE
#endif
/*-----------------------------------*/
#ifdef ENABLE_VERBOSE_LOG
#undef ENABLE_DEBUG_LOG
#define ENABLE_DEBUG_LOG
// #error
#ifdef LOG_FILE_PATH
#define V(fmt, args...) \
{ D(fmt, ## args); }
// { LOGV("[File] : %s; [Line] : %d; [Func] : %s; " fmt , __FILE__, __LINE__, __FUNCTION__, ## args); }
#else
#define V(fmt, args...) \
{ D(fmt, ## args); }
// { LOGV("[Line] : %d; [Func] : %s; " fmt , __LINE__, __FUNCTION__, ## args); }
#endif
#else
#define V(...) ((void)0)
#endif
/*-----------------------------------*/
#ifdef ENABLE_DEBUG_LOG
#ifdef LOG_FILE_PATH
#define D(fmt, args...) \
{ LOGD("[File] : %s; [Line] : %d; [Func] : %s;\n" fmt , __FILE__, __LINE__, __FUNCTION__, ## args); }
#else
#define D(fmt, args...) \
{ LOGD("[Line] : %d; [Func] : %s; " fmt , __LINE__, __FUNCTION__, ## args); }
#endif
#else
#define D(...) ((void)0)
#endif
/*-----------------------------------*/
// #ifdef ENABLE_DEBUG_LOG
#ifdef LOG_FILE_PATH
#define I(fmt, args...) \
{ LOGI("[File] : %s; [Line] : %d; [Func] : %s;\n" fmt , __FILE__, __LINE__, __FUNCTION__, ## args); }
#else
#define I(fmt, args...) \
{ LOGI("[Line] : %d; [Func] : %s; " fmt , __LINE__, __FUNCTION__, ## args); }
#endif
/*
#else // #ifdef ENABLE_DEBUG_LOG
#define I(fmt, args...) \
{ LOGI(fmt, ## args); }
#endif
*/
/*-----------------------------------*/
#ifdef LOG_FILE_PATH
#define W(fmt, args...) \
{ LOGW("[File] : %s; [Line] : %d; [Func] : %s;\n" fmt , __FILE__, __LINE__, __FUNCTION__, ## args); }
#else
#define W(fmt, args...) \
{ LOGW("[Line] : %d; [Func] : %s; " fmt , __LINE__, __FUNCTION__, ## args); }
#endif
/*-----------------------------------*/
#ifdef LOG_FILE_PATH
#define E(fmt, args...) \
{ LOGE("[File] : %s; [Line] : %d; [Func] : %s;\n" fmt , __FILE__, __LINE__, __FUNCTION__, ## args); }
#else
#define E(fmt, args...) \
{ LOGE("[Line] : %d; [Func] : %s; " fmt , __LINE__, __FUNCTION__, ## args); }
#endif
/*-----------------------------------*/
/**
* 若程序重复运行到当前位置的次数等于 threshold 或者第一次到达, 则打印指定的 log 信息.
*/
#ifdef ENABLE_DEBUG_LOG
#define D_WHEN_REPEAT(threshold, fmt, args...) \
do { \
static int count = 0; \
if ( 0 == count || (count++) == threshold ) { \
D(fmt, ##args); \
count = 1; \
} \
} while (0)
#else
#define D_WHEN_REPEAT(...) ((void)0)
#endif
/*-------------------------------------------------------*/
/** 使用 D(), 以十进制的形式打印变量 'var' 的 value. */
#define D_DEC(var) \
{ \
long long num = (var); \
D(#var " = %lld.", num); \
}
/** 使用 D(), 以十六进制的形式打印变量 'var' 的 value. */
#define D_HEX(var) \
{ \
long long num = (var); \
D(#var " = 0x%llx.", num); \
}
#define D_FLOAT(var) \
{ \
float num = (var); \
D(#var " = %f.", num); \
}
/** 使用 D(), 以十六进制的形式 打印指针类型变量 'ptr' 的 value. */
#define D_PTR(ptr) D(#ptr " = %p.", ptr);
/** 使用 D(), 打印 char 字串. */
#define D_STR(pStr) \
{\
if ( NULL == pStr )\
{\
D(#pStr" = NULL.");\
}\
else\
{\
D(#pStr" = '%s'.", pStr);\
}\
}
/*---------------------------------------------------------------------------*/
/** 使用 V(), 以十进制的形式打印变量 'var' 的 value. */
#define V_DEC(var) V(#var " = %d.", var);
/** 使用 V(), 以十六进制的形式打印变量 'var' 的 value. */
#define V_HEX(var) V(#var " = 0x%x.", var);
/** 使用 V(), 以十六进制的形式打印 类型是 unsigned long long 变量 'var' 的 value. */
#define V_HEX_ULL(var) V(#var " = 0x%016llx.", var);
/** 使用 V(), 以十六进制的形式 打印指针类型变量 'ptr' 的 value. */
#define V_PTR(ptr) V(#ptr " = %p.", ptr);
/** 使用 V(), 打印 char 字串. */
#define V_STR(pStr) \
{\
if ( NULL == pStr )\
{\
V(#pStr" = NULL.");\
}\
else\
{\
V(#pStr" = '%s'.", pStr);\
}\
}
/*-------------------------------------------------------*/
/**
* 调用函数, 并检查返回值, 根据返回值决定是否跳转到指定的错误处理代码.
* @param functionCall
* 对特定函数的调用, 该函数的返回值必须是 表征 成功 or err 的 整型数.
* 这里, 被调用函数 "必须" 是被定义为 "返回 0 表示操作成功".
* @param result
* 用于记录函数返回的 error code 的 整型变量, 通常是 "ret" or "result" 等.
* @param label
* 若函数返回错误, 程序将要跳转到的 错误处理处的 标号, 通常就是 "EXIT".
*/
#define CHECK_FUNC_CALL(functionCall, result, label) \
{\
if ( 0 != ( (result) = (functionCall) ) )\
{\
E("Function call returned error : " #result " = %d.", result);\
goto label;\
}\
}
/**
* 分配 heap 空间, 检查返回地址, 将分配得到的 heap 空间全部清 0.
* 若失败, 则将指定的 error code 赋值给指定的变量, 之后跳转到指定的错误处理代码.
* @param pDest
* 用于保存分配得到的 heap block 地址的目标指针变量.
* @param type
* 待分配的空间中, 数据单元 的类型.
* @param size
* 待分配空间中包含 "数据单元"(对应类型 'type') 的具体个数.
* 所以, 待分配空间的字节大小 是 "sizeof(type) * size".
* @param retVar
* 用于记录函数返回的 error code 的 整型变量, 通常是 "ret" or "result" 等.
* @param errCode
* 用来表征 "内存不足" 的 error code, 不同模块中可能使用不同的常数标识.
* 标准 linux 下, 通常是 ENOMEM.
* @param label
* 若空间分配失败, 程序将要跳转到的 错误处理代码的 标号, 通常就是 "EXIT".
*/
#define CHECK_MALLOC(pDest, type, size, retVar, errCode, label) \
{\
unsigned int bug_len = sizeof(type) * (size);\
if ( NULL == ( (pDest) = (type*)malloc(bug_len)))\
{\
retVar = errCode;\
E("Failed to malloc %u bytes.", bug_len);\
goto label;\
}\
memset( (void*)(pDest), 0, sizeof(bug_len));\
}
/**
* 在特定条件下, 判定 error 发生, 对变量 'retVar' 设置 'errCode',
* Log 输出对应的 Error Caution, 然后跳转 'label' 指定的代码处执行.
* @param msg
* 纯字串形式的提示信息.
* @param retVar
* 标识函数执行状态或者结果的变量, 将被设置具体的 Error Code.
* 通常是 'ret' or 'result'.
* @param errCode
* 表征特定 error 的常数标识, 通常是 宏的形态.
* @param label
* 程序将要跳转到的错误处理代码的标号, 通常就是 'EXIT'.
* @param args...
* 对应 'msgFmt' 实参中 '%s', '%d', ... 等 转换说明符 的具体可变长实参.
*/
#define SET_ERROR_AND_JUMP(msgFmt, retVar, errCode, label, args...) \
{\
E("To set '" #retVar "' to %d('" #errCode "') : " msgFmt, (errCode), ## args);\
(retVar) = (errCode);\
goto label;\
}
#define EXIT_FOR_DEBUG \
{\
E("To exit for debug.");\
return 1;\
}
/*---------------------------------------------------------------------------*/
/**
* 返回指定数组中的元素个数.
* @param array
* 有效的数组实例标识符.
*/
#define ELEMENT_NUM(array) ( sizeof(array) / sizeof(array[0]) )
/*---------------------------------------------------------------------------*/
/**
* 断言.
* 期望 'expect' 的 实参表达式 "成立", 即 非 0, 否则直接 abort 当前进程.
* @param msgFmt
* 字串形式的提示信息, 可以包含 '%s', '%d' 等 转换说明符.
* @param args...
* 对应 'msgFmt' 实参中 '%s', '%d', ... 等 转换说明符 的具体可变长实参.
*/
#define ASSERT(expect, msgFmt, args...) \
do { \
if ( !(expect) ) \
{ \
E("assert('" #expect "') FAILED, to ABORT. " msgFmt, ## args); \
abort(); \
} \
} while ( 0 )
/* ---------------------------------------------------------------------------------------------------------
* Types and Structures Definition
* ---------------------------------------------------------------------------------------------------------
*/
/* ---------------------------------------------------------------------------------------------------------
* Global Functions' Prototype
* ---------------------------------------------------------------------------------------------------------
*/
/* ---------------------------------------------------------------------------------------------------------
* Inline Functions Implementation
* ---------------------------------------------------------------------------------------------------------
*/
/*-------------------------------------------------------*/
/**
* dump 从 地址 'pStart' 开始, 长度为 'len' 字节的 memory block 的内容(16 进制数的形式).
*/
#ifdef ENABLE_DEBUG_LOG
#define D_MEM(pStart, len) \
{ \
D("dump memory from addr of '" #pStart"' : "); \
dumpMemory( (pStart), (len) ); \
}
inline static void dumpMemory(const void* pStart, uint32_t len)
{
char* pBuf = NULL; /* dump buffer. 用来以文本的形式("0xaa, 0xbb, ...") 表示 一行, 最多 16 字节的 十六进制数. */
size_t bufLen = 0; /* *pBuf 的字节长度, 包括末尾的 '\0'. */
unsigned char* pSource = (unsigned char*)pStart; /* 单次 sprintf 操作的源地址. */
char* pTarget = NULL; /* 目标地址. */
size_t i, j;
#define BYTES_PER_LINE (16) /* dump 输出每行打印的 source bytes 的数目. */
size_t BUF_SIZE_PER_SRC_BYTE = strlen("0xXX, "); // const. 每个待 dump 的 字节在 *pBuf 中需要的空间大小.
// memory 中的每个字节被表示为 "0xXX, " 或者 "0xXX\n " 的形式.
size_t fullLines = len / BYTES_PER_LINE; // 满 16 字节的行数.
size_t leftBytes = len % BYTES_PER_LINE; // 最后可能的不满行的 字节的个数.
if ( NULL == pStart || 0 == len )
{
return;
}
bufLen = (BYTES_PER_LINE * BUF_SIZE_PER_SRC_BYTE) + 1;
pBuf = (char*)malloc(bufLen);
if ( NULL == pBuf )
{
E("no enough memory.");
return;
}
LOGD("from %p; length %d : ", pStart, len);
/* 处理所有的 full line, ... */
for ( j = 0; j < fullLines; j++ )
{
pTarget = pBuf;
/* 遍历每个待 log 的 字节, ... */
for ( i = 0; i < BYTES_PER_LINE; i++ )
{
/* 打印到 *pTarget. */
sprintf(pTarget, "0x%02x, ", *pSource);
pTarget += BUF_SIZE_PER_SRC_BYTE;
pSource++;
}
*(++pTarget) = '\0';
/* log out 当前行. */
LOGD("\t%s", pBuf);
}
/* 处理最后的 不满的行. */
leftBytes = len % BYTES_PER_LINE;
if ( 0 != leftBytes )
{
pTarget = pBuf;
for ( i = 0; i < leftBytes; i++ )
{
sprintf(pTarget, "0x%02x, ", *pSource);
pTarget += BUF_SIZE_PER_SRC_BYTE;
pSource++;
}
*(++pTarget) = '\0';
LOGD("\t%s", pBuf);
}
free(pBuf);
#ifdef MASSIVE_LOG
usleep(RESPITE_TIME_FOR_MASSIVE_LOG_IN_US);
#endif
return;
}
#else // #ifdef ENABLE_DEBUG_LOG
#define D_MEM(...) ((void)0)
#endif
/*-------------------------------------------------------*/
#ifdef ENABLE_VERBOSE_LOG
#define V_MEM(pStart, len) \
{ \
D("dump memory from addr of '" #pStart"' : "); \
dumpMemory( (pStart), (len) ); \
}
#else // #ifdef ENABLE_VERBOSE_LOG
#define V_MEM(...) ((void)0)
#endif
/*---------------------------------------------------------------------------*/
#define DUMP_SIZE_PER_SRC_BYTE (sizeof("0xXX, ") - 1) // "1" : 字串最后的 '\0'.
/**
* 将 'pStart' 和 'len' 指定的一块内存数据, 以 hex ASCII 的形态 dump 'pBuf' 指定的 buf 中.
* 函数返回之后, "*pBuf' 尾部有 '\0' 字符.
* .! : 调用者 "必须" 保证 'pDest' 指向的 buf 的不小于 'len * DUMP_SIZE_PER_SRC_BYTE'.
*/
inline static void dumpMemInHexAsciiToMem(const void* pStart, unsigned int len, char* pBuf)
{
unsigned int i = 0;
unsigned char* pSource = (unsigned char*)pStart;
char* pTarget = pBuf; // 特定写入操作的目标地址.
if ( NULL == pStart || 0 == len || NULL == pBuf )
{
return;
}
for ( i = 0; i < len; i++ )
{
if ( i < len - 1 )
{
sprintf(pTarget, "0x%02x, ", *pSource);
}
else
{
sprintf(pTarget, "0x%02x", *pSource);
}
pSource++;
pTarget += DUMP_SIZE_PER_SRC_BYTE;
}
pBuf[len * DUMP_SIZE_PER_SRC_BYTE - 1] = '\0';
}
/*---------------------------------------------------------------------------*/
/**
* 以 hex ASCII 格式 log dump 从 'pStart' 开始, 长度为 'len' 字节的 mem 的内容, 16 字节为一行.
* 前导有 'indentNum' 个 '\t' 缩进.
* 支持的最大缩进不超过 15.
*/
inline static void dumpMemoryWithIndents(const void* pStart, unsigned int len, unsigned int indentNum)
{
char indents[16];
const unsigned int SRC_BYTES_NUM_PER_LINE = 16; // 输出中每行显示的源字节的个数.
unsigned int bufLen = SRC_BYTES_NUM_PER_LINE * DUMP_SIZE_PER_SRC_BYTE;
char* pBuf = (char*)malloc(bufLen);
unsigned int linesNum = 0; // 输出的行数.
unsigned char* pSrcStartInLine = NULL; // 当前行输出对应的源字节序列的起始地址.
unsigned int srcBytesNumInLine = 0; // 当前行要输出端的源字节的个数.
unsigned int i = 0;
/* 若原数据可以被若干个 满行 正好打印, 则... */
if ( 0 == (len % SRC_BYTES_NUM_PER_LINE) )
{
linesNum = len / SRC_BYTES_NUM_PER_LINE;
}
/* 否则, ... */
else
{
/* 增加最后一行的 不满行. */
linesNum = (len / SRC_BYTES_NUM_PER_LINE) + 1;
}
/*-------------------------------------------------------*/
indents[0] = '\0';
// for ( i = 0; i < indentNum - 1; i++ ) // "-1" : 对输出内容的地址标识, 可以替代一个缩进.
for ( i = 0; i < indentNum; i++ ) // "-1" : 对输出内容的地址标识, 可以替代一个缩进.
{
strcat(indents , "\t");
}
*(indents + indentNum) = '\0';
/*-------------------------------------------------------*/
pBuf[0] = '\0';
pSrcStartInLine = (unsigned char*)pStart;
/* 逐行输出. */
for ( i = 0; i < linesNum; i++ )
{
srcBytesNumInLine = (len - (i * SRC_BYTES_NUM_PER_LINE) ) % SRC_BYTES_NUM_PER_LINE;
/* 若当前行 "不是" 最后一行(第 (linesNum - 1) 行 , 则... */
if ( i < (linesNum - 1) )
{
srcBytesNumInLine = SRC_BYTES_NUM_PER_LINE;
}
/* 否则, 即当前行 "是" 最后一行", 则... */
else
{
/* 若是满行, 则... */
if ( 0 == (len % SRC_BYTES_NUM_PER_LINE ) )
{
srcBytesNumInLine = SRC_BYTES_NUM_PER_LINE;
}
else
{
srcBytesNumInLine = len % SRC_BYTES_NUM_PER_LINE;
}
}
dumpMemInHexAsciiToMem(pSrcStartInLine, srcBytesNumInLine, pBuf);
LOGD("%s" " [0x%04x] : " "%s", indents, SRC_BYTES_NUM_PER_LINE * i, pBuf);
pSrcStartInLine += srcBytesNumInLine;
#ifdef MASSIVE_LOG
usleep(RESPITE_TIME_FOR_MASSIVE_LOG_IN_US);
#endif
}
/*-------------------------------------------------------*/
free(pBuf);
}
/**
* 在 'pIndentsBuf' 指向的 buf 中, 从头插入 'indentNum' 个 '\t' 字符(缩进), 并跟上一个 '\0'.
* 通常 pIndentsBuf 指向一个 16 字节的 buffer.
*/
inline static void setIndents(char* pIndentsBuf, unsigned char indentNum)
{
unsigned char i = 0;
const unsigned char MAX_NUM_OF_INDENT = 16 - sizeof('\0');
if ( indentNum > MAX_NUM_OF_INDENT )
{
indentNum = MAX_NUM_OF_INDENT;
}
*pIndentsBuf = '\0';
for ( i = 0; i < indentNum; i++ )
{
strcat(pIndentsBuf, "\t");
}
*(pIndentsBuf + indentNum) = '\0';
}
inline static int dumpCharArray(const char* pStart, unsigned int len, unsigned char indentNum)
{
int ret = 0;
//unsigned long ret1 = -1;
char indents[16];
setIndents(indents, indentNum);
char* pBuf = NULL;
/*-------------------------------------------------------*/
if ( NULL == pStart )
{
LOGD("%s %s", indents, "null");
goto EXIT;
}
CHECK_MALLOC( pBuf, char, len + 1, ret, -1, EXIT);
memcpy(pBuf, pStart, len);
pBuf[len] = '\0';
// pBuf[len] = 0;
LOGD("%s %s", indents, pBuf);
EXIT:
if ( NULL != pBuf )
{
free(pBuf);
}
return ret;
}
inline static int dumpStr(const char* pStr, unsigned char indentNum)
{
int ret = 0;
char indents[16];
setIndents(indents, indentNum);
/*-------------------------------------------------------*/
if ( NULL == pStr )
{
LOGD("%s %s", indents, "null");
}
else
{
LOGD("%s %s", indents, pStr);
}
return ret;
}
/* ############################################################################################# */
/* < 单独针对 Android 平台的调试宏. > */
/**
* 打印 sp<T> 实例 "sp" 指向的实例对象的当前 强被引用计数.
* "D_SC" : Debug log Strong Count.
*/
#define D_SC(sp) D("strong count of '" #sp "' is '%d'.", (sp)->getStrongCount() )
#ifdef __cplusplus
}
#endif
#endif /* __CUSTOM_LOG_H__ */