51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

查看: 364|回复: 1
打印 上一主题 下一主题

Linux C 日志模块(附代码)给有用的人

[复制链接]
  • TA的每日心情
    无聊
    昨天 09:21
  • 签到天数: 409 天

    连续签到: 3 天

    [LV.9]测试副司令

    跳转到指定楼层
    1#
    发表于 2023-8-14 13:08:06 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

    在产品研发的过程中,经常需要借助打印信息来帮助调试和后期维护。所以拥有一个完善的日志模块是至关重要的。

    如下是从经手的项目中整理出来的日志模块及使用示例,以备后续项目开发时使用。(备注:Linux环境下)

    log.c
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <sys/time.h>
    4. #include <sys/types.h>
    5. #include <sys/stat.h>
    6. #include <unistd.h>
    7. #include <string.h>
    8. #include <time.h>
    9. #include <ctype.h>
    10. #include <pthread.h>
    11. #include "log.h"

    12. /*存储日志的文件名*/

    13. static unsigned char g_ucLogFileName[MAX_LOG_FILE_NUM][STR_COMM_SIZE] = {{0}};

    14. /*指明是g_ucLogFileName中的哪个文件*/
    15. static unsigned char g_ucLogFileNo = 0;

    16. /*输出日志位置标记,0-输出到终端,1-输出到日志文件*/
    17. unsigned long g_ulPrintLogPlaceFlag = 0;
    18. /*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/
    19. unsigned long g_ulPrintDebugLogFlag = 0;

    20. /*日志文件大小*/
    21. static unsigned long g_ulLogFileSize = 0;

    22. /*日志文件句柄*/
    23. static FILE* pFile = NULL;

    24. /*日志存储互斥锁*/
    25. static pthread_mutex_t g_stSaveLogMutexLock;

    26. /*日志模块初始化标记*/
    27. static unsigned long g_ulLogInitFlag = 0;


    28. void LOG_SetPrintLogPlaceFlag(unsigned long flag)
    29. {
    30. g_ulPrintLogPlaceFlag = flag;
    31. }

    32. void LOG_SetPrintDebugLogFlag(unsigned long flag)
    33. {
    34. g_ulPrintDebugLogFlag = flag;
    35. }


    36. /*****************************************************************
    37. ** 函数名: get_file_size
    38. ** 输 入: char *path
    39. ** 输 出:
    40. ** 功能描述:获取指令文件大小
    41. ** 返回值: long
    42. ****************************************************************/
    43. static long get_file_size(const char *path)
    44. {
    45. long filesize = -1;
    46. struct stat statbuff;

    47. if(stat(path, &statbuff) < 0){
    48.      return filesize;
    49. }
    50. else{
    51.      filesize = statbuff.st_size;
    52. }
    53. return filesize;
    54. }

    55. /*****************************************************************
    56. ** 函数名: unsigned long LOG_PrintLogTime
    57. ** 输 入:  unsigned long ulBufLen 存储时间的空间长度
    58. ** 输 出:unsigned char *ucTime  存储时间
    59. ** 功能描述:日志输出
    60. ** 返回值:unsigned long
    61. ****************************************************************/
    62. unsigned long LOG_PrintLogTime(unsigned char *ucTime, unsigned long ulBufLen)
    63. {
    64.     struct tm* pstTmSec;
    65.     struct timeval stTmMsec;

    66. if(NULL == ucTime)
    67. {
    68.   return -1;
    69. }
    70. gettimeofday(&stTmMsec, NULL);
    71. pstTmSec = localtime(&stTmMsec.tv_sec);
    72. snprintf((char *)ucTime, ulBufLen - 1, "%04d-%02d-%02d %02d:%02d:%02d %03ldms",
    73.             pstTmSec->tm_year + 1900, pstTmSec->tm_mon + 1, pstTmSec->tm_mday, pstTmSec->tm_hour,
    74.             pstTmSec->tm_min, pstTmSec->tm_sec, stTmMsec.tv_usec / 1000);

    75. return 0;
    76. }

    77. /*****************************************************************
    78. ** 函数名:  unsigned char *LOG_LogTypeToStr
    79. ** 输 入:   unsigned char ucType  日志类型
    80.    unsigned long ulBufLen 存储日志类型字符串空间的长度
    81. ** 输 出:unsigned char *pucTypeString 根据日志类型将其转换成相应的字符串
    82. ** 功能描述:根据日志类型转换成相应的字符串
    83. ** 返回值:unsigned long
    84. ****************************************************************/
    85. unsigned long LOG_LogTypeToStr(unsigned char ucType, unsigned char *pucTypeString, unsigned long ulBufLen)
    86. {
    87. if(NULL == pucTypeString)
    88. {
    89.   return -1;
    90. }
    91. /*防止发生越界*/
    92. ulBufLen -= 1;

    93. switch(ucType)
    94. {
    95.   case LOG_DEBUG:
    96.   {
    97.    strncpy((char *)pucTypeString, "DEBUG", ulBufLen);
    98.    break;
    99.   }
    100.   case LOG_ERROR:
    101.   {
    102.    strncpy((char *)pucTypeString, "ERROR", ulBufLen);
    103.    break;
    104.   }
    105.   case LOG_WARNING:
    106.   {
    107.    strncpy((char *)pucTypeString, "WARNING", ulBufLen);
    108.    break;
    109.   }
    110.   case LOG_ACTION:
    111.   {
    112.    strncpy((char *)pucTypeString, "ACTION", ulBufLen);
    113.    break;
    114.   }
    115.   case LOG_SYSTEM:
    116.   {
    117.    strncpy((char *)pucTypeString, "SYSTEM", ulBufLen);
    118.    break;
    119.   }
    120.   default:
    121.   {
    122.    strncpy((char *)pucTypeString, "UNKNOWN", ulBufLen);
    123.    break;
    124.   }
    125. }
    126. return 0;
    127. }

    128. /*****************************************************************
    129. ** 函数名: unsigned long LOG_OpenLogFile
    130. ** 输 入:  void
    131. ** 输 出:void
    132. ** 功能描述:打开日志文件
    133. ** 返回值:unsigned long
    134. ****************************************************************/
    135. unsigned long LOG_OpenLogFile(void)
    136. {
    137. char *path = (char*)g_ucLogFileName[g_ucLogFileNo];
    138. char *flag = NULL;
    139. int len = 0;

    140. /*判断文件是否已经打开*/
    141. if(NULL != pFile)
    142. {
    143.   LOG_PRINT("[ACTION] file opened!");
    144.   return 0;
    145. }
    146. /*判断文件名是否有定义*/
    147. if(NULL == path)
    148. {
    149.   LOG_PRINT("[ERROR] file name is NULL.");
    150.   return -1;
    151. }

    152. /*判断文件是否存在*/
    153. if (!access(path, 0))
    154. {
    155.   /*获取文件大小*/
    156.   if (0 > (len = get_file_size(path)))
    157.   {
    158.    LOG_PRINT("[ERROR] get file size failed!");
    159.    return -1;
    160.   }
    161. }
    162. flag = (len > 0 && len < g_ulLogFileSize) ? "a" : "w";

    163. /*打开文件*/
    164. pFile = fopen(path, flag);
    165. if(NULL == pFile)
    166. {
    167.   LOG_PRINT("[ERROR] open file failed!");
    168.   return -1;
    169. }
    170. LOG_PRINT("[DEBUG] open file name = %s", path);
    171. return 0;
    172. }

    173. /*****************************************************************
    174. ** 函数名: LOG_PrintLog
    175. ** 输 入:  unsigned char *ucLogInfo  需要打印或者存储的日志信息
    176.    unsigned char ucType 日志类型
    177. ** 输 出:void
    178. ** 功能描述:日志输出
    179. ** 返回值:unsigned long
    180. ****************************************************************/
    181. unsigned long LOG_PrintLog(unsigned char ucType, unsigned char *pucLogInfo)
    182. {
    183. unsigned long ulResult = 0;
    184. unsigned long ulFileLen = 0;
    185. unsigned char ucTime[STR_COMM_SIZE] = {0};
    186. unsigned char ucLogTypeStr[STR_COMM_SIZE] = {0};
    187. unsigned char ucLogInfo[STR_MAX_SIZE] = {0};

    188. if(NULL == pucLogInfo)
    189. {
    190.   return -1;
    191. }

    192. /*将日志类型转换成字符串*/
    193. ulResult = LOG_LogTypeToStr(ucType, ucLogTypeStr, sizeof(ucLogTypeStr));
    194. /*获取生成日志的时间*/
    195. ulResult += LOG_PrintLogTime(ucTime, sizeof(ucTime));
    196. if(0 != ulResult)
    197. {
    198.   return -1;
    199. }
    200. snprintf((char *)ucLogInfo, sizeof(ucLogInfo) - 1, "[%s] [%s] %s", ucTime, ucLogTypeStr, pucLogInfo);
    201. /*判断是否打印调试日志*/
    202. if(PRINT_LOG_TO_TERM == g_ulPrintLogPlaceFlag)
    203. {
    204.   printf("%s", ucLogInfo);
    205.   return 0;
    206. }
    207. /*加锁保护文件操作*/
    208. pthread_mutex_lock(&g_stSaveLogMutexLock);
    209. /*打开日志文件*/
    210. (void)LOG_OpenLogFile();
    211. if(NULL != pFile)
    212. {
    213.   fputs((char *)ucLogInfo, pFile);
    214.   ulFileLen = ftell(pFile);
    215.   LOG_PRINT("file len = %ld", ulFileLen);
    216.   if(ulFileLen >= g_ulLogFileSize)
    217.   {
    218.    fclose(pFile);
    219.    pFile = NULL;
    220.    g_ucLogFileNo = (g_ucLogFileNo + 1) % MAX_LOG_FILE_NUM;
    221.   }
    222. }
    223. pthread_mutex_unlock(&g_stSaveLogMutexLock);
    224. return 0;
    225. }

    226. /*****************************************************************
    227. ** 函数名: LOG_Init
    228. ** 输 入:  const unsigned char* ucLogFileName  用来保存日志的文件名
    229.    unsigned long ulFileSize 存储日志的文件大小
    230. ** 输 出:void
    231. ** 功能描述:日志打印初始化
    232. ** 返回值:unsigned long
    233. ****************************************************************/
    234. unsigned long LOG_Init(const unsigned char* ucLogFileName, unsigned long ulFileSize)
    235. {
    236. unsigned int i = 0;
    237. /*判断参数的合法性*/
    238. if((NULL == ucLogFileName) || !(ulFileSize > 0))
    239. {
    240.   return -1;
    241. }
    242. /*判断是否将日志输出到日志文件*/
    243. if((PRINT_LOG_TO_FILE != g_ulPrintLogPlaceFlag) || (0 != g_ulLogInitFlag))
    244. {
    245.   printf("g_ulPrintLogPlaceFlag = %ld g_ulLogInitFlag = %ld\n",g_ulPrintLogPlaceFlag,g_ulLogInitFlag);
    246.   LOG_PRINT("print log to termination!!");
    247.   return 0;
    248. }

    249. /*记录日志模块已经被初始化(防止改模块被重复初始化)*/
    250. g_ulLogInitFlag = 1;

    251. /*生成存储日志的文件名*/
    252. for(i = 0; i < NUMBER(g_ucLogFileName); i++)
    253. {
    254.   snprintf((char *)g_ucLogFileName[i], sizeof(g_ucLogFileName[i]) - 1, "%s_%02d", ucLogFileName, i);
    255.   LOG_PRINT("Log File: %s", g_ucLogFileName[i]);
    256.   printf("Log File: %s\n", g_ucLogFileName[i]);
    257. }
    258. /*设置日志文件大小*/
    259. g_ulLogFileSize = ulFileSize;
    260. pthread_mutex_init(&g_stSaveLogMutexLock, NULL);

    261. return 0;
    262. }

    263. /*****************************************************************
    264. ** 函数名: LOG_Destroy
    265. ** 输 入:  void
    266. ** 输 出:void
    267. ** 功能描述:日志打印资源释放
    268. ** 返回值:unsigned long
    269. ****************************************************************/
    270. void LOG_Destroy(void)
    271. {
    272. if(pFile != NULL)
    273. {
    274.   fclose(pFile);
    275.   pFile = NULL;
    276. }
    277. pthread_mutex_destroy(&g_stSaveLogMutexLock);
    278. return;
    279. }
    复制代码




    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    昨天 09:21
  • 签到天数: 409 天

    连续签到: 3 天

    [LV.9]测试副司令

    2#
     楼主| 发表于 2023-8-14 13:09:05 | 只看该作者

    log.h
    1. #ifndef _LOG_H_
    2. #define _LOG_H_
    3. #include <string.h>

    4. /*通用字符串存储大小定义*/
    5. #define STR_COMM_SIZE 128
    6. #define STR_MAX_SIZE 1024

    7. #define MAX_LOG_FILE_NUM    (3)

    8. #define NUMBER(type) sizeof(type)/sizeof(type[0])

    9. #define __FILENAME__ (strrchr(__FILE__, '/') ? (strrchr(__FILE__, '/') + 1) : __FILE__)

    10. /*日志类型*/
    11. enum
    12. {
    13.     LOG_DEBUG = 0,/*调试日志*/
    14.     LOG_ERROR,/*错误日志*/
    15.     LOG_WARNING,/*告警日志*/
    16.     LOG_ACTION,/*运行日志*/
    17.     LOG_SYSTEM,/*系统日志*/
    18.     BUTTOM
    19. };

    20. /*将日志输出到终端*/
    21. #define PRINT_LOG_TO_TERM (0)
    22. /*将日志输出到文件中*/
    23. #define PRINT_LOG_TO_FILE (1)

    24. /*调试日志宏定义*/
    25. #define DEBUG_PRINT 0
    26. #define LOG_PRINT(fmt, ...) do{\
    27. if(DEBUG_PRINT)\
    28. {\
    29.   printf(fmt"  [line:%d] [%s]\n", ##__VA_ARGS__, __LINE__, __FUNCTION__);\
    30. }\
    31. }while(0);

    32. /*错误日志打印(在日志打印模块还未启动时使用)*/
    33. #define LOG_ERR(fmt, ...) do{\
    34. printf("[ERROR]  "fmt"  [line:%d] [%s]\n", ##__VA_ARGS__, __LINE__, __FUNCTION__);\
    35. }while(0);



    36. /*存储日志标记. 0-不存储日志, 1-存储日志*/
    37. extern unsigned long g_ulPrintLogPlaceFlag;

    38. /*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/
    39. extern unsigned long g_ulPrintDebugLogFlag;

    40. unsigned long LOG_PrintLog(unsigned char ucType, unsigned char *pucLogInfo);


    41. /*日志打印宏定义*/
    42. #define LOG_INFO(type, fmt, ...) do{\
    43. if(PRINT_LOG_TO_TERM == g_ulPrintLogPlaceFlag) \
    44. { \
    45.   if((0 == g_ulPrintDebugLogFlag) && (LOG_DEBUG == type)) \
    46.   {\
    47.    break;\
    48.   }\
    49.      unsigned char ucLogInfo[STR_MAX_SIZE] = {0}; \
    50.   snprintf((char *)ucLogInfo, sizeof(ucLogInfo) - 1, fmt"  [%s] [line:%d] [%s]\n", ##__VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__); \
    51.   LOG_PrintLog(type, ucLogInfo); \
    52. } \
    53. else \
    54. { \
    55.   unsigned char ucLogInfo[STR_MAX_SIZE] = {0}; \
    56.   snprintf((char *)ucLogInfo, sizeof(ucLogInfo) - 1, fmt"  [%s] [line:%d] [%s]\n", ##__VA_ARGS__, __FILENAME__, __LINE__, __FUNCTION__); \
    57.   LOG_PrintLog(type, ucLogInfo); \
    58. } \
    59. }while(0)


    60. /*是否打印调试日志标记,0-不打印调试日志,1-打印调试日志*/
    61. extern void LOG_SetPrintDebugLogFlag(unsigned long flag);
    62. /*存储日志标记. 0-不存储日志, 1-存储日志*/
    63. extern void LOG_SetPrintLogPlaceFlag(unsigned long flag);

    64. extern unsigned long LOG_Init(const unsigned char* ucLogFileName, unsigned long ulFileSize);
    65. extern void LOG_Destroy(void);

    66. #endif //_LOG_H_
    复制代码
    main.c
    1. #include <stdio.h>
    2. #include "log.h"

    3. int test_func1()
    4. {
    5. LOG_INFO(LOG_DEBUG, "%s", "hello world!!");
    6. return 0;
    7. }

    8. int main(int argc, char *argv[])
    9. {
    10. LOG_SetPrintDebugLogFlag(1);//打印调试信息
    11. //LOG_SetPrintLogPlaceFlag(1);//保存打印信息到文件
    12. LOG_Init("info", 8000);

    13. LOG_INFO(LOG_DEBUG, "%s", "Init log!!");

    14. test_func1();

    15. LOG_INFO(LOG_DEBUG, "%s", "Destroy log!!");
    16. LOG_Destroy();
    17. }
    复制代码

    执行结果:

    由执行结果可以看出一条打印信息包含了时间、日志类型、内容、文件名、行号、函数名等信息,这样就能够方便快速的定位问题,其使用方法也与printf函数类似,简单方便。

    其次该日志模块还支持将日志存至文件,可以自行定义文件的大小及个数,日志循环覆盖。


    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-5-9 05:50 , Processed in 0.067978 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表