acl 日志记录方式介绍
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
? ? ? 在使用 acl 庫(kù)編寫應(yīng)用過(guò)程中,記錄日志是一個(gè)非常重要的過(guò)程,acl 從幾個(gè)層面提供了日志的不同記錄方式。在 acl 的 C 庫(kù)部分(lib_acl.a),有三個(gè)源文件與日志記錄相關(guān):acl_msg.c/acl_msg.h, acl_mylog.c/acl_mylog.h, acl_debug.c/acl_debug.h。其中,acl_mylog.c 是真正記錄日志的源文件,acl_msg.c 則是在 acl_mylog.c 基礎(chǔ)之上的二次封裝,acl_debug.c 是在 acl_msg.c 基礎(chǔ)之上的再次封裝。下面根據(jù)此三個(gè)日志源文件從三個(gè)層次描述日志記錄的過(guò)程。
?
? ? ? 一、ac_mylog.c/acl_mylog.h
? ? ? 打開(kāi) acl_mylog.h 頭文件,可以看到主要有三個(gè)函數(shù):acl_open_log(打開(kāi)日志文件),acl_write_to_log(寫日志)以及acl_close_log(關(guān)閉日志)---(這三個(gè)函數(shù)是最基礎(chǔ)的日志記錄過(guò)程,當(dāng)然我們不必直接使用)。該庫(kù)支持兩類日志記錄方式:1、本地文件記錄方式,2、與 syslog-ng 結(jié)合的網(wǎng)絡(luò)日志記錄方式。本地文件記錄方式是 acl 日志庫(kù)對(duì)外提供的最簡(jiǎn)單的日志記錄方式,此方式不依賴于第三方日志庫(kù),但不應(yīng)用在生產(chǎn)環(huán)境中,因?yàn)樵摲绞讲恢С秩罩净貪L等高級(jí)特性,為了便于生產(chǎn)上使用,所以產(chǎn)生了第二種方式(與 syslog-ng 結(jié)合),查看日志打開(kāi)接口(如下):
/*** 打開(kāi)日志文件* @param recipients {const char*} 日志接收器列表,由 "|" 分隔,接收器* 可以是本地文件或遠(yuǎn)程套接口,如:* /tmp/test.log|UDP:127.0.0.1:12345|TCP:127.0.0.1:12345|UNIX:/tmp/test.sock* 該配置要求將所有日志同時(shí)發(fā)給 /tmp/test.log, UDP:127.0.0.1:12345,* TCP:127.0.0.1:12345 和 UNIX:/tmp/test.sock 四個(gè)日志接收器對(duì)象* @param plog_pre {const char*} 日志記錄信息前的提示信息,建議用進(jìn)程* 名填寫此值*/ ACL_API int acl_open_log(const char *recipients, const char *plog_pre);? ? ? ?從上面的函數(shù)聲明可以看出,acl 的日志記錄允許同時(shí)輸出至多個(gè)日志管道中(最簡(jiǎn)單的方式就是直接寫入本地磁盤文件:/tmp/test.log),同時(shí)更應(yīng)看到,其中有三個(gè)奇怪的日志文件表達(dá)方式:UDP:IP:PORT, TCP:IP:PORT, UNIX:/xxx,其實(shí)這三種方式均是與 syslog-ng 相關(guān),即分別表示:
? ? ? 1、以 UDP 方式發(fā)送日志至 syslog-ng;
? ? ? 2、以 TCP 方式發(fā)送日志至 syslog-ng;
? ? ? 3、以 UNIX 域套接字方式發(fā)送日志至 syslog-ng。
? ? ? 因?yàn)槿罩竟芾硎且粋€(gè)非常復(fù)雜的過(guò)程,所以在 acl 除了提供最簡(jiǎn)單的日志文件記錄外,更建議用戶將日志輸出至 syslog-ng 中(作者自己的項(xiàng)目也往往是這樣做的)。
?
? ? ? 二、acl_msg.c/acl_msg.h
? ? ? 該日志庫(kù)提供了更為高級(jí)的日志記錄方法,不僅提供了靈活的日志記錄函數(shù),同時(shí)還允許用戶注冊(cè)自己的日志記錄函數(shù)庫(kù),該日志庫(kù)主要函數(shù)接口如下:
/*** 日志打開(kāi)函數(shù)* @param log_file {const char*} 日志接收者集合,由 "|" 分隔,接收器* 可以是本地文件或遠(yuǎn)程套接口,如:* /tmp/test.log|UDP:127.0.0.1:12345|TCP:127.0.0.1:12345|UNIX:/tmp/test.sock* 該配置要求將所有日志同時(shí)發(fā)給 /tmp/test.log, UDP:127.0.0.1:12345,* TCP:127.0.0.1:12345 和 UNIX:/tmp/test.sock 四個(gè)日志接收器對(duì)象* @param plog_pre {const char*} 日志記錄信息前的提示信息,建議用進(jìn)程* @param info_pre {const char*} 日志記錄信息前的提示信息*/ ACL_API void acl_msg_open(const char *log_file, const char *info_pre);/*** 關(guān)閉日志函數(shù)*/ ACL_API void acl_msg_close(void);? ? ? ?上面是日志打開(kāi)與關(guān)閉的函數(shù),看上去算是相對(duì)簡(jiǎn)單。下面是幾個(gè)日志記錄的函數(shù)接口:
/*** 一般級(jí)別日志信息記錄函數(shù)* @param fmt {const char*} 參數(shù)格式* @param ... 變參序列*/ #ifdef WIN32 ACL_API void acl_msg_info(const char *fmt,...); #else ACL_API void __attribute__((format(printf,1,2)))acl_msg_info(const char *fmt,...); #endif/*** 警告級(jí)別日志信息記錄函數(shù)* @param fmt {const char*} 參數(shù)格式* @param ... 變參序列*/ #ifdef WIN32 ACL_API void acl_msg_warn(const char *fmt,...); #else ACL_API void __attribute__((format(printf,1,2)))acl_msg_warn(const char *fmt,...); #endif/*** 錯(cuò)誤級(jí)別日志信息記錄函數(shù)* @param fmt {const char*} 參數(shù)格式* @param ... 變參序列*/ #ifdef WIN32 ACL_API void acl_msg_error(const char *fmt,...); #else ACL_API void __attribute__((format(printf,1,2)))acl_msg_error(const char *fmt,...); #endif/*** 致命級(jí)別日志信息記錄函數(shù)* @param fmt {const char*} 參數(shù)格式* @param ... 變參序列*/ #ifdef WIN32 ACL_API void acl_msg_fatal(const char *fmt,...); #else ACL_API void __attribute__((format(printf,1,2)))acl_msg_fatal(const char *fmt,...); #endif/*** 恐慌級(jí)別日志信息記錄函數(shù)* @param fmt {const char*} 參數(shù)格式* @param ... 變參序列*/ #ifdef WIN32 ACL_API void acl_msg_panic(const char *fmt,...); #else ACL_API void __attribute__((format(printf,1,2)))acl_msg_panic(const char *fmt,...); #endif? ? ? ?可以看到,這些函數(shù)的使用方式與 printf 類似,另外,在 UNIX 下使用 GCC 編譯時(shí)前面還有一個(gè)修飾符:__attribute__((format(printf,m,n))),這主要是方便 gcc 編譯器針對(duì)變參進(jìn)行語(yǔ)法檢查(大家應(yīng)該知道變參是如此方便靈活而又如此容易出錯(cuò))。
? ? ? 為了方便程序開(kāi)發(fā)過(guò)程中的調(diào)試,下面的函數(shù)當(dāng)用戶未調(diào)用 acl_msg_open 打開(kāi)日志而直接使用 acl_msg_xxx 寫日志時(shí),決定是否將日志信息輸出至屏幕(這個(gè)函數(shù)應(yīng)該在程序初始化時(shí)調(diào)用):
/*** 當(dāng)未調(diào)用 acl_msg_open 方式打開(kāi)日志時(shí),調(diào)用了 acl_msg_info/error/fatal/warn* 的操作,是否允許信息輸出至標(biāo)準(zhǔn)輸出屏幕上,通過(guò)此函數(shù)來(lái)設(shè)置該開(kāi)關(guān),該開(kāi)關(guān)* 僅影響是否需要將信息輸出至終端屏幕而不影響是否輸出至文件中* @param onoff {int} 非 0 表示允許輸出至屏幕*/ ACL_API void acl_msg_stdout_enable(int onoff);? ? ? ?前面曾說(shuō)過(guò),acl 的日志庫(kù)還允許用戶使用自己的日志記錄過(guò)程,但要求用戶必須在程序初始化時(shí)注冊(cè)自己的日志處理函數(shù),如下:
/*** 在打開(kāi)日志前調(diào)用此函數(shù)注冊(cè)應(yīng)用自己的日志打開(kāi)函數(shù)、日志關(guān)閉函數(shù)、日志記錄函數(shù)* @param open_fn {ACL_MSG_OPEN_FN} 自定義日志打開(kāi)函數(shù)* @param close_fn {ACL_MSG_CLOSE_FN} 自定義日志關(guān)閉函數(shù)* @param write_fn {ACL_MSG_WRITE_FN} 自定義日志記錄函數(shù)* @param ctx {void*} 自定義參數(shù)*/ ACL_API void acl_msg_register(ACL_MSG_OPEN_FN open_fn, ACL_MSG_CLOSE_FN close_fn,ACL_MSG_WRITE_FN write_fn, void *ctx);? ? ?調(diào)用此函數(shù)后,以后的日志記錄過(guò)程(即當(dāng)用戶調(diào)用:acl_msg_xxx 相關(guān)過(guò)程時(shí))的內(nèi)容便輸出便由用戶的日志庫(kù)控制。
?
? ? ? 除了以上主要的日志函數(shù)接口,在 acl_msg 中還提供了以下幾個(gè)函數(shù),便于用戶知曉程序出錯(cuò)原因:
/*** 獲得上次系統(tǒng)調(diào)用出錯(cuò)時(shí)的錯(cuò)誤描述信息,該函數(shù)內(nèi)部采用了線程局部變量,所以是線程* 安全的,但使用起來(lái)更簡(jiǎn)單些* @return {const char *} 返回錯(cuò)誤提示信息 */ ACL_API const char *acl_last_serror(void);/*** 獲得上次系統(tǒng)調(diào)用出錯(cuò)時(shí)的錯(cuò)誤號(hào)* @return {int} 錯(cuò)誤號(hào)*/ ACL_API int acl_last_error(void);?
? ? ? 三、acl_debug.c/acl_debug.h
? ? ? 該日志函數(shù)庫(kù)是在 acl_msg 之上的再一次封裝,該庫(kù)的思想來(lái)源于 squid 的日志記錄方式,可以將日志分成不同的類別,每一個(gè)類別又分成不同的級(jí)別,這樣用戶就可以非常方便地通過(guò)配置文件來(lái)記錄不同類別的不同級(jí)別的日志信息了。在程序初始化時(shí)需先調(diào)用如此函數(shù):
/*** 初始化日志調(diào)試調(diào)用接口* @param pStr {const char*} 調(diào)試類別(建議值在100至1000之間)標(biāo)簽及級(jí)別字符串,* 格式: 1,1; 2,10; 3,8... or 1:1; 2:10; 3:8...*/ ACL_API void acl_debug_init(const char *pStr);/*** 初始化日志調(diào)試調(diào)用接口* @param pStr {const char*} 調(diào)試標(biāo)簽及級(jí)別字符串,* 格式: 1,1; 2,10; 3,8... or 1:1; 2:10; 3:8...* @param max_debug_level {int} 最大調(diào)試標(biāo)簽值*/ ACL_API void acl_debug_init2(const char *pStr, int max_debug_level);? ? ? ?其中,第一個(gè)參數(shù)是一個(gè)由日志記錄類別與級(jí)別組成的字符串,格式為:類別1:最大記錄級(jí)別, 類別2:最大記錄級(jí)別, ...。例如:100:2; 102:3; 103:4,其含義是日志將會(huì)記錄類別為 100 的所有級(jí)別值小于2、類別為 101 的所有級(jí)別值小于 3 以及類別為 103 的所有級(jí)別值小于 4 的日志信息。關(guān)于記錄類別需要注意:類別值最好是 >= 100,且 < 1000(當(dāng)使用 acl_debug_init2 初始化時(shí)只要類別值 >= 100 即可,因?yàn)榈诙€(gè)參數(shù)指定了最大類別值),這是因?yàn)?acl 庫(kù)內(nèi)部一些保留的類別值都在 0 -- 100 之間。
? ? ? ?那么具體的使用這些類別與級(jí)別記錄日志的接口是什么呢?如下所示:
/*** 日志調(diào)試宏接口* @param SECTION {int} 調(diào)試標(biāo)簽值* @param LEVEL {int} 對(duì)應(yīng)于SECTION調(diào)試標(biāo)簽的級(jí)別*/ #define acl_debug(SECTION, LEVEL) \!acl_do_debug((SECTION), (LEVEL)) ? (void) 0 : acl_msg_info?? ? ? ?看到了吧,用戶其實(shí)只需要調(diào)用一個(gè)宏即可,如下面的例子:?
/* 初始化日志類別記錄 */const char *str = "101:2; 103:4; 105:3";/* 記錄所有類別值為 101 級(jí)別小于等于 2、類別值為 102 級(jí)別小于等于 4、類別值為 105 級(jí)別小于等于 3 的日志內(nèi)容 */acl_debug_init(str);....../* 下面的日志因符合類別值 101 級(jí)別值 <= 2 而被記錄 */acl_debug(101, 2)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));/* 下面日志符合類別 105 的記錄級(jí)別 */acl_debug(105, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));/* 下面的日志因不符合類別值 103 的記錄級(jí)別條件而被忽略 */acl_debug(103, 5)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));/* 下面日志的類別值 102 因不存在而被忽略 */acl_debug(102, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));?
? ? ? 此外,為了方便,還可以傳給 acl_debug_init 的參數(shù)寫為:"all:1",意思是所有類別的級(jí)別值 <= 1 的日志都將被記錄,如下面的內(nèi)容都會(huì)被記錄:
?
acl_debug_init("all:1"); ......acl_debug(100, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(101, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(101, 0)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(102, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(103, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(104, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));acl_debug(105, 1)("%s(%d): log time: %ld", __FILE__, __LINE__, time(NULL));......?
? ? ? ?ok,有關(guān)日志 ?acl 日志記錄函數(shù)就先寫這些,使用者可以根據(jù)項(xiàng)目需要采用不同的日志記錄方式。
?
? ? ? 參考:
? ? ? 本文地址:http://zsxxsz.iteye.com/blog/1893115
? ? ? 更多文章:http://zsxxsz.iteye.com/
? ? ? 下載:http://sourceforge.net/projects/acl/
? ? ? svn:svn checkout svn://svn.code.sf.net/p/acl/code/trunk acl-code
? ? ? QQ 群:242722074
?
?
?
轉(zhuǎn)載于:https://my.oschina.net/u/568966/blog/309522
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的acl 日志记录方式介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PHP框架
- 下一篇: Chromium on Android: