C/C++项目日志通用接口整理

对于C/C++项目比较大或模块比较多时,日志记录起来特别麻烦。将其整理为通用接口,后续开发比较方便。

头文件 dg_log.h 如下:

​
/******************************************************************************

                  Copyright (C), 2017-2018, xxx Co.xxx, Ltd.

 ******************************************************************************
    File Name     : dg_log.h
    Version       : V1.0
    Author        : 
    Created       : 
    Description   : debug log
                    1. DG_INIT      --- Init
                    2. DG_SET_MODE  --- Set the log mode
                    3. DG_SET_LEN   --- Set the log file size
                    4. DG_LOG       --- Print log
    History       :
******************************************************************************/
#ifndef _DG_LOG_H_
#define _DG_LOG_H_

#ifdef __cplusplus
extern "C" {
#endif

/* log mode */
enum {
    DG_LOG_MODE_STDOUT   = 1, // output to screen
    DG_LOG_MODE_FILE     = 2, // output to file
    DG_LOG_MODE_DISABLE  = 3, // close log
    DG_LOG_MODE_MAX,
};

/********************************************************************/
// The following is the internal use interface
int dg_log_init(const char *name, const char *file);
void dg_log_set_mode(int num, int mode);
int dg_log_get_mode(int num);
void dg_log_set_size(int num, int size);
void dg_log_print(int num, const char *function,
    unsigned int line, const char *format, ...);
/********************************************************************/


#define DG_TOSTRING(s)		#s


/********************************************************************/
// eg:
//	    ......
//      int log_num;
//      log_num = DG_LOG_INIT(test_log_mod, "./test.log");
//      ......
//      DG_LOG(log_num, "Test debug_log_mod!");
//      DG_LOG(log_num, "Test debug_log_mod id = %d", log_num);
//      ......

/* init */
#define DG_LOG_INIT(_log_mod, _log_file) ({ \
    int _log_num = dg_log_init(DG_TOSTRING(_log_mod), (_log_file)); \
    (_log_num); \
})

/* set log mode */
#define DG_SET_MODE(_log_num, _log_mode) do { \
    dg_log_set_mode((_log_num), (_log_mode)); \
} while (0)

/* set log file size */
#define DG_SET_SIZE(_log_num, _log_size) do { \
    dg_log_set_size((_log_num), (_log_size)); \
} while (0)

/* get log mode */
#define DG_GET_MODE(_log_num) ({ \
    int _mode = dg_log_get_mode((_log_num)); \
    (_mode); \
})

/* print log */
#define DG_LOG(_log_num, ...) do { \
    if (dg_log_get_mode((_log_num)) != DG_LOG_MODE_DISABLE) \
        dg_log_print((_log_num), __FUNCTION__, __LINE__,  __VA_ARGS__); \
} while (0)
#define DG_LOG0(flag, log_num, fmt) \
    if (flag) \
        DG_LOG(log_num, fmt)
#define DG_LOG1(flag, log_num, fmt, arg1) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1)
#define DG_LOG2(flag, log_num, fmt, arg1, arg2) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2)
#define DG_LOG3(flag, log_num, fmt, arg1, arg2, arg3) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3)
#define DG_LOG4(flag, log_num, fmt, arg1, arg2, arg3, arg4) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4)
#define DG_LOG5(flag, log_num, fmt, arg1, arg2, arg3, arg4, arg5) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4, arg5)
#define DG_LOG6(flag, log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6)
#define DG_LOG7(flag, log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define DG_LOG8(flag, log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define DG_LOG9(flag, log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
    if (flag) \
        DG_LOG(log_num, fmt, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
/********************************************************************/

#ifdef __cplusplus
}
#endif

#endif

程序实现 dg_log.c 如下:

/******************************************************************************

                  Copyright (C), 2017-2018, xxx Co.xxx, Ltd.

 ******************************************************************************
    File Name     : dg_log.c
    Version       : V1.0
    Author        : 
    Created       : 
    Description   : debug log
    History       :
******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/queue.h>

#include "dg_log.h"

#define DG_LOG_FILE_PATH   256
#define DG_LOG_ENTRY_MAX   512

struct dg_log_entry {
    TAILQ_ENTRY(dg_log_entry) next;
    int index;
    int mode;
    long size;
    char name[DG_LOG_FILE_PATH];
    char file[DG_LOG_FILE_PATH];
    char n_file[DG_LOG_FILE_PATH];
};
TAILQ_HEAD(dg_log_head, dg_log_entry);

struct dg_log_free_entry {
    TAILQ_ENTRY(dg_log_free_entry) next;
    int index;
};
TAILQ_HEAD(dg_log_free_head, dg_log_free_entry);

/* Log queue header */
static struct dg_log_head g_dg_log_head =
    TAILQ_HEAD_INITIALIZER(g_dg_log_head);
static struct dg_log_free_head g_dg_log_free_head =
    TAILQ_HEAD_INITIALIZER(g_dg_log_free_head);

/* Total number of log queue nodes */
static struct dg_log_entry g_dg_log_entry[DG_LOG_ENTRY_MAX];
static struct dg_log_free_entry g_dg_log_free_entry[DG_LOG_ENTRY_MAX];

/* Get the head node */
#define DG_LOG_HEAD(_head)        \
    (_head) = &g_dg_log_head
#define DG_LOG_FREE_HEAD(_f_head) \
    (_f_head) = &g_dg_log_free_head

/* Get the node by subscript */
#define DG_LOG_ENTRY_BY_INDEX(_elm, _index)      \
    (_elm) = &g_dg_log_entry[(_index)]
#define DG_LOG_FREE_ENTRY_BY_INDEX(_var, _index) \
    (_var) = &g_dg_log_free_entry[(_index)]

/* Initialize node */
#define DG_LOG_ENTRY_INIT(_elm) do {    \
    (_elm)->index = -1;                 \
    (_elm)->mode = DG_LOG_MODE_STDOUT;  \
    (_elm)->size = 50 * 1024 * 1024;    \
    (_elm)->name[0] = '\0';             \
    (_elm)->file[0] = '\0';             \
} while (0)

typedef struct {
	volatile int locked; /**< lock status 0 = unlocked, 1 = locked */
} dg_log_spinlock_t;

/* Log lock */
static dg_log_spinlock_t g_dg_log_lock = {
    .locked = 0
};

static volatile int dg_log_init_flag = 0;

/*****************************************************************************
    Prototype    : dg_log_spinlock_lock
    Description  : Lock
    Input        : dg_log_spinlock_t *sl
    Output       : void
    Return Value : void
    Author       : 
    Date         : 
*****************************************************************************/
static inline void
dg_log_spinlock_lock(dg_log_spinlock_t *sl)
{
	int lock_val = 1;
	asm volatile (
			"1:\n"
			"xchg %[locked], %[lv]\n"
			"test %[lv], %[lv]\n"
			"jz 3f\n"
			"2:\n"
			"pause\n"
			"cmpl $0, %[locked]\n"
			"jnz 2b\n"
			"jmp 1b\n"
			"3:\n"
			: [locked] "=m" (sl->locked), [lv] "=q" (lock_val)
			: "[lv]" (lock_val)
			: "memory");
}

/*****************************************************************************
    Prototype    : dg_log_spinlock_unlock
    Description  : Unlock
    Input        : dg_log_spinlock_t *sl
    Output       : None
    Return Value : None
    Author       : 
    Date         :
*****************************************************************************/
static inline void
dg_log_spinlock_unlock(dg_log_spinlock_t *sl)
{
	int unlock_val = 0;
	asm volatile (
			"xchg %[locked], %[ulv]\n"
			: [locked] "=m" (sl->locked), [ulv] "=q" (unlock_val)
			: "[ulv]" (unlock_val)
			: "memory");
}

/*****************************************************************************
    Prototype    : dg_log_init
    Description  : Init
    Input        : const char *name
                   const char *file
    Output       : None
    Return Value : int
    Author       : 
    Date         : 
*****************************************************************************/
int dg_log_init(const char *name, const char *file)
{
    int i;
    int num  = -1;
    char n_file[DG_LOG_FILE_PATH];
    struct dg_log_entry *elm;
    struct dg_log_head *head;
    struct dg_log_free_entry *var;
    struct dg_log_free_head *free_head;

    if (!name || !file) return -1;

    dg_log_spinlock_lock(&g_dg_log_lock);

    DG_LOG_HEAD(head);
    DG_LOG_FREE_HEAD(free_head);

    if (!dg_log_init_flag) {
        for (i = 0; i < DG_LOG_ENTRY_MAX; i++) {
            DG_LOG_ENTRY_BY_INDEX(elm, i);
            DG_LOG_ENTRY_INIT(elm);
            DG_LOG_FREE_ENTRY_BY_INDEX(var, i);
            var->index = i;
            TAILQ_INSERT_TAIL(free_head, var, next);
        }
		dg_log_init_flag = 1;
    }

    snprintf(n_file, sizeof(n_file), "%s_%s.log", file, name);

    TAILQ_FOREACH(elm, head, next) {
        if (!strcmp(elm->n_file, n_file)) {
            num = elm->index;
            goto unlock;
        }
    }

    var = TAILQ_FIRST(free_head);
    if (var) {
        DG_LOG_ENTRY_BY_INDEX(elm, var->index);
        elm->index = var->index;
        snprintf(elm->name, sizeof(elm->name), "%s", name);
        snprintf(elm->file, sizeof(elm->file), "%s", file);
        snprintf(elm->n_file, sizeof(elm->n_file), "%s", n_file);
        TAILQ_INSERT_TAIL(head, elm, next);

        TAILQ_REMOVE(free_head, var, next);
        var->index = -1;
        num = elm->index;
    }

unlock:
    dg_log_spinlock_unlock(&g_dg_log_lock);

    return num;
}

/*****************************************************************************
    Prototype    : dg_log_set_mode
    Description  : Set the log mode
    Input        : int num
                   int mode
    Output       : None
    Return Value : None
    Author       : 
    Date         : 
*****************************************************************************/
void dg_log_set_mode(int num, int mode)
{
    struct dg_log_entry *elm;
    struct dg_log_head *head;

    if (num < 0) return;

    dg_log_spinlock_lock(&g_dg_log_lock);

    DG_LOG_HEAD(head);

    TAILQ_FOREACH(elm, head, next) {
        if (elm->index == num) {
            elm->mode = mode;
            break;
        }
    }

    dg_log_spinlock_unlock(&g_dg_log_lock);
}

/*****************************************************************************
    Prototype    : dg_log_get_mode
    Description  : Get the log mode
    Input        : int num
    Output       : None
    Return Value : int
    Author       : 
    Date         : 
*****************************************************************************/
int dg_log_get_mode(int num)
{
    struct dg_log_entry *elm;
    struct dg_log_head *head;
    int mode = DG_LOG_MODE_DISABLE;

    if (num < 0) return mode;

    dg_log_spinlock_lock(&g_dg_log_lock);

    DG_LOG_HEAD(head);

    TAILQ_FOREACH(elm, head, next) {
        if (elm->index == num) {
            mode = elm->mode;
            break;
        }
    }

    dg_log_spinlock_unlock(&g_dg_log_lock);

    return mode;
}

/*****************************************************************************
    Prototype    : dg_log_set_size
    Description  : Set the log file size
    Input        : int num
                   int mode
    Output       : None
    Return Value : None
    Author       : 
    Date         : 
*****************************************************************************/
void dg_log_set_size(int num, int size)
{
    struct dg_log_entry *elm;
    struct dg_log_head *head;

    if (num < 0) return;

    dg_log_spinlock_lock(&g_dg_log_lock);

    DG_LOG_HEAD(head);

    TAILQ_FOREACH(elm, head, next) {
        if (elm->index == num) {
            if (size >= 50) {
                elm->size = size * 1024 * 1024;
            }
            break;
        }
    }

    dg_log_spinlock_unlock(&g_dg_log_lock);
}

/*****************************************************************************
    Prototype    : dg_log_print
    Description  : Print log
    Input        : int num
                   const char *function
                   unsigned int line
                   const char *format
                   ...
    Output       : None
    Return Value : None
    Author       : 
    Date         : 
*****************************************************************************/
void dg_log_print(int num, const char *function, unsigned int line,
    const char *format, ...)
{
    if (num < 0) return;

    dg_log_spinlock_lock(&g_dg_log_lock);

    long file_size;
    FILE *fp = stdout;
    struct stat stStat;
    struct dg_log_entry *elm;
    struct dg_log_head *head;

    DG_LOG_HEAD(head);

    TAILQ_FOREACH(elm, head, next) {
        if (elm->index == num) {
            break;
        }
    }

    if (elm == NULL) goto unlock;
    if (elm->mode == DG_LOG_MODE_FILE) {
        if (stat(elm->n_file, &stStat) != 0) {
            if (errno == ENOENT) file_size = 0;
            else goto unlock;
        } else {
            file_size = stStat.st_size;
        }
        if (file_size > elm->size) {
            if ((fp = fopen(elm->n_file, "w")) == NULL) goto unlock;
        } else {
            if ((fp = fopen(elm->n_file, "a")) == NULL) goto unlock;
        }
    } else if (elm->mode == DG_LOG_MODE_DISABLE) goto unlock;

    int len;
    va_list ap;
    char buf[128];
    char msg[2048];
    time_t tm_t;
    struct tm *ttm = NULL;

    tm_t = time(NULL);
    ttm = localtime(&tm_t);
    strftime(buf, sizeof(buf), "%Y/%m/%d %X", ttm);
    va_start(ap, format);
    vsnprintf(msg, sizeof(msg), format, ap);
    va_end(ap);
    fprintf(fp, "[%s][%s:%d] %s\n", buf, function, line, msg);
    fflush(fp);
    if (fp != stdout) fclose(fp);

unlock:
    dg_log_spinlock_unlock(&g_dg_log_lock);
    return;
}

测试代码如下:

#include <stdio.h>
#include "dg_log.h"

int LOG_NUM = 0;

int test1()
{
	LOG_NUM = DG_LOG_INIT(test1, "/home/log/lijd.log");

    DG_SET_MODE(LOG_NUM, DG_LOG_MODE_FILE);

    DG_LOG(LOG_NUM, "test1 code1!");
    DG_LOG(LOG_NUM, "test1 code2, num = %d", LOG_NUM);
    DG_LOG(LOG_NUM, "test1 code3, str = %s", "test code");
	
	return 0;
}

int test2()
{
	LOG_NUM = DG_LOG_INIT(test2, "/home/log/lijd.log");

    DG_SET_MODE(LOG_NUM, DG_LOG_MODE_FILE);

    DG_LOG(LOG_NUM, "test2 code1!");
    DG_LOG(LOG_NUM, "test2 code2, num = %d", LOG_NUM);
    DG_LOG(LOG_NUM, "test2 code3, str = %s", "test code");
	return 0;
}

int main(int argc, char *argv[]) 
{
    LOG_NUM = DG_LOG_INIT(main, "/home/log/lijd.log");

    DG_SET_MODE(LOG_NUM, DG_LOG_MODE_FILE);

    DG_LOG(LOG_NUM, "main code1!");
    DG_LOG(LOG_NUM, "main code2, num = %d", LOG_NUM);
    DG_LOG(LOG_NUM, "main code3, str = %s", "test code");
	
	test1();
	test2();

    return 0;
}

编译代码: gcc -g -o main main.c dg_log.c

运行结果如下:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值