Linux下使用c编写简单的日志系统

1、日志系统用来干什么的?

在大型软件系统中,为了检测运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件,在日志文件中存放程序流程中的一些重要信息,包括:变量名称及其值、消息结构定义、函数返回值及其执行情况、脚本执行及调用情况等。通过阅读日志文件,我们能很快地跟踪程序流程,并发现程序地问题。因此,熟练掌握日志系统地编写方法并快速地阅读日志文件,是对一个软件开发工程师地基本要求。

2、打印等级

函数需要有打印等级,目前分为ERROR、WARNING、INFO、DEBUG几种,等级越高,数字越小。在使用时需要根据实际情况,出错的情况使用ERROR,不出错可以使用INFO。为代码简洁起见,使用gcc扩展语法。
代码如下:

static const char *s_loginfo[] = {
"ERROR","WARN","INFO","DEBUG"
};

这样通过s_loginfo数组即可以获取等级对应的字符串。注意,这种语法只能在c语言中使用,c++代码编译出错。

3、可变参数宏__VA_ARGS__

__VA_ARGS__是一个可变参数的宏(gcc支持),实现思想就是宏定义中参数列表的最后一个参数为省略号(也就是三个点…),这样预定义宏__VA_ARGS__就可以被用在替换部分中,替换省略号所代表的字符串。加##用来支持0个可变参数的情况。

可变参数宏就像下面这个样子:

#define debug(...) printf(__VA_ARGS__)

缺省号代表一个可以变化的参数表,使用保留名__VA_ARGS__把参数传递给宏,当宏的调用展开时,实际的参数就传递给了printf(),例如:

debug("Y = %d\n", y);

而处理器会把宏的调用替换成:

printf("Y = %d\n",y);

因为debug()是一个可变参数宏,你能在每一次调用中传递不同数目的参数:

debug("test"); //一个参数

带##的可变参数宏的例子

#define PRINT(s, ...) printf(s, ##__VA_ARGS__)

如果我们调用宏

PRINT("hello world\n");//这里没有可变参数,所以要用##__VA_ARGS__

这个时候处理器会把宏的调用替换成:

printf("hello world\n");

如果调用以下宏:

PRINT("hello, %s\n", "i love you");

这个时候处理器会把宏的调用替换成:

printf("hello, %s\n","i love you");

4、va_arg,va_list,va_start,va_end的理解
可变参数用到以下宏函数:

void func(char *fmt, ...)
{
     va_list ap;

     va_start(ap, fmt);
     va_arg(ap, int);
     va_end(va);
}

这里ap其实就是一个指针,指向了参数的地址。

va_start()所做的就是让ap指向函数的最后一个确定的参数(声明程序中是fmt)的下一个参数的地址。

va_arg()所做的就是根据ap指向的地址,和第二个参数所确定的类型,将这个参数中的数据提取出来,作为返回值,同时让ap指向下一个参数。

va_end()所做的就是让ap这个指针指向0。

关于这三个参数实现的宏可以参看下面的实现:

// 使ap指向第一个可变参数的地址
#define  va_start(ap,v)     ( ap = (va_list)&v + _INTSIZEOF(v) )

// 使ap指向下一个可变参数,同时将目前ap所指向的参数提取出来并返回
#define  va_arg(ap,t)       ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )

//  销毁ap
#define  va_end(ap)         ( ap = (va_list)0 )

5、Linux下使用c编写的简单日志系统

log.c的代码:

/********************************************************************************
 *      Copyright:  (C) 2020 makun<1394987689@qq.com>
 *                  All rights reserved.
 *
 *       Filename:  log.c
 *    Description:  This head file 
 *
 *        Version:  1.0.0(08/08/20)
 *         Author:  makun <1394987689@qq.com>
 *      ChangeLog:  1, Release initial version on "08/08/20 12:45:11"
 *                 
 ********************************************************************************/



#include"log.h"
 
FILE * g_file = NULL;

//gcc扩展语法,通过s_loginfo数组可以获取等级对应的字符串
static const char* s_loginfo[] =
{
    "ERROR","INFO"
};
 
/* 创建文件记录error和warn信息*/
FILE* log_open()
{
    g_file = fopen(LOGFILENAME,"a");
    if(NULL == g_file)
     return NULL;
}
int log_write(char* file, const char *func, int line, enum
        en_log_level level, const char *fmt, ...)
{
    char           buf[LOG_BUFFSIZE];
    char           log_buf[LOG_BUFFSIZE];
    va_list        arg_list;
    int            millisec;
    off_t          filesize;

    memset(buf,0,sizeof(buf));
    va_start(arg_list,fmt);
    vsnprintf(buf,sizeof(buf),fmt,arg_list);
    va_end(arg_list);

    if(level > INFO)
    {
        return -1;
    }


    snprintf(log_buf,sizeof(buf),"%s,File: %s, Func: %s, Line :%d,information is: %s",s_loginfo[level],file, func,
line, buf);

    log_print(log_buf);
}

int log_print(char *log_msg)
{
    if (NULL == log_msg)
    {
        log_error("Error input arguemwnts");
        return -1;
    }

    char log_buf[LOG_BUFFSIZE];
    snprintf(log_buf,LOG_BUFFSIZE, "mqtt log message:\n %s \n",log_msg);
    fwrite(log_buf,strlen(log_buf),1,g_file);
    log_roll_back(LOGFILENAME);

    return 0;

}
int log_roll_back()
{
    FILE *fp;
    if( (fp = fopen(LOGFILENAME,"r")) == NULL)
    {
        return -1;
    }
    fseek(fp,0L,SEEK_END);
    long size = ftell(fp);
    fclose(fp);
    if(size >= MAX_ROLL_LOG_SIZE)
    {
        char name_str[32]={0};
        strcpy(name_str,LOGFILENAME);
        strcat(name_str,(char *)".bak");
        remove(name_str);
        if( !rename(LOGFILENAME,name_str));
        {
            return -1;
        }
    }
    return 0;
}
/* 程序结束后调用,关闭日志文件*/
int log_close()
{
    fclose(g_file);
}

log.h

#ifndef  _LOG_H_
#define  _LOG_H_
 
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
#include<time.h>
#include <stdarg.h>
 
 
enum en_log_level
{
    ERROR,
    INFO 
};
 
#define LOG_BUFFSIZE        256
#define MAX_ROLL_LOG_SIZE   (10*1024)
#define LOGFILENAME  "mqtt_message.log"
#define log_info(fmt,...) log_write(__FILE__,__func__,__LINE__,INFO,fmt,##__VA_ARGS__) 
#define log_error(fmt,...)log_write(__FILE__,__func__,__LINE__,ERROR,fmt,##__VA_ARGS__) 
extern FILE *g_file;
extern FILE* log_open();
extern int log_close();
extern int log_print(char *log_msg);
extern int log_roll_back();
extern int log_write(char* file, const char *func, int line, enum en_log_level, const char *fmt, ...);

#endif   /* ----- #ifndef _LOG_H_  ----- */
  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值