歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> C語言實現簡單的分級別寫日志程序

C語言實現簡單的分級別寫日志程序

日期:2017/3/1 10:32:29   编辑:Linux編程
  1. /************************************************************************/
  2. /*
  3. * 文件名稱:write_log.cpp
  4. * 摘 要:此文件實現了普通WINDOWS程序中的日志功能
  5. * 主要有以下特點:
  6. * 1. 根據日期創建日志文件目錄,每天的日志分別存放在不同的日志目錄中;
  7. * 2. 日志內容分三種類型,根據不同需要,寫不同的日志類型的日志文件,
  8. * 方便通過日志定位、分析問題;
  9. * 3. 函數經過比較好的封裝,便於復用;
  10. * 待改進點:
  11. * 1. 為了方便,日志內容打印時使用了time函數,其精確度較低;
  12. * 2. 可將這些函數封裝為一個日志類,或者動態庫,使其更通用;
  13. * 3. 沒有考慮跨平台情景,目前只使用於WINDOWS下
  14. * 4. 日志文件內容還可進一步改進,比如打印出當前文件名與行號,使用日志功能
  15. * 更加實用;
  16. *
  17. * 當前版本:1.0
  18. * 作 者:duanyongxing
  19. * 完成日期:2009年10月11日
  20. */
  21. /************************************************************************/
  22. #ifndef __WRITELOG_H__
  23. #define __WRITELOG_H__
  24. #include "stdafx.h"
  25. #include <time.h>
  26. #include <memory.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <stdarg.h>
  30. #include <windows.h>
  31. #define _LOG_WRITE_STATE_ 1 /* 條件編譯開關,1:寫日志,0:不寫日志 */
  32. #define LOG_SUCCESS (0)
  33. #define LOG_FAILED (-1)
  34. #define LOG_BOOL_TRUE (1)
  35. #define LOG_BOOL_FALSE (0)
  36. #define DWORD_NULL (0xFFFFFFFF)
  37. #define MAX_LOGTEXT_LEN (2048) /* 每行日志的最大長度*/
  38. #define MAX_FILE_PATH (255) /* 日志文件路徑的最大長度*/
  39. #define MAX_LOG_FILE_SIZE (512 * 1024) /* 日志文件內容的最大長度*/
  40. #define MAX_LOG_FILE_NAME_LEN (256) /* 日志文件名的最大長度*/
  41. #define LOG_TYPE_INFO 0 /* 日志類型: 信息類型*/
  42. #define LOG_TYPE_ERROR 1 /* 日志類型: 錯誤類型*/
  43. #define LOG_TYPE_SYSTEM 2 /* 日志類型: 系統類型*/
  44. #define TEST_CASE_MAX_FILE_LEN (1024) /* 測試函數中文件內容最大長度*/
  45. const char g_LogRootPath[] = "C://My_APPLOG"; /*日志文件根路徑,由用戶指定*/
  46. #pragma pack(push, 1)
  47. typedef struct tagLOG_DATA /* 日志內容結構體*/
  48. {
  49. char strDate[11]; /* 日期:格式為如:2009-10-11*/
  50. char strTime[9]; /* 時間:格式為如:16:10:57*/
  51. unsigned int iType; /* 日志類型:3種:INFO(0)/ERROR(1)/SYSTEM(2)*/
  52. char strText[MAX_LOGTEXT_LEN]; /*日志內容*/
  53. }LOG_DATA, *LPLOG_DATA;
  54. #pragma pack(pop)
  55. int Create_LogDir(const char *pStrPath);
  56. int Create_LogFile(const char *pStrFile, int iPos);
  57. int IsFileExist(const char *pStrFile);
  58. int GetLogPath(char *pStrPath);
  59. DWORD GetFileLenth(const char *pFile);
  60. int Write_Log_Text(LPLOG_DATA lpLogData);
  61. void Write_Log(unsigned int uiLogType, char *pstrFmt, ...);
  62. void TestLogCase_One();
  63. int main(int argc, char* argv[])
  64. {
  65. Write_Log(LOG_TYPE_SYSTEM, "Program begin.");
  66. TestLogCase_One();
  67. Write_Log(LOG_TYPE_SYSTEM, "Program end.");
  68. return 0;
  69. }
  70. /*********************************************************************
  71. * 函數名稱:void TestLogCase_One()
  72. * 說明:簡單的測試函數,讀文件
  73. * 調用者:main
  74. * 輸入參數:
  75. * 無
  76. * 輸出參數:
  77. * 無
  78. * 返回值:
  79. * void --
  80. * 作者: duanyongxing
  81. * 時間 : 2009-10-11
  82. *********************************************************************/
  83. void TestLogCase_One()
  84. {
  85. FILE *pFile = NULL;
  86. char *pFieldContent = NULL;
  87. char szFileName[] = "test_case.txt";
  88. pFieldContent = (char *)malloc(TEST_CASE_MAX_FILE_LEN);
  89. if(NULL == pFieldContent)
  90. {
  91. Write_Log(LOG_TYPE_ERROR, "malloc memory failed,program exit!");
  92. return;
  93. }
  94. memset(pFieldContent, 0, TEST_CASE_MAX_FILE_LEN);
  95. Write_Log(LOG_TYPE_INFO, "malloc memory for pFiled successful,memory size is: %ld",
  96. TEST_CASE_MAX_FILE_LEN);
  97. pFile = fopen(szFileName, "r");
  98. if(NULL == pFile)
  99. {
  100. fprintf(stderr, "open file failed.");
  101. Write_Log(LOG_TYPE_ERROR, "Open file %s failed. program exit!", szFileName);
  102. return;
  103. }
  104. Write_Log(LOG_TYPE_INFO, "Open file %s successful.", szFileName);
  105. fread(pFieldContent, 1, TEST_CASE_MAX_FILE_LEN, pFile);
  106. pFieldContent[TEST_CASE_MAX_FILE_LEN -1] = '/0';
  107. fclose(pFile);
  108. printf("The file %s content is: /n%s/n", szFileName, pFieldContent);
  109. Write_Log(LOG_TYPE_INFO, "The file %s content is: /n%s/n", szFileName, pFieldContent);
  110. }
  111. /*********************************************************************
  112. * 函數名稱:void Write_Log(unsigned int uiLogType, char *pstrFmt, ...)
  113. * 說明:日志寫函數,支持變長參數
  114. * 調用者:任何需要寫日志的地方
  115. * 輸入參數:
  116. * unsigned iType -- 日志類別
  117. * char *pstrFmt -- 日志內容
  118. * ... -- 變長參數
  119. * 輸出參數:
  120. * 無
  121. * 返回值:
  122. * void --
  123. * 作者: duanyongxing
  124. * 時間 : 2009-10-11
  125. *********************************************************************/
  126. void Write_Log(unsigned int uiLogType, char *pstrFmt, ...)
  127. {
  128. #if _LOG_WRITE_STATE_ /* 寫日志與否的編譯開關*/
  129. LOG_DATA data;
  130. time_t curTime;
  131. struct tm *mt;
  132. va_list v1;
  133. memset(&data, 0, sizeof(LOG_DATA));
  134. va_start(v1, pstrFmt);
  135. _vsnprintf(data.strText, MAX_LOGTEXT_LEN, pstrFmt, v1);
  136. va_end(v1);
  137. data.iType = uiLogType;
  138. curTime = time(NULL);
  139. mt = localtime(&curTime);
  140. strftime(data.strDate, sizeof(data.strDate), "%Y-%m-%d", mt);
  141. strftime(data.strTime, sizeof(data.strTime), "%H:%M:%S", mt);
  142. Write_Log_Text(&data);
  143. #endif _LOG_WRITE_STATE_
  144. }
  145. /*********************************************************************
  146. * 函數名稱:int GetLogPath(char *pStrPath)
  147. * 說明:獲取日志文件路徑
  148. * 調用者:Write_Log_Text
  149. * 輸入參數:
  150. * 無
  151. * 輸出參數:
  152. * char *pStrPath
  153. * 返回值:
  154. * int -- LOG_FAILED: 失敗
  155. * -- LOG_SUCCESS: 成功
  156. * 作者: duanyongxing
  157. * 時間 : 2009-10-11
  158. *********************************************************************/
  159. int GetLogPath(char *pStrPath)
  160. {
  161. if(NULL == pStrPath)
  162. {
  163. return LOG_FAILED;
  164. }
  165. int iRet = 0;
  166. time_t curTime = time(NULL);
  167. struct tm *mt = localtime(&curTime);
  168. /* 根據日期組成文件夾名稱*/
  169. sprintf(pStrPath, "%s//%d%02d%02d", g_LogRootPath, mt->tm_year + 1900,
  170. mt->tm_mon + 1, mt->tm_mday);
  171. iRet = Create_LogDir(pStrPath);
  172. return iRet;
  173. }
  174. /*********************************************************************
  175. * 函數名稱:int GetLogFileName(int iLogType, const char *pStrPath, char *pStrName)
  176. * 說明:獲取日志文件名
  177. * 調用者:Write_Log_Text
  178. * 輸入參數:
  179. * int iLogType -- 日志類型 3種:INFO(0)/ERROR(1)/SYSTEM(2)
  180. * const char *pStrPath -- 日志路徑 由GetLogPath得到
  181. * 輸出參數:
  182. * char *pStrName -- 日志文件名
  183. * 返回值:
  184. * int -- LOG_FAILED: 失敗
  185. * -- LOG_SUCCESS: 成功
  186. * 作者: duanyongxing
  187. * 時間 : 2009-10-11
  188. *********************************************************************/
  189. int GetLogFileName(int iLogType, const char *pStrPath, char *pStrName)
  190. {
  191. if(NULL == pStrPath)
  192. {
  193. return LOG_FAILED;
  194. }
  195. char szLogName[MAX_FILE_PATH];
  196. FILE *pFile = NULL;
  197. memset(szLogName, 0, MAX_FILE_PATH);
  198. switch (iLogType)
  199. {
  200. case LOG_TYPE_INFO:
  201. sprintf(szLogName, "%s//app_info", pStrPath);
  202. break;
  203. case LOG_TYPE_ERROR:
  204. sprintf(szLogName, "%s//app_error", pStrPath);
  205. break;
  206. case LOG_TYPE_SYSTEM:
  207. sprintf(szLogName, "%s//app_system", pStrPath);
  208. break;
  209. default:
  210. return LOG_FAILED;
  211. break;
  212. }
  213. strcat(szLogName, ".log");
  214. if(IsFileExist(szLogName))
  215. {
  216. /* 如果文件長度大於指定的最大長度,重新創建一文件,覆蓋原文件*/
  217. if((int)GetFileLenth(szLogName) + 256 >= MAX_LOG_FILE_SIZE)
  218. {
  219. Create_LogFile(szLogName, 0);
  220. }
  221. }
  222. else
  223. {
  224. Create_LogFile(szLogName, 0);
  225. }
  226. sprintf(pStrName, "%s", szLogName);
  227. return LOG_SUCCESS;
  228. }
  229. /*********************************************************************
  230. * 函數名稱:int Create_LogDir(const char *pStrPath)
  231. * 說明:創建日志存放路徑
  232. * 調用者:GetLogPath
  233. * 輸入參數:
  234. * const char *pStrPath --用戶指定的根路徑
  235. * 輸出參數:
  236. * 無
  237. * 返回值:
  238. * int -- LOG_FAILED: 失敗
  239. * -- LOG_SUCCESS: 成功
  240. * 作者: duanyongxing
  241. * 時間 : 2009-10-11
  242. *********************************************************************/
  243. int Create_LogDir(const char *pStrPath)
  244. {
  245. if(NULL == pStrPath)
  246. {
  247. return LOG_FAILED;
  248. }
  249. int iRet = 0;
  250. char szSub[MAX_FILE_PATH];
  251. char *pSub = NULL;
  252. int iIndex = 0;
  253. int iLen = 0;
  254. int bFind = 0;
  255. memset(szSub, 0, sizeof(MAX_FILE_PATH));
  256. /* 逐層創建目錄*/
  257. while(1)
  258. {
  259. pSub = strchr(pStrPath + iLen, '//');
  260. if(NULL == pSub)
  261. {
  262. if(iLen == 0)
  263. {
  264. return LOG_FAILED;
  265. }
  266. iRet = CreateDirectory(pStrPath, NULL);
  267. if(0 == iRet)
  268. {
  269. iRet = GetLastError();
  270. if(ERROR_ALREADY_EXISTS == iRet)
  271. {
  272. return LOG_SUCCESS;
  273. }
  274. return LOG_FAILED;
  275. }
  276. return LOG_SUCCESS;
  277. }
  278. else
  279. {
  280. if (!bFind)
  281. {
  282. bFind = 1;
  283. }
  284. else
  285. {
  286. memset(szSub, 0, sizeof(szSub));
  287. strncpy(szSub, pStrPath, pSub - pStrPath);
  288. CreateDirectory(szSub, NULL);
  289. }
  290. iLen = pSub - pStrPath + 1;
  291. }
  292. }
  293. return LOG_SUCCESS;
  294. }
  295. /*********************************************************************
  296. * 函數名稱:int Create_LogFile(const char *pStrFile, int iPos)
  297. * 說明:創建日志文件
  298. * 調用者:GetLogFileName
  299. * 輸入參數:
  300. * const char *pStrFile --文件名
  301. * int iPos --文件指針位置
  302. * 輸出參數:
  303. * 無
  304. * 返回值:
  305. * int -- LOG_FAILED: 失敗
  306. * -- LOG_SUCCESS: 成功
  307. * 作者: duanyongxing
  308. * 時間 : 2009-10-11
  309. *********************************************************************/
  310. int Create_LogFile(const char *pStrFile, int iPos)
  311. {
  312. HANDLE hd = 0;
  313. int iRet = 0;
  314. if(NULL == pStrFile)
  315. {
  316. return LOG_FAILED;
  317. }
  318. hd = CreateFile(pStrFile,
  319. GENERIC_READ | GENERIC_WRITE,
  320. 0,
  321. NULL,
  322. CREATE_ALWAYS,
  323. FILE_ATTRIBUTE_NORMAL,
  324. NULL
  325. );
  326. if(INVALID_HANDLE_VALUE == hd)
  327. {
  328. return LOG_FAILED;
  329. }
  330. if(DWORD_NULL == SetFilePointer(hd, iPos, NULL, FILE_BEGIN))
  331. {
  332. return LOG_FAILED;
  333. }
  334. iRet = SetEndOfFile(hd);
  335. CloseHandle(hd);
  336. return iRet;
  337. }
  338. /*********************************************************************
  339. * 函數名稱:int IsFileExist(const char *pStrFile)
  340. * 說明:判斷指定的文件是否存在
  341. * 調用者:GetLogFileName
  342. * 輸入參數:
  343. * const char *pStrFile --文件名
  344. * 輸出參數:
  345. * 無
  346. * 返回值:
  347. * int -- LOG_BOOL_FALSE: 不存在
  348. * -- LOG_BOOL_TRUE: 存在
  349. * 作者: duanyongxing
  350. * 時間 : 2009-10-11
  351. *********************************************************************/
  352. int IsFileExist(const char *pStrFile)
  353. {
  354. int iLen = 0;
  355. WIN32_FIND_DATA finddata;
  356. memset(&finddata, 0, sizeof(WIN32_FIND_DATA));
  357. HANDLE hd = FindFirstFile(pStrFile, &finddata);
  358. if(INVALID_HANDLE_VALUE == hd)
  359. {
  360. DWORD dwRet = GetLastError();
  361. if(ERROR_FILE_NOT_FOUND == dwRet || ERROR_PATH_NOT_FOUND == dwRet)
  362. {
  363. return LOG_BOOL_FALSE;
  364. }
  365. }
  366. FindClose(hd);
  367. return LOG_BOOL_TRUE;
  368. }
  369. /*********************************************************************
  370. * 函數名稱:DWORD GetFileLenth(const char *pFile)
  371. * 說明:判斷指定的文件大小
  372. * 調用者:GetLogFileName
  373. * 輸入參數:
  374. * const char *pFile --文件名
  375. * 輸出參數:
  376. * 無
  377. * 返回值:
  378. * DWORD -- 文件大小
  379. * 作者: duanyongxing
  380. * 時間 : 2009-10-11
  381. *********************************************************************/
  382. DWORD GetFileLenth(const char *pFile)
  383. {
  384. WIN32_FIND_DATA buff;
  385. HANDLE hd = NULL;
  386. memset(&buff, 0, sizeof(WIN32_FIND_DATA));
  387. hd = FindFirstFile(pFile, &buff);
  388. FindClose(hd);
  389. return (buff.nFileSizeHigh * MAXDWORD) + buff.nFileSizeLow;
  390. }
  391. /*********************************************************************
  392. * 函數名稱:int Write_Log_Text(LPLOG_DATA lpLogData)
  393. * 說明:寫日志內容
  394. * 調用者:Write_Log
  395. * 輸入參數:
  396. * LPLOG_DATA lpLogData --日志內容結構體量
  397. * 輸出參數:
  398. * 無
  399. * 返回值:
  400. * int -- LOG_FAILED: 失敗
  401. * -- LOG_SUCCESS: 成功
  402. * 作者: duanyongxing
  403. * 時間 : 2009-10-11
  404. *********************************************************************/
  405. int Write_Log_Text(LPLOG_DATA lpLogData)
  406. {
  407. char szFilePath[MAX_FILE_PATH];
  408. char szFileName[MAX_LOG_FILE_NAME_LEN];
  409. FILE *pFile = NULL;
  410. char szLogText[MAX_LOGTEXT_LEN];
  411. memset(szFilePath, 0, MAX_FILE_PATH);
  412. memset(szFileName, 0, MAX_LOG_FILE_NAME_LEN);
  413. memset(szLogText, 0, MAX_LOGTEXT_LEN);
  414. GetLogPath(szFilePath);
  415. GetLogFileName(lpLogData->iType, szFilePath, szFileName);
  416. pFile = fopen(szFileName, "a+");
  417. if(NULL == pFile)
  418. {
  419. return LOG_FAILED;
  420. }
  421. sprintf(szLogText, "%s %s %s/n", lpLogData->strDate, lpLogData->strTime,
  422. lpLogData->strText);
  423. fwrite(szLogText, 1, strlen(szLogText), pFile);
  424. fclose(pFile);
  425. return LOG_SUCCESS;
  426. }
Copyright © Linux教程網 All Rights Reserved