C语言实现简单的分级别写日志程序


  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.   
  42. #define LOG_TYPE_INFO    0             /* 日志类型: 信息类型*/   
  43. #define LOG_TYPE_ERROR   1             /* 日志类型: 错误类型*/   
  44. #define LOG_TYPE_SYSTEM  2             /* 日志类型: 系统类型*/   
  45. #define TEST_CASE_MAX_FILE_LEN (1024)   /* 测试函数中文件内容最大长度*/   
  46. const char g_LogRootPath[] = "C://My_APPLOG"/*日志文件根路径,由用户指定*/  
  47. #pragma pack(push, 1)   
  48. typedef struct tagLOG_DATA             /* 日志内容结构体*/  
  49. {  
  50.  char             strDate[11];   /* 日期:格式为如:2009-10-11*/  
  51.  char             strTime[9];    /* 时间:格式为如:16:10:57*/  
  52.  unsigned int  iType;         /* 日志类型:3种:INFO(0)/ERROR(1)/SYSTEM(2)*/  
  53.  char             strText[MAX_LOGTEXT_LEN]; /*日志内容*/  
  54. }LOG_DATA, *LPLOG_DATA;  
  55. #pragma pack(pop)   
  56.   
  57. int Create_LogDir(const char *pStrPath);  
  58. int Create_LogFile(const char *pStrFile, int iPos);  
  59. int IsFileExist(const char *pStrFile);  
  60. int GetLogPath(char *pStrPath);  
  61. DWORD GetFileLenth(const char *pFile);  
  62. int Write_Log_Text(LPLOG_DATA lpLogData);  
  63. void Write_Log(unsigned int uiLogType, char *pstrFmt, ...);  
  64. void TestLogCase_One();  
  65.   
  66. int main(int argc, char* argv[])  
  67. {  
  68.     Write_Log(LOG_TYPE_SYSTEM, "Program begin.");  
  69.  TestLogCase_One();  
  70.  Write_Log(LOG_TYPE_SYSTEM, "Program end.");  
  71.  return 0;  
  72. }  
  73. /********************************************************************* 
  74. * 函数名称:void TestLogCase_One() 
  75. * 说明:简单的测试函数,读文件 
  76. * 调用者:main 
  77. * 输入参数: 
  78. * 无 
  79. * 输出参数: 
  80. * 无 
  81. * 返回值: 
  82. * void  --  
  83. * 作者: duanyongxing 
  84. * 时间 : 2009-10-11 
  85. *********************************************************************/  
  86. void TestLogCase_One()  
  87. {  
  88.     FILE *pFile = NULL;  
  89.  char *pFieldContent = NULL;  
  90.  char szFileName[] = "test_case.txt";  
  91.  pFieldContent = (char *)malloc(TEST_CASE_MAX_FILE_LEN);  
  92.  if(NULL == pFieldContent)  
  93.  {  
  94.   Write_Log(LOG_TYPE_ERROR, "malloc memory failed,program exit!");  
  95.   return;  
  96.  }  
  97.  memset(pFieldContent, 0, TEST_CASE_MAX_FILE_LEN);  
  98.  Write_Log(LOG_TYPE_INFO, "malloc memory for pFiled successful,memory size is: %ld",  
  99.   TEST_CASE_MAX_FILE_LEN);  
  100.  pFile = fopen(szFileName, "r");  
  101.  if(NULL == pFile)  
  102.  {  
  103.   fprintf(stderr, "open file failed.");  
  104.         Write_Log(LOG_TYPE_ERROR, "Open file %s failed. program exit!", szFileName);  
  105.   return;  
  106.  }  
  107.     Write_Log(LOG_TYPE_INFO, "Open file %s successful.", szFileName);  
  108.  fread(pFieldContent, 1, TEST_CASE_MAX_FILE_LEN, pFile);  
  109.     pFieldContent[TEST_CASE_MAX_FILE_LEN -1] = '/0';  
  110.    
  111.  fclose(pFile);  
  112.       
  113.  printf("The file %s content is: /n%s/n", szFileName,  pFieldContent);  
  114.  Write_Log(LOG_TYPE_INFO, "The file %s content is: /n%s/n", szFileName,  pFieldContent);  
  115. }  
  116. /********************************************************************* 
  117. * 函数名称:void Write_Log(unsigned int uiLogType, char *pstrFmt, ...) 
  118. * 说明:日志写函数,支持变长参数 
  119. * 调用者:任何需要写日志的地方 
  120. * 输入参数: 
  121. * unsigned iType --  日志类别 
  122. * char *pstrFmt  --  日志内容 
  123. * ...            --  变长参数 
  124. * 输出参数: 
  125. * 无 
  126. * 返回值: 
  127. * void  --  
  128. * 作者: duanyongxing 
  129. * 时间 : 2009-10-11 
  130. *********************************************************************/  
  131. void Write_Log(unsigned int uiLogType, char *pstrFmt, ...)  
  132. {  
  133.    #if _LOG_WRITE_STATE_   /* 写日志与否的编译开关*/   
  134.    LOG_DATA data;  
  135.    time_t curTime;  
  136.    struct tm *mt;  
  137.    va_list v1;  
  138.    memset(&data, 0, sizeof(LOG_DATA));  
  139.    va_start(v1, pstrFmt);  
  140.    _vsnprintf(data.strText, MAX_LOGTEXT_LEN, pstrFmt, v1);  
  141.    va_end(v1);  
  142.    data.iType = uiLogType;  
  143.    curTime = time(NULL);  
  144.    mt = localtime(&curTime);  
  145.    strftime(data.strDate, sizeof(data.strDate), "%Y-%m-%d", mt);  
  146.    strftime(data.strTime, sizeof(data.strTime), "%H:%M:%S", mt);  
  147.    Write_Log_Text(&data);  
  148.    #endif _LOG_WRITE_STATE_   
  149. }  
  150. /********************************************************************* 
  151. * 函数名称:int  GetLogPath(char *pStrPath) 
  152. * 说明:获取日志文件路径 
  153. * 调用者:Write_Log_Text 
  154. * 输入参数: 
  155. * 无 
  156. * 输出参数: 
  157. * char *pStrPath 
  158. * 返回值: 
  159. * int  -- LOG_FAILED:  失败 
  160. *      -- LOG_SUCCESS: 成功 
  161. * 作者: duanyongxing 
  162. * 时间 : 2009-10-11 
  163. *********************************************************************/  
  164. int  GetLogPath(char *pStrPath)  
  165. {  
  166.  if(NULL == pStrPath)  
  167.  {  
  168.   return LOG_FAILED;  
  169.  }  
  170.     int iRet = 0;  
  171.  time_t curTime = time(NULL);  
  172.  struct tm *mt = localtime(&curTime);  
  173.     /* 根据日期组成文件夹名称*/  
  174.  sprintf(pStrPath, "%s//%d%02d%02d", g_LogRootPath, mt->tm_year + 1900,  
  175.       mt->tm_mon + 1, mt->tm_mday);  
  176.     iRet = Create_LogDir(pStrPath);  
  177.  return iRet;  
  178. }  
  179. /********************************************************************* 
  180. * 函数名称:int GetLogFileName(int iLogType, const char *pStrPath, char *pStrName) 
  181. * 说明:获取日志文件名 
  182. * 调用者:Write_Log_Text 
  183. * 输入参数: 
  184. * int iLogType         -- 日志类型 3种:INFO(0)/ERROR(1)/SYSTEM(2) 
  185. * const char *pStrPath -- 日志路径 由GetLogPath得到 
  186. * 输出参数: 
  187. * char *pStrName       -- 日志文件名 
  188. * 返回值: 
  189. * int  -- LOG_FAILED:  失败 
  190. *      -- LOG_SUCCESS: 成功 
  191. * 作者: duanyongxing 
  192. * 时间 : 2009-10-11 
  193. *********************************************************************/  
  194. int GetLogFileName(int iLogType, const char *pStrPath, char *pStrName)  
  195. {  
  196.  if(NULL == pStrPath)  
  197.  {  
  198.   return LOG_FAILED;  
  199.  }  
  200.  char szLogName[MAX_FILE_PATH];  
  201.  FILE *pFile = NULL;  
  202.  memset(szLogName, 0, MAX_FILE_PATH);  
  203.  switch (iLogType)  
  204.  {  
  205.    case LOG_TYPE_INFO:  
  206.     sprintf(szLogName, "%s//app_info", pStrPath);  
  207.     break;  
  208.    case LOG_TYPE_ERROR:  
  209.     sprintf(szLogName, "%s//app_error", pStrPath);  
  210.     break;  
  211.    case LOG_TYPE_SYSTEM:  
  212.     sprintf(szLogName, "%s//app_system", pStrPath);  
  213.     break;  
  214.       default:  
  215.     return LOG_FAILED;  
  216.     break;  
  217.  }  
  218.  strcat(szLogName, ".log");  
  219.  if(IsFileExist(szLogName))  
  220.  {  
  221.   /* 如果文件长度大于指定的最大长度,重新创建一文件,覆盖原文件*/  
  222.         if((int)GetFileLenth(szLogName) + 256 >= MAX_LOG_FILE_SIZE)  
  223.   {  
  224.    Create_LogFile(szLogName, 0);  
  225.   }  
  226.  }  
  227.  else  
  228.  {  
  229.   Create_LogFile(szLogName, 0);  
  230.  }  
  231.       
  232.  sprintf(pStrName, "%s", szLogName);  
  233.  return LOG_SUCCESS;  
  234. }  
  235. /********************************************************************* 
  236. * 函数名称:int Create_LogDir(const char *pStrPath) 
  237. * 说明:创建日志存放路径 
  238. * 调用者:GetLogPath 
  239. * 输入参数: 
  240. * const char *pStrPath --用户指定的根路径 
  241. * 输出参数: 
  242. * 无 
  243. * 返回值: 
  244. * int  -- LOG_FAILED:  失败 
  245. *      -- LOG_SUCCESS: 成功 
  246. * 作者: duanyongxing 
  247. * 时间 : 2009-10-11 
  248. *********************************************************************/  
  249. int Create_LogDir(const char *pStrPath)  
  250. {  
  251.  if(NULL == pStrPath)  
  252.  {  
  253.   return LOG_FAILED;  
  254.  }  
  255.  int iRet = 0;  
  256.  char szSub[MAX_FILE_PATH];  
  257.  char *pSub = NULL;  
  258.  int iIndex = 0;  
  259.  int iLen = 0;  
  260.  int bFind = 0;  
  261.  memset(szSub, 0, sizeof(MAX_FILE_PATH));  
  262.       
  263.  /* 逐层创建目录*/  
  264.  while(1)  
  265.  {  
  266.   pSub = strchr(pStrPath + iLen, '//');  
  267.   if(NULL == pSub)  
  268.   {  
  269.    if(iLen == 0)  
  270.    {  
  271.     return LOG_FAILED;  
  272.    }  
  273.    iRet = CreateDirectory(pStrPath, NULL);  
  274.    if(0 == iRet)  
  275.    {  
  276.     iRet = GetLastError();  
  277.     if(ERROR_ALREADY_EXISTS == iRet)  
  278.     {  
  279.      return LOG_SUCCESS;  
  280.     }  
  281.     return LOG_FAILED;  
  282.    }  
  283.    return LOG_SUCCESS;  
  284.   }  
  285.   else  
  286.   {  
  287.    if (!bFind)  
  288.    {  
  289.     bFind = 1;  
  290.    }  
  291.    else  
  292.    {  
  293.     memset(szSub, 0, sizeof(szSub));  
  294.     strncpy(szSub, pStrPath, pSub - pStrPath);  
  295.     CreateDirectory(szSub, NULL);  
  296.    }  
  297.    iLen = pSub - pStrPath + 1;  
  298.   }  
  299.  }  
  300.  return LOG_SUCCESS;  
  301. }  
  302. /********************************************************************* 
  303. * 函数名称:int Create_LogFile(const char *pStrFile, int iPos) 
  304. * 说明:创建日志文件 
  305. * 调用者:GetLogFileName 
  306. * 输入参数: 
  307. * const char *pStrFile --文件名 
  308. * int iPos             --文件指针位置 
  309. * 输出参数: 
  310. * 无 
  311. * 返回值: 
  312. * int  -- LOG_FAILED:  失败 
  313. *      -- LOG_SUCCESS: 成功 
  314. * 作者: duanyongxing 
  315. * 时间 : 2009-10-11 
  316. *********************************************************************/  
  317. int Create_LogFile(const char *pStrFile, int iPos)  
  318. {  
  319.  HANDLE hd = 0;  
  320.  int iRet = 0;  
  321.  if(NULL == pStrFile)  
  322.  {  
  323.   return LOG_FAILED;  
  324.  }  
  325.  hd = CreateFile(pStrFile,   
  326.               GENERIC_READ | GENERIC_WRITE,  
  327.      0,  
  328.      NULL,  
  329.      CREATE_ALWAYS,  
  330.      FILE_ATTRIBUTE_NORMAL,  
  331.      NULL  
  332.      );  
  333.  if(INVALID_HANDLE_VALUE == hd)  
  334.  {  
  335.   return LOG_FAILED;  
  336.  }  
  337.     if(DWORD_NULL == SetFilePointer(hd, iPos, NULL, FILE_BEGIN))  
  338.  {  
  339.   return LOG_FAILED;  
  340.  }  
  341.  iRet = SetEndOfFile(hd);  
  342.  CloseHandle(hd);  
  343.  return iRet;  
  344. }  
  345. /********************************************************************* 
  346. * 函数名称:int IsFileExist(const char *pStrFile) 
  347. * 说明:判断指定的文件是否存在 
  348. * 调用者:GetLogFileName 
  349. * 输入参数: 
  350. * const char *pStrFile --文件名 
  351. * 输出参数: 
  352. * 无 
  353. * 返回值: 
  354. * int  -- LOG_BOOL_FALSE:  不存在 
  355. *      -- LOG_BOOL_TRUE: 存在 
  356. * 作者: duanyongxing 
  357. * 时间 : 2009-10-11 
  358. *********************************************************************/  
  359. int IsFileExist(const char *pStrFile)  
  360. {  
  361.  int iLen = 0;  
  362.  WIN32_FIND_DATA finddata;  
  363.  memset(&finddata, 0, sizeof(WIN32_FIND_DATA));  
  364.  HANDLE hd = FindFirstFile(pStrFile, &finddata);  
  365.  if(INVALID_HANDLE_VALUE == hd)  
  366.  {  
  367.   DWORD dwRet = GetLastError();  
  368.   if(ERROR_FILE_NOT_FOUND == dwRet || ERROR_PATH_NOT_FOUND == dwRet)  
  369.   {  
  370.    return LOG_BOOL_FALSE;  
  371.   }  
  372.  }  
  373.  FindClose(hd);  
  374.  return LOG_BOOL_TRUE;  
  375. }  
  376. /********************************************************************* 
  377. * 函数名称:DWORD GetFileLenth(const char *pFile) 
  378. * 说明:判断指定的文件大小 
  379. * 调用者:GetLogFileName 
  380. * 输入参数: 
  381. * const char *pFile --文件名 
  382. * 输出参数: 
  383. * 无 
  384. * 返回值: 
  385. * DWORD -- 文件大小 
  386. * 作者: duanyongxing 
  387. * 时间 : 2009-10-11 
  388. *********************************************************************/  
  389. DWORD GetFileLenth(const char *pFile)  
  390. {  
  391.  WIN32_FIND_DATA buff;  
  392.  HANDLE hd = NULL;  
  393.  memset(&buff, 0, sizeof(WIN32_FIND_DATA));  
  394.  hd = FindFirstFile(pFile, &buff);  
  395.  FindClose(hd);  
  396.  return (buff.nFileSizeHigh * MAXDWORD) + buff.nFileSizeLow;  
  397. }  
  398. /********************************************************************* 
  399. * 函数名称:int Write_Log_Text(LPLOG_DATA lpLogData) 
  400. * 说明:写日志内容 
  401. * 调用者:Write_Log 
  402. * 输入参数: 
  403. * LPLOG_DATA lpLogData --日志内容结构体量 
  404. * 输出参数: 
  405. * 无 
  406. * 返回值: 
  407. * int  -- LOG_FAILED:  失败 
  408. *      -- LOG_SUCCESS: 成功 
  409. * 作者: duanyongxing 
  410. * 时间 : 2009-10-11 
  411. *********************************************************************/  
  412. int Write_Log_Text(LPLOG_DATA lpLogData)  
  413. {  
  414.     char szFilePath[MAX_FILE_PATH];  
  415.  char szFileName[MAX_LOG_FILE_NAME_LEN];  
  416.  FILE *pFile = NULL;  
  417.  char szLogText[MAX_LOGTEXT_LEN];  
  418.  memset(szFilePath, 0, MAX_FILE_PATH);  
  419.  memset(szFileName, 0, MAX_LOG_FILE_NAME_LEN);  
  420.  memset(szLogText, 0, MAX_LOGTEXT_LEN);  
  421.  GetLogPath(szFilePath);  
  422.  GetLogFileName(lpLogData->iType, szFilePath, szFileName);  
  423.  pFile = fopen(szFileName, "a+");  
  424.     if(NULL == pFile)  
  425.  {  
  426.         return LOG_FAILED;  
  427.  }  
  428.  sprintf(szLogText, "%s %s %s/n", lpLogData->strDate, lpLogData->strTime,  
  429.    lpLogData->strText);  
  430.  fwrite(szLogText, 1, strlen(szLogText), pFile);  
  431.  fclose(pFile);  
  432.  return LOG_SUCCESS;  
  433. }  

相关内容