C++分级别写日志代码

 转自: http://hi.baidu.com/jakmax/blog/item/42f95d185039c6b94bedbc56.html
/************************************************************************/
/*
* 文件名称:write_log.cpp
* 摘    要:此文件实现了普通WINDOWS程序中的日志功能
*           主要有以下特点:
*           1. 根据日期创建日志文件目录,每天的日志分别存放在不同的日志目录中;
*           2. 日志内容分三种类型,根据不同需要,写不同的日志类型的日志文件,
*              方便通过日志定位、分析问题;
*           3. 函数经过比较好的封装,便于复用;
*           待改进点:
*           1. 为了方便,日志内容打印时使用了time函数,其精确度较低;
*           2. 可将这些函数封装为一个日志类,或者动态库,使其更通用;
*           3. 没有考虑跨平台情景,目前只使用于WINDOWS下 
*           4. 日志文件内容还可进一步改进,比如打印出当前文件名与行号,使用日志功能
*              更加实用;
*
*/                                                                    
/************************************************************************/
#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 --
*********************************************************************/
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 --
*********************************************************************/
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: 成功
*********************************************************************/
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: 成功
*********************************************************************/
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: 成功
*********************************************************************/
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: 成功
*********************************************************************/
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: 存在
*********************************************************************/
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 -- 文件大小
*********************************************************************/
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: 成功
*********************************************************************/
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值