现在知道去哪找介绍文档的文字了。本头文件的主要作用就是定义SU模块的调试宏。
/**@ingroup su_log
* @file sofia-sip/su_debug.h
* @brief SU debugging macros
*
* The logging levels and macros to use are defined as follows:
* - SU_DEBUG_0() fatal errors, panic
* - SU_DEBUG_1() critical errors, minimal progress at subsystem level
* - SU_DEBUG_2() non-critical errors
* - SU_DEBUG_3() warnings, progress messages
* - SU_DEBUG_5() signaling protocol actions (incoming packets, etc.)
* - SU_DEBUG_7() media protocol actions (incoming packets, etc.)
* - SU_DEBUG_9() entering/exiting functions, very verbatim progress
*
* These macros are used to log with module-specific levels. The SU_LOG
* macro is redefined with a pointer to a module-specific #su_log_t
* structure, e.g., "iptsec_debug.h".
*
* @author Pekka Pessi
*
* @date Created: Tue Feb 8 10:06:33 2000 ppessi
*
* @sa @ref debug_logs, su_llog(), su_vllog(), #su_log_t,
*/
从文字可以看出来,将会定义SU_DEBUG_0至SU_DEBUG_9这十个宏。还会用一个指向su_log_t结构体的变量重新再定义SU_LOG宏。所谓的重新定义SU_LOG宏的意思是,su模块是个基础模块,其他功能模块将使用它提供的基础服务来实现高层功能。例如,其他功能模块都会使用su模块提供的日志服务。因此其他功能模块一般都会再建立一个xxx_debug.h头文件,在这个头文件内会申明一个su_log_t结构体变量,然后再用这个新的su_log_t结构体变量重新定义SU_LOG宏。具体可参考iptsec_debug.h头文件。由于其他功能模块采用链接su模块代码的方式,因此所有的功能模块都会包含一份自身的SU_DEBUG_x和SU_LOG宏。
其实这也验证了之前在分析su_log.c/h文件时的疑惑,那时就觉得这只是日志框架代码,并没有任何实际使用的代码。经过这里的介绍内容,可以获知一些如何使用su模块日志服务的规则。
#ifndef SU_DEBUG_MAX
/** The maximum debugging level. */
#define SU_DEBUG_MAX 9
#endif
#define SU_LOG_LEVEL \
((SU_LOG != NULL && SU_LOG->log_init) == 0 ? 9 : \
((SU_LOG != NULL && SU_LOG->log_init > 1) ? \
SU_LOG->log_level : su_log_default->log_level))
上面前一段是重新定义SU_DEBUG_MAX宏,为数字9。后面那段是定义SU_LOG_LEVEL宏的值。SU_LOG也是一个宏,它会在各个功能模块的xxx_debug.h头文件中重新定义。可以查看iptsec_debug.c/h。
SOFIA_BEGIN_DECLS
/** Common log for client and server components. */
SOFIAPUBVAR su_log_t iptsec_log[];
SOFIA_END_DECLS
#define SU_LOG (iptsec_log)
#include
su_log_t iptsec_log[] = { SU_LOG_INIT("iptsec", "IPTSEC_DEBUG", SU_DEBUG) };
我们正在分析的头文件su_debug.h在定义了SU_LOG后被包含。也就是说在特定功能模块的debug.h头文件内会首先定义模块特定的一个su_log_t结构体变量,并将SU_LOG重定义成SU_LOG。如此一来,su_debug.h中SU_LOG_LEVEL的值将取决于iptset_log,或者说取决于特定模块的su_log_t结构体变量。换种说法是,每个功能模块(例如iptsec模块)都有自己特定的SU_LOG_LEVEL宏,这个值取决于自身模块的su_log_t结构体变量(iptsec模块内是iptset_log变量)。
有了上述SU_LOG_LEVLE的分析经验。我们知道SU_LOG会在某个特定模块内重新定义:iptsec模块内是iptset_log变量。下面这段的意思是,如果某个模块未定义自己特定的su_log_t结构体变量,那么就使用su_log文件中定义的su_log_default变量。
#if SU_DEBUG_MAX >= 0
#ifndef SU_LOG
#define SU_LOG (su_log_default)
#else
SOFIAPUBVAR su_log_t SU_LOG[];
#endif
接下来是定义SU_DEBUG_DEF宏。它的作用是生成各类日志等级水平的内联函数:su_debug_0至su_debug_9。
#define SU_DEBUG_DEF(level) \
su_inline void su_debug_##level(char const *fmt, ...) \
__attribute__ ((__format__ (printf, 1, 2))); \
su_inline void su_debug_##level(char const *fmt, ...) \
{ va_list ap; va_start(ap, fmt); su_vllog(SU_LOG, level, fmt, ap); va_end(ap); }
然后会像下面这样使用。
SU_DEBUG_DEF(0)
/** Log messages at level 0.
*
* Fatal errors and panic messages should be logged at level 0.
*
* @sa su_llog(), su_vllog(), #su_log_t, @ref debug_logs
*/
#define SU_DEBUG_0(x) (SU_LOG_LEVEL >= 0 ? (su_debug_0 x) : (void)0)
/** Log C library errors. */
#define SU_LERROR(s) (su_llog(SU_LOG, 1, "%s: %s\n", (s), strerror(errno)))
/** Log socket errors. */
#define SU_LSERROR(s) \
(su_llog(SU_LOG, 1, "%s: %s\n", (s), su_strerror(su_errno())))
#else
#define SU_DEBUG_0(x) ((void)0)
#define SU_LERROR(s) ((void)0)
#define SU_LSERROR(s) ((void)0)
#endif
如果日志等级满足大于等于0,那么SU_DEBUG_0将是su_debug_0函数,否则SU_DEBUG_0将退化成0(数字零)最终宏替换后成为一条“0;”这样的无意义语句。同时,连带着定义另两个宏:SU_LERROR和SU_LSERROR。一个用来记录C库的错误,一个用来记录socket错误。如果日志等级小于0,那么这三个宏都将退化成0(数字零)。文件中其他部分的内容都是生成1至9日志等级的宏(SU_DEBUG_X)。
我们在回头看看这个宏定义。它是在编译期确定最多生成哪几类日志等级输出函数(su_debug_x)。
#ifndef SU_DEBUG_MAX
/** The maximum debugging level. */
#define SU_DEBUG_MAX 9
#endif
而SU_DEBUG_LEVEL将决定编译期生成哪几类对应实际输出函数的SU_DEBUG_X宏。否则SU_DEBUG_X宏将对应无意义的“0;”这样的语句。
分析su_debug.h头文件让我们对su模块内的基础日志输出服务有了更深一层的认识。同时,也清楚了其他模块内如何使用这基础服务。查看su_module_debug.h头文件会发现,其他su模块自身也以同样的方式在使用这个基础服务框架。su模块内将使用su_log文件内定义的su_log_global变量记录日志。这里同样是重定义了SU_LOG后,再包含su_debug.h头文件。
** Debugging log for @b su module. */
SOFIAPUBVAR su_log_t su_log_global[];
#define SU_LOG (su_log_global)
#include
但还有一个疑问:因为每个特定功能模块都会重定义SU_LOG宏,以及再包含su_debug.h头文件,那么可以认定每个特定功能模块都有一套自己的SU_DEBUG_X宏(因为宏里使用了SU_LOG宏)。如果是这样的话,那同时使用两个或两个以上的功能模块时是否会产生SU_DEBUG_X宏重定义的冲突?如果不想造成冲突,那么在某个特定功能模块提供出的公开API接口头文件中不应该包括特定功能模块的xx_debug.h头文件,因为这头文件就是用来重新定义SU_DEBUG_X宏的。更进一步猜测,所有其他功能模块内的代码都只会在.c文件中包括自身模块的xx_debug.h头文件来获得日志输出接口。