Linux中调试程序使用打印日志纠错的技巧
2011-02-28 20:46
951 查看
写程序的过程中肯定会遇到错误,怎么去发现错误?简单的办法是自己去看代码的执行过程,发现一些错误所在
的点。但是很多时候这一招不管用,怎么办?只好在关键点上使用printf函数去打印一些变量的值或提示信息来发现一
些错误。最后当然是使用gdb去调试啦,不过gdb不是今天的主角。而是怎么简单的使用printf来记录和分类一些程序
日志信息。
下面我将介绍下怎么使用printf打印一些日志,让我们在调试的时候更快的发现程序的错误。我们约定可以使用
[ERRORS] ,[WARNINGS] ,[INFO]标识分别来区分错误,警告,信息三类日志信息,例如:
fd=open("/home/user/debug/config.ini",O_RDONLY);
if(fd<=0)
{
printf("[ERRORS][OpenFile.c][Init()] open file failed!/n");
return EXCEPTION;
}
复制代码
在 printf("[ERRORS][OpenFile.c][Init()] open file failed!/n")中我们可以明确知道的信息是当前打印的改行日志是
属于错误日志,位于文件OpenFile.c的Init()函数当中。
int Ret;
char szText[1024];
Ret=0;
memset(szText,0,sizeof(szText));
#ifdef __DEBUG__
printf("[INFO][Convertion.c][Convert()] Before Convert:%s/n",szText);
#endif
nRet=Convert(szText);
if(nRet==EXCEPTION)
{
printf("[INFO][Convertion.c][Convert()] Convert failed!/n");
return EXCEPTION;
}
#ifdef __DEBUG__
printf("[INFO][Convertion.c][Convert()] After Convert:%s/n",szText);
#endif
复制代码
在这段代码中,我们可以通过在对用头文件中添加#define __DEBUG__的宏定义来达到打印调试日志信息。
下面为大家提供本人自己整理的一个比较成熟日志打印程序:
说明:
程序运行会在$HOME/mysrc/test路径下创建一个名为log的文件夹,之后会在log文件夹下创建以当天
系统时间为名称的日志文件,例如系统时间为2011年2月19日,则当天的日志文件名为:20110219.log。
/*********************************************************
*Author: lizhangjie
*Date: 2011-02-15
*Description: Log Printging Functions
*********************************************************/
#include "pub.h"
/*这个是全局日志文件指针,定义并初始化*/
static FILE *gpLogFile=NULL;
char *GetSystemTime()
{
struct tm struTmNow;
time_t struTimeNow;
static char szSystemTime[128];
memset(szSystemTime,'/0',sizeof(szSystemTime));
if(time(&struTimeNow)==(time_t)-1)
{
printf("[ERRORS][Log.c][SystemTime()] time() failed!/n");
return NULL;
}
/*转换成本地时间*/
struTmNow=*localtime(&struTimeNow);
sprintf(szSystemTime,"%04d%02d%02d",struTmNow.tm_year+1900,/
struTmNow.tm_mon+1,struTmNow.tm_mday);
#ifdef __DEBUG__
printf("[INFO][Log.c][SystemTime()] 成功获取系统时间:%s/n",szSystemTime);
#endif
return szSystemTime;
}
char *GetPrtLogFileName()
{
/*definition*/
struct tm struTmNow;
time_t struTimeNow;
static char szFileName[256];
/*initializing*/
memset(szFileName,0,sizeof(szFileName));
if(time(&struTimeNow)==(time_t)-1)
{
printf("[ERRORS][Log.c][GetPrtLogFileName()] time() failed!/n");
return NULL;
}
struTmNow=*localtime(&struTimeNow);
sprintf(szFileName,"%04d%02d%02d.log",struTmNow.tm_year+1900,/
struTmNow.tm_mon+1,struTmNow.tm_mday);
#ifdef __DEBUG__
printf("[INFO][Log.c][GetPrtLogFileName()] 成功组成文件名:%s/n",szFileName);
#endif
return szFileName;
}
int InitPrtLogFile()
{
/*definition*/
/*日志文件路径*/
char szFilePath[256];
static char szFileName[256];
/*initializing*/
memset(szFilePath,0,sizeof(szFilePath));
memset(szFileName,0,sizeof(szFilePath));
/*如果日志文件已打开,返回NORMAL*/
if(gpLogFile!=NULL)
{
if(access(szFileName,F_OK|W_OK)==0)
{
if(strcmp(szFileName,GetPrtLogFileName())==0)
{
printf("[INFO][Log.c][InitPrtLogFile()] 日志文件已存在!/n");
return NORMAL;
}
}
}
/*获取HOME环境变量*/
if(getenv("HOME"))
{
/*log日志文件夹路径位于$HOME/log*/
sprintf(szFilePath,"%s/mysrc/test/log",getenv("HOME"));
#ifdef __DEBUG__
printf("组成路径:%s/n",szFilePath);
#endif
/*在指定目录下创建文件夹*/
if((mkdir(szFilePath,S_IRUSR|S_IWUSR|S_IXUSR)==-1)&&(errno!=EEXIST))
{
printf("[ERRORS][Log.c][InitPtrLogFile()] mkdir() failed!/n");
return EXCEPTION;
}
#ifdef __DEBUG__
printf("[INFO][Log.c][InitPtrLogFile()] log文件夹创建成功!/n");
#endif
sprintf(szFileName,"%s/mysrc/test/log/%s",getenv("HOME"),GetPrtLogFileName());
printf("[INFO][Log.c][InitPrtLogFile()] 路径和文件名获取成功:%s/n",szFileName);
}
else
{
printf("[ERRORS][Log.c][InitPtrLogFile()] getenv() failed!/n");
return EXCEPTION;
}
/*关闭日志文件*/
if(gpLogFile!=NULL)
fclose(gpLogFile);
gpLogFile=fopen(szFileName,"a+");
if(gpLogFile==NULL)
{
printf("[ERRORS][Log.c][InitPtrLogFile()] fopen() failed!/n");
return EXCEPTION;
}
if(chmod(szFileName,S_IRUSR|S_IWUSR)==-1)
{
printf("[ERRORS][Log.c][InitPtrLogFile()] chmod() failed!/n");
return EXCEPTION;
}
return NORMAL;
}
void PrtLog(char *pszDebugStr,char *pszFormatStr,...)
{
/*definition*/
va_list listArg;
static int nFileLineNum;
if(InitPrtLogFile()==NORMAL)
{
va_start(listArg,pszFormatStr);
/*将时间和打印位置写入日志文件*/
fprintf(gpLogFile,"[%s]%s/n/t",GetSystemTime(),pszDebugStr);
/*将日志内容写入日志文件*/
vfprintf(gpLogFile,pszFormatStr,listArg);
va_end(listArg);
/*将内存缓冲中的数据回写到硬盘*/
fflush(gpLogFile);
/*日志文件行数超过限制时做相应处理*/
if(nFileLineNum++>LOG_FILE_MAX_LINE_NUM)
{
/*文件指针重新定位到文件打开时的初始位置*/
fseek(gpLogFile,0,SEEK_SET);
/*日志文件行数清零*/
nFileLineNum=0;
}
}
}
的点。但是很多时候这一招不管用,怎么办?只好在关键点上使用printf函数去打印一些变量的值或提示信息来发现一
些错误。最后当然是使用gdb去调试啦,不过gdb不是今天的主角。而是怎么简单的使用printf来记录和分类一些程序
日志信息。
下面我将介绍下怎么使用printf打印一些日志,让我们在调试的时候更快的发现程序的错误。我们约定可以使用
[ERRORS] ,[WARNINGS] ,[INFO]标识分别来区分错误,警告,信息三类日志信息,例如:
fd=open("/home/user/debug/config.ini",O_RDONLY);
if(fd<=0)
{
printf("[ERRORS][OpenFile.c][Init()] open file failed!/n");
return EXCEPTION;
}
复制代码
在 printf("[ERRORS][OpenFile.c][Init()] open file failed!/n")中我们可以明确知道的信息是当前打印的改行日志是
属于错误日志,位于文件OpenFile.c的Init()函数当中。
int Ret;
char szText[1024];
Ret=0;
memset(szText,0,sizeof(szText));
#ifdef __DEBUG__
printf("[INFO][Convertion.c][Convert()] Before Convert:%s/n",szText);
#endif
nRet=Convert(szText);
if(nRet==EXCEPTION)
{
printf("[INFO][Convertion.c][Convert()] Convert failed!/n");
return EXCEPTION;
}
#ifdef __DEBUG__
printf("[INFO][Convertion.c][Convert()] After Convert:%s/n",szText);
#endif
复制代码
在这段代码中,我们可以通过在对用头文件中添加#define __DEBUG__的宏定义来达到打印调试日志信息。
下面为大家提供本人自己整理的一个比较成熟日志打印程序:
说明:
程序运行会在$HOME/mysrc/test路径下创建一个名为log的文件夹,之后会在log文件夹下创建以当天
系统时间为名称的日志文件,例如系统时间为2011年2月19日,则当天的日志文件名为:20110219.log。
/*********************************************************
*Author: lizhangjie
*Date: 2011-02-15
*Description: Log Printging Functions
*********************************************************/
#include "pub.h"
/*这个是全局日志文件指针,定义并初始化*/
static FILE *gpLogFile=NULL;
char *GetSystemTime()
{
struct tm struTmNow;
time_t struTimeNow;
static char szSystemTime[128];
memset(szSystemTime,'/0',sizeof(szSystemTime));
if(time(&struTimeNow)==(time_t)-1)
{
printf("[ERRORS][Log.c][SystemTime()] time() failed!/n");
return NULL;
}
/*转换成本地时间*/
struTmNow=*localtime(&struTimeNow);
sprintf(szSystemTime,"%04d%02d%02d",struTmNow.tm_year+1900,/
struTmNow.tm_mon+1,struTmNow.tm_mday);
#ifdef __DEBUG__
printf("[INFO][Log.c][SystemTime()] 成功获取系统时间:%s/n",szSystemTime);
#endif
return szSystemTime;
}
char *GetPrtLogFileName()
{
/*definition*/
struct tm struTmNow;
time_t struTimeNow;
static char szFileName[256];
/*initializing*/
memset(szFileName,0,sizeof(szFileName));
if(time(&struTimeNow)==(time_t)-1)
{
printf("[ERRORS][Log.c][GetPrtLogFileName()] time() failed!/n");
return NULL;
}
struTmNow=*localtime(&struTimeNow);
sprintf(szFileName,"%04d%02d%02d.log",struTmNow.tm_year+1900,/
struTmNow.tm_mon+1,struTmNow.tm_mday);
#ifdef __DEBUG__
printf("[INFO][Log.c][GetPrtLogFileName()] 成功组成文件名:%s/n",szFileName);
#endif
return szFileName;
}
int InitPrtLogFile()
{
/*definition*/
/*日志文件路径*/
char szFilePath[256];
static char szFileName[256];
/*initializing*/
memset(szFilePath,0,sizeof(szFilePath));
memset(szFileName,0,sizeof(szFilePath));
/*如果日志文件已打开,返回NORMAL*/
if(gpLogFile!=NULL)
{
if(access(szFileName,F_OK|W_OK)==0)
{
if(strcmp(szFileName,GetPrtLogFileName())==0)
{
printf("[INFO][Log.c][InitPrtLogFile()] 日志文件已存在!/n");
return NORMAL;
}
}
}
/*获取HOME环境变量*/
if(getenv("HOME"))
{
/*log日志文件夹路径位于$HOME/log*/
sprintf(szFilePath,"%s/mysrc/test/log",getenv("HOME"));
#ifdef __DEBUG__
printf("组成路径:%s/n",szFilePath);
#endif
/*在指定目录下创建文件夹*/
if((mkdir(szFilePath,S_IRUSR|S_IWUSR|S_IXUSR)==-1)&&(errno!=EEXIST))
{
printf("[ERRORS][Log.c][InitPtrLogFile()] mkdir() failed!/n");
return EXCEPTION;
}
#ifdef __DEBUG__
printf("[INFO][Log.c][InitPtrLogFile()] log文件夹创建成功!/n");
#endif
sprintf(szFileName,"%s/mysrc/test/log/%s",getenv("HOME"),GetPrtLogFileName());
printf("[INFO][Log.c][InitPrtLogFile()] 路径和文件名获取成功:%s/n",szFileName);
}
else
{
printf("[ERRORS][Log.c][InitPtrLogFile()] getenv() failed!/n");
return EXCEPTION;
}
/*关闭日志文件*/
if(gpLogFile!=NULL)
fclose(gpLogFile);
gpLogFile=fopen(szFileName,"a+");
if(gpLogFile==NULL)
{
printf("[ERRORS][Log.c][InitPtrLogFile()] fopen() failed!/n");
return EXCEPTION;
}
if(chmod(szFileName,S_IRUSR|S_IWUSR)==-1)
{
printf("[ERRORS][Log.c][InitPtrLogFile()] chmod() failed!/n");
return EXCEPTION;
}
return NORMAL;
}
void PrtLog(char *pszDebugStr,char *pszFormatStr,...)
{
/*definition*/
va_list listArg;
static int nFileLineNum;
if(InitPrtLogFile()==NORMAL)
{
va_start(listArg,pszFormatStr);
/*将时间和打印位置写入日志文件*/
fprintf(gpLogFile,"[%s]%s/n/t",GetSystemTime(),pszDebugStr);
/*将日志内容写入日志文件*/
vfprintf(gpLogFile,pszFormatStr,listArg);
va_end(listArg);
/*将内存缓冲中的数据回写到硬盘*/
fflush(gpLogFile);
/*日志文件行数超过限制时做相应处理*/
if(nFileLineNum++>LOG_FILE_MAX_LINE_NUM)
{
/*文件指针重新定位到文件打开时的初始位置*/
fseek(gpLogFile,0,SEEK_SET);
/*日志文件行数清零*/
nFileLineNum=0;
}
}
}
相关文章推荐
- Linux中调试程序使用打印日志纠错
- Linux 程序开发打印 Debug 信息的使用技巧--C语言中几种输出调试信息的方法
- Linux 程序开发打印 Debug 信息的使用技巧--C语言中几种输出调试信息的方法
- Linux 程序开发打印 Debug 信息的使用技巧
- Linux 程序开发打印 Debug 信息的使用技巧
- Linux 程序开发打印 Debug 信息的使用技巧
- Linux 程序开发打印Debug 信息的使用技巧
- Linux下使用函数打印程序堆栈错误的方法
- 使用Eclipse调试Java程序的10个技巧
- 在linux/unix上分析程序日志的技巧
- 使用 Linux 的 strace 命令跟踪/调试程序的常用选项
- 一个简单的用于嵌入式Linux开发的C调试日志打印接口
- 【Linux网络编程】使用GDB调试程序
- linux程序调试及调试工具使用笔记
- VC中用于调试程序的几个宏的使用技巧
- 使用 Linux 的 strace 命令跟踪/调试程序的常用选项
- Linux下使用pdb简单调试python程序
- linux使用--13.ubuntu14.04下安装cgdb及程序调试
- 使用VS+VisualGDB编译调试Linux程序
- 使用Eclipse调试Java 程序的10个技巧