概述
在現代軟件開發中,日志記錄系統是不可或缺的一部分。它不僅可以幫助開發人員在應用程序中定位和解決問題,還可以用于監控、性能分析、安全審計等方面。本文將介紹日志記錄系統的基本概念、重要性以及如何構建一個高效的日志記錄系統。
為什么需要日志記錄系統?
日志是應用程序在運行時生成的文本消息,用于記錄關鍵事件、錯誤信息、警告以及其他有價值的信息。日志記錄系統的作用如下:
故障排除與問題定位:當應用程序出現問題時,日志可以提供關于發生了什么、在哪里發生以及為什么發生的關鍵信息,幫助開發人員快速定位和解決問題。
性能分析:通過記錄關鍵操作的時間戳和執行時間,開發人員可以分析應用程序的性能瓶頸,并進行優化。
監控與報警:監控系統可以分析日志,實時監控應用程序的健康狀態。當出現異常情況時,可以觸發報警機制,使團隊可以及時采取措施。
安全審計:記錄安全相關事件和訪問,以便進行后續的審計和分析。
構建日志記錄系統的關鍵步驟
日志級別與分類:日志級別包括調試(Debug)、信息(Info)、警告(Warning)、錯誤(Error)等。不同級別的日志用于不同目的,例如調試時使用調試日志來追蹤代碼執行,而錯誤日志用于記錄嚴重的問題。選擇合適的日志級別可以避免日志信息過于冗雜或過于稀少。
日志格式與結構:一個良好的日志格式應包括時間戳、日志級別、模塊/組件名以及具體的日志消息。統一的格式使得日志易于閱讀和分析。例如:[時間戳] [日志級別] [模塊名] - 日志消息
異步日志寫入:為避免阻塞應用程序的正常執行,可以采用異步日志寫入方式。日志消息被緩沖并在適當的時機寫入磁盤,從而提高應用程序的性能。
日志存儲與滾動:考慮使用滾動策略,定期歸檔或刪除舊的日志文件,以免日志文件無限增大。選擇適當的存儲方式,如本地文件、數據庫或云存儲。
上下文信息:除了基本的日志信息外,還可以在日志中添加上下文信息,如用戶ID、請求ID、會話ID等。這些信息有助于在復雜的分布式系統中跟蹤請求流程。
敏感信息與安全:避免將敏感信息(如密碼、API密鑰)寫入日志。同時,實施權限控制,限制對日志文件的訪問,確保敏感信息不被濫用。
日志分析與可視化:利用日志分析工具或平臺,對日志進行聚合、搜索和可視化分析。這有助于發現模式、趨勢以及潛在問題。
Rlog組件
Rlog作為一款高性能的純C語言日志組件,為開發人員提供了一種輕松、靈活且可定制的日志記錄解決方案。其簡單的接口和插件擴展功能使得它適用于各種不同規模和類型的項目。無論是小型應用程序還是大型系統,Rlog都能為您提供高效的日志記錄支持,幫助您更好地理解和管理應用程序的運行狀態。
純C語言開發:Rlog完全由C語言編寫,因此具有廣泛的可移植性和兼容性。它可以輕松地集成到各種C語言項目中。
簡單的接口:Rlog提供了簡單、直觀的接口,使開發人員可以輕松地在代碼中插入日志記錄語句。這使得調試和問題定位變得更加容易。
靈活可配置:Rlog允許開發人員根據項目需求進行高度自定義的配置。您可以定義日志級別、格式、輸出位置等,以滿足不同應用場景的需求。
插件擴展:一個突出的特點是Rlog的插件式擴展輸出端點的能力。這意味著您可以將日志消息輸出到各種不同的地方,如文件、終端、遠程服務器等,以適應多樣化的需求。
Rlog特性
支持用戶自定義輸出端點(例如:串口終端、網絡中斷、Flash...),輸出端點以插件形式自定義擴展。
日志內容可包含日志等級、時間戳、行號,函數信息,文件信息;
支持多種操作系統(RT-Thread、Linux...),也支持裸機平臺;
日志輸出支持:printf原始格式,日志等級輸出,hexdump輸出;
Rlog目錄結構
?
. ├──?example │???├──?rlog_linux_adapter.c????????/*?linux環境下的適配接口?*/ │???└──?rlog_rtt_adapter.c??????????/*?rt-thread環境下的適配接口?*/ ├──?include/ │???├──?rlog_adapter.h??????????????/*?rlog適配描述?*/ │???└──?rlog.h??????????????????????/*?rlog對外接口?*/ ├──?main.c??????????????????????????/*?rlog的測試樣例?*/ ├──?Makefile????????????????????????/*?linux環境rlog構建Makefile?*/ ├──?plug-in?????????????????????????/*?輸出端點插件的存放路徑?*/ ├──?SConscript??????????????????????/*?rt-thread環境rlog構建腳本?*/ └──?src ????├──?rlog.c??????????????????????/*?rlog核心代碼?*/ ????├──?rlog_def.h??????????????????/*?rlog核心代碼使用的定義?*/ ????└──?rlog_utils.c????????????????/*?rlog使用的C庫接口?*/
?
Rlog靈活配置
靜態配置:
靜態配置采用宏定義的方式,用戶可直接修改rlog_adapter.h頭文件的宏定義,就可以修正相關配置;
靜態配置的管控權限比動態配置的高,例如:靜態配置設置日志輸出總開關為關閉,動態配置設置日志輸出使能,日志已經無法輸出。
配置描述如下:
?
/*?Enable?log?output?*/ #define?RLOG_OUTPUT_ENABLE??????????????1 /*?Set?log?output?level,?rang:?from?RLOG_LEVEL_ASSERT?to?RLOG_LEVEL_VERBOSE?*/ #define?RLOG_OUTPUT_LEVEL???????????????RLOG_LEVEL_VERBOSE /*?Enable?log?color?*/ #define?RLOG_COLOUR_ENABLE??????????????1 /*?Enable?log?color?*/ #define?RLOG_TIME_ENABLE????????????????1 /*?Support?log?include?directory?*/ #define?RLOG_DIRECTORY_ENABLE???????????1 /*?Support?log?include?funtiong?name?*/ #define?RLOG_FUNCTION_ENABLE????????????1 /*?Support?log?include?line?number*/ #define?RLOG_LINE_ENABLE????????????????1 /*?Buffer?size?for?every?line's?log?*/ #define?RLOG_LINE_BUFF_LEN??????????????128 /*?Output?line?number?max?length?*/ #define?RLOG_LINE_NUM_SIZE??????????????5 /*?Output?newline?sign?*/ #define?RLOG_NEWLINE_SIGN???????????????" " /*?Enable?assert?check?*/ #define?RLOG_ASSERT_ENABLE??????????????1 /*?Log?function.?default?FDB_PRINT?macro?is?printf()?*/ #define?RLOG_PRINT(...)?????????????????printf(__VA_ARGS__)
?
?
?
宏 | 描述 |
---|---|
RLOG_OUTPUT_ENABLE | rlog日志輸出總開關 |
RLOG_OUTPUT_LEVEL | rlog日志輸出等級總開關 |
RLOG_COLOUR_ENABLE | rlog日志等級輸出帶顏色開關 |
RLOG_TIME_ENABLE | rlog日志等級輸出帶時間開關 |
RLOG_DIRECTORY_ENABLE | rlog日志等級輸出帶文件路徑開關 |
RLOG_FUNCTION_ENABLE | rlog日志等級輸出帶函數名開關 |
RLOG_LINE_ENABLE | rlog日志等級輸出帶行號開關 |
RLOG_LINE_BUFF_LEN | rlog每一條日志最大長度 |
RLOG_LINE_NUM_SIZE | rlog日志等級輸出行號的最大長度 |
RLOG_NEWLINE_SIGN | rlog日志換行符格式 |
RLOG_ASSERT_ENABLE | rlog使用assert功能 |
RLOG_PRINT(...) | rlog中斷輸出設置,如rt-thread采用rt_kprintf, linux采用printf |
?
動態配置:
動態配置采用接口的方式,用戶通過調用rlog.h頭文件提供的接口設置;
動態配置的管控權限比靜態配置的低,例如:靜態配置設置日志輸出總開關為關閉,動態配置設置日志輸出使能,日志已經無法輸出。
?
/** ?*?RLog?output?enable ?*? ?*?@param?enable?true:?enable?output,?false:?disable?output? ?*/ void?rlog_enable(bool?enable); /** ?*?RLog?output?color?enable ?*? ?*?@param?enable?true:?enable?output?color,?false:?disable?output?color ?*/ void?rlog_color_enable(bool?enable); /** ?*?RLog?level?output?format?setting ?*? ?*?@param?level??log?level ?*?@param?format?log?format ?*/ void?rlog_level_fmt_set(rlog_lvl_t?level,?int?format); /** ?*?RLog?level?output?format?setting ?*? ?*?@param?level??log?level ?*?@param?format?log?format ?*? ?*?@return?result?true:?supported?format,?false:?unsupported?format ?*/ bool?rlog_level_fmt_get(rlog_lvl_t?level,?int?format); /** ?*?RLog?filter?the?content?of?the?log?level ?*? ?*?@param?level??log?level ?*/ void?rlog_level_filter_set(rlog_lvl_t?level);
配置函數 | 描述 |
---|---|
rlog_enable | rlog日志輸出使能開關 |
rlog_color_enable | rlog日志等級輸出帶顏色開關 |
rlog_level_fmt_set | rlog日志等級輸出格式設置,RLOG_FMT_LVL/RLOG_FMT_TAG/RLOG_FMT_TIME/RLOG_FMT_DIR/RLOG_FMT_FUNC/RLOG_FMT_LINE |
rlog_level_fmt_get | rlog日志等級輸出格式獲取 |
rlog_level_filter_set | rlog日志等級輸出過濾設置 |
?
Rlog適配
不同平臺的適配方式不同,所以為rlog核心層提供了統一的接口,適配接口如下:
?
void?rlog_adapter_init(void); void?rlog_adapter_deinit(void); void?rlog_lock(void); void?rlog_unlock(void); char?*rlog_get_time(void); void?rlog_output(const?char?*log,?uint16_t?len);
適配函數 | 描述 |
---|---|
rlog_adapter_init | rlog適配層初始化,如端點插件初始化 |
rlog_adapter_deinit | rlog適配層去初始化,如端點插件去初始化 |
rlog_lock | rlog日志鎖,為rlog提供線程安全 |
rlog_unlock | rlog日志解鎖,為rlog提供線程安全 |
rlog_get_time | rlog日志提供時間 |
rlog_output | rlog日志輸出適配接口 |
?
linux下的適配方式:
?
static?pthread_mutex_t?mutex; void?rlog_lock(void) { ????pthread_mutex_lock(&mutex); } void?rlog_unlock(void) { ????pthread_mutex_unlock(&mutex); } char?*rlog_get_time(void) { #define?TIME_STR_SIZE???????32 ????static?char?time_str[TIME_STR_SIZE]?=?{0}; ????time_t?tmp; ????struct?tm?*timp; ????time(&tmp);??? ????timp?=?localtime(&tmp); ????memset(time_str,?0,?TIME_STR_SIZE); ????rlog_snprintf(time_str,?TIME_STR_SIZE,?"%04d-%02d-%02d?%02d:%02d:%02d",? ????????????????????????????????(1900?+?timp->tm_year),?(1?+?timp->tm_mon),?timp->tm_mday, ????????????????????????????????timp->tm_hour,?timp->tm_min,?timp->tm_sec); ????return?time_str; } void?rlog_output(const?char?*log,?uint16_t?len) { ????RLOG_PRINT("%.*s",?len,?log); } void?rlog_adapter_init(void) { ????pthread_mutex_init(&mutex,?NULL); } void?rlog_adapter_deinit(void) { ????pthread_mutex_destroy(&mutex); }
?
Rlog驗證
rlog驗證以linux環境為例,Rlog開源路徑:https://gitee.com/RiceChen0/rlog
rlog驗證操作流程:
?
youyeetoo@youyeetoo:~$?git?clone?https://gitee.com/RiceChen0/rlog.git youyeetoo@youyeetoo:~/rlog$?make youyeetoo@youyeetoo:~/rlog$?./output/rlog_1.0.0? RLog?Version:?v1.0.0 RLog?Author:?RiceChen RLog?Contact:?https://gitee.com/RiceChen0/rlog Youyeetoo (2023-08-15?18:53:27)[main.c?main:12]I/RLOG:?Youyeetoo RLOG?HexDump--Title:?RLOG,?len:?9 00000000:?59?6F?75?79?65?65?74?6F?6F???????????????????????Youyeetoo
?
rlog驗證效果:
Rlog總結
rlog提供了簡單易用的日志系統,采用插件方式,提供靈活的輸出端點的設置。
rlog的原型參考了開源項目:https://gitee.com/RT-Thread-Mirror/EasyLogger。
rlog不依賴C庫,rlog_utils.c中,重新定義了C庫接口。
下一步計劃:
rlog提供不同場景下的插件,網絡中斷,文件存儲,異步操作。
rlog將提供對應的上位機,上位機功能將集成到RTOOLS中。
編輯:黃飛
?
評論
查看更多