/**********************************************************************
* 版权所有 (C)2015, 王茂春。
*
* 文件名称:WriteLog.c
* 文件标识:无
* 内容摘要:演示日志信息的打印方法
* 其它说明:无
第一,本文中对日志信息的写入采用的是直接在日志文件后面追加的方式,因此每次测试之前,要在“log”目录下删除上一次产生的“WriteLog.log”文件,
否则新的日志信息会写入旧的日志文件中。
第二,由于写日志函数WriteLogFile的入参较多,每次调用的时候编写代码较为繁琐,因此使用一个宏WRITELOGFILE来代替,且只需要带上日志等级和日志消息两个参数即可,
其它的如代码文件名、函数名和代码行数直接使用系统自定义的宏即可。
* 完成日期:20160522
*
**********************************************************************/
#include <stdio.h>
#include <
string.h>
#include <time.h>
#include <sys/time.h>
// 函数宏定义
#define WriteLogFile(level, msg) writeLog((char *)__FILE__, (char *)__FUNCTION__, __LINE__, level, (char *)msg)
// 全局变量
typedef
char INT8;
INT8 LogFileName[100] =
"WriteLog.log";
// 带路径的日志文件名
// 函数声明
void writeLog(
char *pFileName,
char *pFunctionName,
int iCodeLine,
int iLogLevel,
char *
pContent);
void GetTime(
char *
pszTimeStr);
/**********************************************************************
* 功能描述: 获取时间串
* 输入参数: pszTimeStr-时间串
* 输出参数: pszTimeStr-时间串
* 返 回 值: 无
* 其它说明: 时间串样式: YYYY.MM.DD HH:MIN:SS.Usec
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 2016年5月22日 V1.0 王茂春 创建
********************************************************************/
void GetTime(
char *
pszTimeStr)
{
struct tm tSysTime = {
0};
struct timeval tTimeVal = {
0};
time_t tCurrentTime = {
0};
INT8 szUsec[20] = {
0};
// 微秒
INT8 szMsec[
20] = {
0};
// 毫秒
if (pszTimeStr ==
NULL)
{
return;
}
tCurrentTime =
time(NULL);
localtime_r(&tCurrentTime, &tSysTime);
// localtime_r是线程安全的
gettimeofday(&
tTimeVal, NULL);
sprintf(szUsec, "ld", tTimeVal.tv_usec);
// 获取微秒
strncpy(szMsec, szUsec,
3);
// 微秒的前3位为毫秒(1毫秒=1000微秒)
sprintf(pszTimeStr, "[d.d.d d:d:d.%3.3s]",
tSysTime.tm_year+
1900, tSysTime.tm_mon+
1, tSysTime.tm_mday,
tSysTime.tm_hour, tSysTime.tm_min, tSysTime.tm_sec, szMsec);
}
/**********************************************************************
* 功能描述: 将内容写到日志文件中
* 输入参数: pFileName-代码文件名
pFunctionName-代码所在函数名
iCodeLine-代码行
iLogLevel-日志等级(0,1,2,3)
pContent-每条日志的具体内容
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20160522 V1.0 王茂春 创建
********************************************************************/
void writeLog(
char *pFileName,
char *pFunctionName,
int iCodeLine,
int iLogLevel,
char *
pContent)
{
char szTimeStr[
128] = {
0};
char szLogContent[
128] = {
0};
FILE *fp =
NULL;
//判断文件名,函数名,日志文件名是否为空
if (pFileName == NULL || pFunctionName == NULL || LogFileName ==
NULL )
{
printf("eer");
return;
}
fp = fopen(LogFileName,
"at+");
// 打开文件, 每次写入的时候在后面追加
if (fp ==
NULL)
{
return;
}
// 先打印版本相关信息
//snprintf(szLogContent, sizeof(szLogContent)-1, "/******Version [1.0], Build time[%s %s].****/\n", __DATE__, __TIME__);
//fputs(szLogContent, fp);
// 写入日志时间
GetTime(szTimeStr);
fputs(szTimeStr, fp);
//在日志信息中显示"文件名/函数名/代码行数"信息
//0 === 严重错误
if (
0 ==
iLogLevel)
{
snprintf(szLogContent, sizeof(szLogContent)-
1,
"[%s][%s][d][%s]%s\n", pFileName, pFunctionName, iCodeLine,
"LOG_FATAL", pContent);
}
//1 === 一般错误
if(
1 ==
iLogLevel)
{
snprintf(szLogContent, sizeof(szLogContent)-
1,
"[%s][%s][d][%s]%s\n", pFileName, pFunctionName, iCodeLine,
"LOG_ERROR", pContent);
}
//2 === 警告
if(
2 ==
iLogLevel)
{
snprintf(szLogContent, sizeof(szLogContent)-
1,
"[%s][%s][d][%s]%s\n", pFileName, pFunctionName, iCodeLine,
"LOG_WARN", pContent);
}
//3 === 一般信息
if(
3 ==
iLogLevel)
{
snprintf(szLogContent, sizeof(szLogContent)-
1,
"[%s][%s][d][%s]%s\n", pFileName, pFunctionName, iCodeLine,
"LOG_INFO", pContent);
}
fputs(szLogContent, fp);
fflush(fp); // 刷新文件
fclose(fp);
// 关闭文件
fp = NULL;
// 将文件指针置为空
return;
}
void test()
{
WriteLogFile(2,
"hhh----fun");
WriteLogFile(3,
"hhh----fun");
}
int main()
{
WriteLogFile(0,
"hhh----main");
WriteLogFile(1,
"hhh----main");
test();
}
本文借鉴 周兆雄 博客,写一个自己的简单的日志文件。
优点:
1. 仅仅提供三个入口:日志文件名、错误等级、错误信息,其他(所属文件名,函数名,所在行,错误等级字符均隐藏)
2. 使用了宏定义函数,简化函数操作
3.文件操作使用snprintf比sprintf更优秀。
缺点:
1.文件采用无限追加模式,每次运行前需要删除日志
2.原博客也是对“const char *"转换为”char ")经常错误出现,这里的解决办法使用强制转换,比如:
writeLog((
char *)__FILE__, (
char *)__FUNCTION__, __LINE__, level, (
char *)msg)
3.本文为了简便起见,对错误等级使用if判断,而没有使用switch语句,笨方法。
转载于:https://www.cnblogs.com/shuqingstudy/p/5516603.html