Debug_Info跨平台动态库实现(2)
接着上一节内容,上一节主要是定义了一些必要的头文件引入,消除平台差异性函数,定义全局变量等内容,本节将具体讲编码给出了,代码确实没有太大的意义。因为他的可变性太大了,给出的代码仅供参考吧!
接着上一节的编号,进行本节的内容:
七、内部函数实现
1、create_dir()函数实现:
/************************************************************************/
/* Create directory if not exists */
/************************************************************************/
int create_dir(char *_pszDir)
{
int i = 0;
int iRet;
int iLen = (int)strlen(_pszDir);
//Append / to the tail
if (_pszDir[iLen - 1] != '\\' && _pszDir[iLen - 1] != '/'){
_pszDir[iLen] = '/';
_pszDir[iLen + 1] = '\0';
}
// Create Directory
for (i = 0;i < iLen;i ++){
if (_pszDir[i] == '\\' || _pszDir[i] == '/'){
_pszDir[i] = '\0';
if(strlen(_pszDir)==0)
_pszDir[i]='/';
//If not exist, created it.
iRet = access(_pszDir,0);
if (iRet != 0){
iRet = mkdir(_pszDir);
if (iRet != 0){
return -1;
}
}
//Change the '\' to '/'
_pszDir[i] = '/';
}
}
return 0;
}
该方法是我参考网上的一个实现方法,就拿来主义了,本来希望最终人家的原创权的,可是后来再找这篇文章,就找不到了。哎,对不起了!
这个方法主要是要注意不同平台之间的文件夹分割符的差异性。
2、debug_info_rec()实现:
在实现之前,首先要提前定义一些变量数组。现在发现数组太好用了,这是我之前不曾感受到的。可以不用挨个的判断具体的值了,而是仅仅进行查找即可,多么强大啊。那些复杂的判断if...elseif..、switch等,比起数组,反而累赘了许多。
const debug_info_category categories[]={
CATEGORY_SHUTDOWN,
CATEGORY_FATAL_ERROR,
CATEGORY_ERROR,
CATEGORY_WARN,
CATEGORY_AUDIT,
CATEGORY_TRACE,
CATEGORY_INFO };const debug_info_module modules[]={
const char *str_cats[]={"SHUTDOWN","FATAL_ERROR","ERROR","WARN","AUDIT","TRACE","INFO"};
const char *str_mods[]={"NONE","SERVER","SYS","DB","SQL_PARSE","ENCRYPT","SECURITY"};
MODULE_NONE,
MODULE_SERVER,
MODULE_SYS,
MODULE_DB,
MODULE_SQL_PARSE,
MODULE_ENCRYPT,
MODULE_SECURITY };
具体方法的实现是根据以上这些变量来实现的,具体的代码如下:
/************************************************************************/
/*Record the debug info based on category level and module level */
/************************************************************************/
int _debug_info_rec(debug_info _debug_info,char *_buffer){
int i = 0,j=0;
if(!create_or_bak_file()){
//Print debug_info into file
if((global_category&_debug_info._cat) && (global_module&_debug_info._module)){
for(i=0;i<sizeof(categories)/sizeof(categories[0]);i++){
if(categories[i]&_debug_info._cat){
for(j=0;j<sizeof(modules)/sizeof(modules[0]);j++){
if(modules[j]&_debug_info._module){
fprintf(debug_info_file,"[%s][%s][0X%08X][%s][%s][%s : %s @ %d]\n",_debug_info._time,str_cats[i],_debug_info._code,str_mods[j],_buffer,_debug_info._file,_debug_info._func,_debug_info._line);
}
}
}
}
}
}
fflush( debug_info_file );
fclose( debug_info_file );
return 0;
}
3、get_current_time()实现
获得当前时间,这是一个要经常用的代码,于是就封装一下吧。简单的不能再简单了,这些方法在<time.h>中定义,并且内容固定,基本就是这样的形式,可以到处用了。
int get_current_time(char *currenttime){
time_t t;
time( &t);
strftime(currenttime, 38, "%Y-%m-%d %H:%M:%S", localtime(&t));
return 0;
}
4、create_or_bak_file()实现
这个函数涉及到很多文件操作的函数,如果对文件操作不太熟悉的朋友,可以参照相关的书籍进行一下恶补,但是网络资源更强大,建议网上查查,编一些小代码test一下就行了。
/************************************************************************/
/* Create or back up the debug_info file */
/************************************************************************/
int create_or_bak_file(){
char back_file_name[MAX_PATH] = {0};
time_t t;
char str_rec_num[21] = {0};
char currentdatetime[64] = {0};
struct stat buf;
if (stat( global_path_file_name, &buf ) == 0)
{
if (buf.st_size >= DEBUG_INFO_FILE_MAXLEN)
{
get_current_time(currentdatetime);
snprintf(back_file_name,sizeof(back_file_name), global_path);
snprintf(back_file_name+strlen(global_path) ,sizeof(back_file_name)-strlen(global_path), "gsen_Dump_%s.bug.bak" , currentdatetime);
rename(global_path_file_name, back_file_name);
}
}
debug_info_file = fopen( global_path_file_name, "r+" );
if( debug_info_file == NULL ) {
sum_debug_info_rec = 0;
debug_info_file = fopen( global_path_file_name, "a+" );
if( debug_info_file == NULL ) {
return -1;
}
fclose( debug_info_file );
debug_info_file = fopen( global_path_file_name, "r+" );
if( debug_info_file == NULL ) {
return 1;
}
}
if( fseek( debug_info_file, 0, SEEK_END ) ) {
fclose( debug_info_file );
return 1;
}
return 0;
}
这个方法的基本思想是:如果这个文件的大小大于文件的限制时,将名字改掉,以时间作为一个后缀是防止文件重复的好方法。如果文件不存在,则通过fopen来创建,以append的方式来讲文件写到末尾。
主要的几个函数和结构,稍微说一下:
struct stat:这个数据类型非常有必要看一下,因为他的作用是在是太大了,可以对多种文件进行操作。定义如下:
struct stat {
mode_t st_mode; //文件对应的模式,文件,目录等
ino_t st_ino; //inode节点号
dev_t st_dev; //设备号码
dev_t st_rdev; //特殊设备号码
nlink_t st_nlink; //文件的连接数
uid_t st_uid; //文件所有者
gid_t st_gid; //文件所有者对应的组
off_t st_size; //普通文件,对应的文件字节数
time_t st_atime; //文件最后被访问的时间
time_t st_mtime; //文件内容最后被修改的时间
time_t st_ctime; //文件状态改变时间
blksize_t st_blksize; //文件内容对应的块大小
blkcnt_t st_blocks; //伟建内容对应的块数量
};
fseek:这个是个游标指针,可以在文件内随意定位,让你方便读取任意位置的字符。第三个参数有SEEK_END、SEEK_CUR、SEEK_SET这些形式,具体的含义是文件的末尾、文件当前位置、文件开头。
snprintf: 这个方法是printf系列的函数,该函数的特点是根据定义的长度进行字符串copy。起初我是用sprintf的,但是经过高手指点才知道,这个函数会更安全,避免字符串copy越界。
这一节先将内部的函数说一下,对外的函数那基本就是判断一下、调用一下内部方法的过程了。

浙公网安备 33010602011771号