/************************************************************************/  
/*    
  * 文件名称:write_log.cpp    
  * 摘    
要:此文件实现了普通WINDOWS程序中的日志功能    
  
*           主要有以下特点:    
  *           1. 
根据日期创建日志文件目录,每天的日志分别存放在不同的日志目录中;    
  
*           2. 
日志内容分三种类型,根据不同需要,写不同的日志类型的日志文件,    
  
*              
方便通过日志定位、分析问题;    
  
*           3. 
函数经过比较好的封装,便于复用;    
  
*           待改进点:    
  *           1. 
为了方便,日志内容打印时使用了time函数,其精确度较低;    
  
*           2. 
可将这些函数封装为一个日志类,或者动态库,使其更通用;    
  
*           3. 
没有考虑跨平台情景,目前只使用于WINDOWS下    
  
*           4. 
日志文件内容还可进一步改进,比如打印出当前文件名与行号,使用日志功能    
  
*              
更加实用;    
  *    
  * 当前版本:1.0    
  * 
作    者:duanyongxing  
  * 完成日期:2009年10月11日    
*/                                                                       
/************************************************************************/  
#ifndef __WRITELOG_H__   
#define __WRITELOG_H__   
#include "stdafx.h"   
#include <time.h>   
#include <memory.h>   
#include 
<stdio.h>   
#include <stdlib.h>    
#include <stdarg.h>   
#include 
<windows.h>   
#define _LOG_WRITE_STATE_ 
1            /* 
条件编译开关,1:写日志,0:不写日志 */   
#define LOG_SUCCESS (0)   
#define LOG_FAILED  (-1)   
#define LOG_BOOL_TRUE 
(1)   
#define LOG_BOOL_FALSE (0)   
#define 
DWORD_NULL  (0xFFFFFFFF)   
#define MAX_LOGTEXT_LEN 
(2048)         /* 
每行日志的最大长度*/   
#define MAX_FILE_PATH 
(255)            /* 
日志文件路径的最大长度*/   
#define MAX_LOG_FILE_SIZE (512 * 1024) /* 
日志文件内容的最大长度*/   
#define MAX_LOG_FILE_NAME_LEN 
(256)    /* 日志文件名的最大长度*/   
#define 
LOG_TYPE_INFO    
0             /* 
日志类型: 信息类型*/   
#define LOG_TYPE_ERROR   
1             /* 
日志类型: 错误类型*/   
#define LOG_TYPE_SYSTEM  
2             /* 
日志类型: 系统类型*/   
#define 
TEST_CASE_MAX_FILE_LEN (1024)   /* 测试函数中文件内容最大长度*/   
const char g_LogRootPath[] = "C://My_APPLOG"; /*日志文件根路径,由用户指定*/  
#pragma pack(push, 1)   
typedef struct 
tagLOG_DATA             
/* 日志内容结构体*/  
{  
 
char             
strDate[11];   /* 日期:格式为如:2009-10-11*/  
 
char             
strTime[9];    /* 时间:格式为如:16:10:57*/  
 unsigned 
int  iType;         /* 
日志类型:3种:INFO(0)/ERROR(1)/SYSTEM(2)*/  
 
char             
strText[MAX_LOGTEXT_LEN]; /*日志内容*/  
}LOG_DATA, *LPLOG_DATA;  
#pragma pack(pop)   
int Create_LogDir(const char 
*pStrPath);  
int Create_LogFile(const char *pStrFile, int iPos);  
int IsFileExist(const char *pStrFile);  
int GetLogPath(char 
*pStrPath);  
DWORD GetFileLenth(const char *pFile);  
int 
Write_Log_Text(LPLOG_DATA lpLogData);  
void Write_Log(unsigned int 
uiLogType, char *pstrFmt, ...);  
void TestLogCase_One();  
int 
main(int argc, char* argv[])  
{  
    
Write_Log(LOG_TYPE_SYSTEM, "Program begin.");  
 
TestLogCase_One();  
 Write_Log(LOG_TYPE_SYSTEM, "Program end.");  
 return 0;  
}  
/*********************************************************************    
* 函数名称:void TestLogCase_One()    
* 说明:简单的测试函数,读文件    
* 调用者:main    
* 输入参数:    
* 无    
* 输出参数:    
* 无    
* 返回值:    
* 
void  --  
* 作者: duanyongxing    
* 时间 : 2009-10-11    
*********************************************************************/  
void TestLogCase_One()  
{  
    FILE *pFile 
= NULL;  
 char *pFieldContent = NULL;  
 char szFileName[] = 
"test_case.txt";  
 pFieldContent = (char 
*)malloc(TEST_CASE_MAX_FILE_LEN);  
 if(NULL == pFieldContent)  
 {  
  Write_Log(LOG_TYPE_ERROR, "malloc memory failed,program 
exit!");  
  return;  
 }  
 memset(pFieldContent, 
0, TEST_CASE_MAX_FILE_LEN);  
 Write_Log(LOG_TYPE_INFO, "malloc memory 
for pFiled successful,memory size is: %ld",  
  
TEST_CASE_MAX_FILE_LEN);  
 pFile = fopen(szFileName, "r");  
 
if(NULL == pFile)  
 {  
  fprintf(stderr, "open file 
failed.");  
        
Write_Log(LOG_TYPE_ERROR, "Open file %s failed. program exit!", 
szFileName);  
  return;  
 }  
    
Write_Log(LOG_TYPE_INFO, "Open file %s successful.", szFileName);  
 
fread(pFieldContent, 1, TEST_CASE_MAX_FILE_LEN, pFile);  
    pFieldContent[TEST_CASE_MAX_FILE_LEN -1] = ‘/0‘;  
 fclose(pFile);  
 printf("The file %s content is: /n%s/n", 
szFileName,  pFieldContent);  
 Write_Log(LOG_TYPE_INFO, "The file 
%s content is: /n%s/n", szFileName,  pFieldContent);  
}  
/*********************************************************************    
* 函数名称:void Write_Log(unsigned int uiLogType, char *pstrFmt, ...)    
* 
说明:日志写函数,支持变长参数    
* 调用者:任何需要写日志的地方    
* 输入参数:    
* unsigned iType 
--  日志类别    
* char *pstrFmt  --  日志内容    
* 
...            --  
变长参数    
* 输出参数:    
* 无    
* 返回值:    
* void  --  
* 
作者: duanyongxing    
* 时间 : 2009-10-11    
*********************************************************************/  
void Write_Log(unsigned int uiLogType, char *pstrFmt, ...)  
{  
   #if _LOG_WRITE_STATE_   /* 写日志与否的编译开关*/   
   LOG_DATA data;  
   time_t curTime;  
   struct tm *mt;  
   va_list v1;  
   memset(&data, 0, sizeof(LOG_DATA));  
   
va_start(v1, pstrFmt);  
   _vsnprintf(data.strText, 
MAX_LOGTEXT_LEN, pstrFmt, v1);  
   va_end(v1);  
   data.iType = uiLogType;  
   curTime = 
time(NULL);  
   mt = localtime(&curTime);  
   strftime(data.strDate, sizeof(data.strDate), "%Y-%m-%d", 
mt);  
   strftime(data.strTime, sizeof(data.strTime), 
"%H:%M:%S", mt);  
   Write_Log_Text(&data);  
   #endif _LOG_WRITE_STATE_   
}  
/*********************************************************************    
* 函数名称:int  GetLogPath(char *pStrPath)    
* 说明:获取日志文件路径    
* 
调用者:Write_Log_Text    
* 输入参数:    
* 无    
* 输出参数:    
* char 
*pStrPath    
* 返回值:    
* int  -- LOG_FAILED:  失败    
*      -- LOG_SUCCESS: 成功    
* 作者: duanyongxing 
   
* 时间 : 2009-10-11    
*********************************************************************/  
int  GetLogPath(char *pStrPath)  
{  
 if(NULL == 
pStrPath)  
 {  
  return LOG_FAILED;  
 }  
    int iRet = 0;  
 time_t curTime = 
time(NULL);  
 struct tm *mt = localtime(&curTime);  
    /* 根据日期组成文件夹名称*/  
 sprintf(pStrPath, 
"%s//%d%02d%02d", g_LogRootPath, mt->tm_year + 1900,  
      mt->tm_mon + 1, mt->tm_mday);  
    iRet = Create_LogDir(pStrPath);  
 return 
iRet;  
}  
/*********************************************************************    
* 函数名称:int GetLogFileName(int iLogType, const char *pStrPath, char 
*pStrName)    
* 说明:获取日志文件名    
* 调用者:Write_Log_Text    
* 输入参数:    
* int iLogType         -- 日志类型 
3种:INFO(0)/ERROR(1)/SYSTEM(2)    
* const char *pStrPath -- 日志路径 
由GetLogPath得到    
* 输出参数:    
* char 
*pStrName       -- 日志文件名    
* 返回值:    
* 
int  -- LOG_FAILED:  失败    
*      -- 
LOG_SUCCESS: 成功    
* 作者: duanyongxing    
* 时间 : 2009-10-11    
*********************************************************************/  
int GetLogFileName(int iLogType, const char *pStrPath, char *pStrName)  
{  
 if(NULL == pStrPath)  
 {  
  return 
LOG_FAILED;  
 }  
 char szLogName[MAX_FILE_PATH];  
 
FILE *pFile = NULL;  
 memset(szLogName, 0, MAX_FILE_PATH);  
 
switch (iLogType)  
 {  
   case LOG_TYPE_INFO:  
    sprintf(szLogName, "%s//app_info", pStrPath);  
    break;  
   case LOG_TYPE_ERROR:  
    sprintf(szLogName, "%s//app_error", pStrPath);  
    break;  
   case LOG_TYPE_SYSTEM:  
    sprintf(szLogName, "%s//app_system", pStrPath);  
    break;  
      
default:  
    return LOG_FAILED;  
    break;  
 }  
 strcat(szLogName, 
".log");  
 if(IsFileExist(szLogName))  
 {  
  /* 
如果文件长度大于指定的最大长度,重新创建一文件,覆盖原文件*/  
        if((int)GetFileLenth(szLogName) + 
256 >= MAX_LOG_FILE_SIZE)  
  {  
   
Create_LogFile(szLogName, 0);  
  }  
 }  
 
else  
 {  
  Create_LogFile(szLogName, 0);  
 
}  
 sprintf(pStrName, "%s", szLogName);  
 return 
LOG_SUCCESS;  
}  
/*********************************************************************    
* 函数名称:int Create_LogDir(const char *pStrPath)    
* 说明:创建日志存放路径    
* 
调用者:GetLogPath    
* 输入参数:    
* const char *pStrPath --用户指定的根路径    
* 
输出参数:    
* 无    
* 返回值:    
* int  -- LOG_FAILED:  失败    
*      -- LOG_SUCCESS: 成功    
* 作者: duanyongxing 
   
* 时间 : 2009-10-11    
*********************************************************************/  
int Create_LogDir(const char *pStrPath)  
{  
 if(NULL == 
pStrPath)  
 {  
  return LOG_FAILED;  
 }  
 int iRet = 0;  
 char szSub[MAX_FILE_PATH];  
 char *pSub = 
NULL;  
 int iIndex = 0;  
 int iLen = 0;  
 int bFind = 
0;  
 memset(szSub, 0, sizeof(MAX_FILE_PATH));  
 /* 
逐层创建目录*/  
 while(1)  
 {  
  pSub = 
strchr(pStrPath + iLen, ‘//‘);  
  if(NULL == pSub)  
  {  
   if(iLen == 0)  
   {  
    return LOG_FAILED;  
   }  
   iRet = CreateDirectory(pStrPath, NULL);  
   
if(0 == iRet)  
   {  
    iRet = 
GetLastError();  
    if(ERROR_ALREADY_EXISTS == 
iRet)  
    {  
     return 
LOG_SUCCESS;  
    }  
    return 
LOG_FAILED;  
   }  
   return 
LOG_SUCCESS;  
  }  
  else  
  {  
   if (!bFind)  
   {  
    bFind = 1;  
   }  
   else  
   {  
    
memset(szSub, 0, sizeof(szSub));  
    strncpy(szSub, 
pStrPath, pSub - pStrPath);  
    CreateDirectory(szSub, 
NULL);  
   }  
   iLen = pSub - pStrPath + 
1;  
  }  
 }  
 return LOG_SUCCESS;  
}  
/*********************************************************************    
* 函数名称:int Create_LogFile(const char *pStrFile, int iPos)    
* 说明:创建日志文件 
   
* 调用者:GetLogFileName    
* 输入参数:    
* const char *pStrFile --文件名   
 
* int 
iPos             
--文件指针位置    
* 输出参数:    
* 无    
* 返回值:    
* int  -- 
LOG_FAILED:  失败    
*      -- LOG_SUCCESS: 成功   
 
* 作者: duanyongxing    
* 时间 : 2009-10-11    
*********************************************************************/  
int Create_LogFile(const char *pStrFile, int iPos)  
{  
 
HANDLE hd = 0;  
 int iRet = 0;  
 if(NULL == pStrFile)  
 {  
  return LOG_FAILED;  
 }  
 hd = 
CreateFile(pStrFile,   
              
GENERIC_READ | GENERIC_WRITE,  
     0,  
     NULL,  
     
CREATE_ALWAYS,  
     FILE_ATTRIBUTE_NORMAL,  
     NULL  
     );  
 if(INVALID_HANDLE_VALUE == hd)  
 {  
  return 
LOG_FAILED;  
 }  
    if(DWORD_NULL == 
SetFilePointer(hd, iPos, NULL, FILE_BEGIN))  
 {  
  return 
LOG_FAILED;  
 }  
 iRet = SetEndOfFile(hd);  
 
CloseHandle(hd);  
 return iRet;  
}  
/*********************************************************************    
* 函数名称:int IsFileExist(const char *pStrFile)    
* 说明:判断指定的文件是否存在    
* 调用者:GetLogFileName    
* 输入参数:    
* const char *pStrFile --文件名    
* 输出参数:    
* 无    
* 返回值:    
* int  -- LOG_BOOL_FALSE:  
不存在    
*      -- LOG_BOOL_TRUE: 存在    
* 作者: 
duanyongxing    
* 时间 : 2009-10-11    
*********************************************************************/  
int IsFileExist(const char *pStrFile)  
{  
 int iLen = 
0;  
 WIN32_FIND_DATA finddata;  
 memset(&finddata, 0, 
sizeof(WIN32_FIND_DATA));  
 HANDLE hd = FindFirstFile(pStrFile, 
&finddata);  
 if(INVALID_HANDLE_VALUE == hd)  
 {  
  DWORD dwRet = GetLastError();  
  
if(ERROR_FILE_NOT_FOUND == dwRet || ERROR_PATH_NOT_FOUND == dwRet)  
  {  
   return LOG_BOOL_FALSE;  
  
}  
 }  
 FindClose(hd);  
 return LOG_BOOL_TRUE;  
}  
/*********************************************************************    
* 函数名称:DWORD GetFileLenth(const char *pFile)    
* 说明:判断指定的文件大小    
* 
调用者:GetLogFileName    
* 输入参数:    
* const char *pFile --文件名    
* 
输出参数:    
* 无    
* 返回值:    
* DWORD -- 文件大小    
* 作者: duanyongxing  
  
* 时间 : 2009-10-11    
*********************************************************************/  
DWORD GetFileLenth(const char *pFile)  
{  
 WIN32_FIND_DATA 
buff;  
 HANDLE hd = NULL;  
 memset(&buff, 0, 
sizeof(WIN32_FIND_DATA));  
 hd = FindFirstFile(pFile, &buff);  
 FindClose(hd);  
 return (buff.nFileSizeHigh * MAXDWORD) + 
buff.nFileSizeLow;  
}  
/*********************************************************************    
* 函数名称:int Write_Log_Text(LPLOG_DATA lpLogData)    
* 说明:写日志内容    
* 
调用者:Write_Log    
* 输入参数:    
* LPLOG_DATA lpLogData --日志内容结构体量    
* 
输出参数:    
* 无    
* 返回值:    
* int  -- LOG_FAILED:  失败    
*      -- LOG_SUCCESS: 成功    
* 作者: duanyongxing 
   
* 时间 : 2009-10-11    
*********************************************************************/  
int Write_Log_Text(LPLOG_DATA lpLogData)  
{  
    char szFilePath[MAX_FILE_PATH];  
 char 
szFileName[MAX_LOG_FILE_NAME_LEN];  
 FILE *pFile = NULL;  
 
char szLogText[MAX_LOGTEXT_LEN];  
 memset(szFilePath, 0, 
MAX_FILE_PATH);  
 memset(szFileName, 0, MAX_LOG_FILE_NAME_LEN);  
 memset(szLogText, 0, MAX_LOGTEXT_LEN);  
 
GetLogPath(szFilePath);  
 GetLogFileName(lpLogData->iType, 
szFilePath, szFileName);  
 pFile = fopen(szFileName, "a+");  
    if(NULL == pFile)  
 {  
        return LOG_FAILED;  
 
}  
 sprintf(szLogText, "%s %s %s/n", lpLogData->strDate, 
lpLogData->strTime,  
   lpLogData->strText);  
 
fwrite(szLogText, 1, strlen(szLogText), pFile);  
 fclose(pFile);  
 return LOG_SUCCESS;  
}  
摘自 Socrates的专栏
原文地址:http://www.cnblogs.com/lizs/p/3718851.html