程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> 關於C >> 簡單的分級別寫日志程序

簡單的分級別寫日志程序

編輯:關於C
/************************************************************************/ 
/*
  * 文件名稱: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的專欄
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved