欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

简单的分级别写日志程序

程序员文章站 2022-06-07 20:41:31
/************************************************************************/  /* &nbs...
/************************************************************************/ 
/*
  * 文件名称: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的专栏