EasyLogger的代码解读和移植(linux和stm)

本文详细介绍了开源库EasyLogger的目录结构、文档分析、源码解读及Linux和STM32平台的移植步骤,包括移植所需的核心文件、接口修改以及缓冲和异步输出的配置与性能测试。
摘要由CSDN通过智能技术生成

1. EasyLogger目录结构分析

  • EasyLogger源码下载地址:https://github.com/armink/EasyLogger
其目录结构如下
.
├── demo:有个平台的移植demo(linux,rt-thread,裸机)
├── docs:easylogger说明文档,有中文的和英文的
├── easylogger:easylogger源码
├── LICENSE
└── README.md

2. EasyLogger之docs查看总结

2.1 EasyLogger之docs查看

  1. 对于所有源码,先看其说明文档,其目录结构如下
docs
├── en #英文说明文档,直接忽略
│   ├── api.md
│   ├── images
│   │   ├── EasyLoggerDemo.gif
│   │   └── LogDemo.gif
│   └── readme.md
├── readme.md
└── zh #中文说明文档,看这个
    ├── api  #接口说明文档
    │   ├── flash.md  #EasyLogger Flash 插件 API 说明
    │   ├── kernel.md #EasyLogger 核心功能 API 说明
    │   └── readme.md
    ├── images #文档中的一些动图,可以忽略不看
    │   ├── EasyLoggerDemo.gif
    │   ├── LogDemo.gif
    │   └── TextColor.png
    ├── port #不同平台的移植说明
    │   ├── flash.md #EasyLogger Flash插件移植说明
    │   ├── kernel.md #EasyLogger 核心功能移植说明
    │   └── readme.md
    └── readme.md
  1. 有些人对Flash插件不太理解,可以理解为这部分对EasyLogger的基本功能没有影响,当时通过配置了这些插件,就能实现更多的功能,所以对于刚使用EasyLogger的你来说,可以忽略,后面我们基本掌握了EasyLogger的使用,再看着一部分。
2.1.2 api->kernel.md文档
  • 先简单的说一下这些api接口,大多从文档中截取,然后进行总结
1.1 初始化
初始化的 EasyLogger 的核心功能,初始化后才可以使用下面的API。
ElogErrCode elog_init(void)

1.2 启动
注意:在初始化完成后,必须调用启动方法,日志才会被输出。
void elog_start(void)

1.3 输出日志

所有日志的级别关系大小如下:

级别 标识 描述
0    [A]  断言(Assert)
1    [E]  错误(Error)
2    [W]  警告(Warn)
3    [I]  信息(Info)
4    [D]  调试(Debug)
5    [V]  详细(Verbose)

通过对日志级别的分级,可以选择性的输出某些日志。
比如你的程序处于调试阶段,你可以把日志级别设为Debug,那么debug以上级别(0,1,2,3,4 )的日志都能够输出。
当你的的产品处于发行阶段了,你只能输出Error的信息到的flash,用于查看,因为其他的调试信息都是不能给用户看的。

1.3.1 输入基本的日志
输出日志有两个函数(和printf函数一样,不定参格式,与printf入参一致,放入将要输出日志):
elog_a(tag, ...)
log_a(...) 
具体使用

1.4 断言
这里讲一下什么叫断言,通过我们程序发生错误后会结束该程序,但是当我们使用断言时
程序会先进入断言的函数,可以做一下操作,并输出错误信息。

1.5 日志输出控制
1.5.1 使能/失能日志输出
void elog_set_output_enabled(bool enabled)
1.5.2 获取日志使能状态
bool elog_get_output_enabled(void)
1.5.3 使能/失能日志输出锁
默认为使能状态,当系统或MCU进入异常后,需要输出异常日志时,就必须失能日志输出锁,来保证异常日志能够被正常输出。
void elog_output_lock_enabled(bool enabled)

1.6 日志格式及样式
1.6.1 设置日志格式
void elog_set_fmt(uint8_t level, size_t set)
1.6.2 使能/失能日志颜色
void elog_set_text_color_enabled(bool enabled)
1.6.3 查找日志级别
int8_t elog_find_lvl(const char *log)
1.6.4 查找日志标签
const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len)

1.7 过滤日志
1.7.1 设置过滤级别
void elog_set_filter_lvl(uint8_t level)
1.7.2 设置过滤标签
void elog_set_filter_tag(const char *tag)
1.7.3 设置过滤关键词
void elog_set_filter_kw(const char *keyword)
1.7.4 设置过滤器
void elog_set_filter(uint8_t level, const char *tag, const char *keyword)
1.7.5 按模块的级别过滤
void elog_set_filter_tag_lvl(const char *tag, uint8_t level);

1.8 缓冲输出模式
1.8.2 将缓冲区中的日志全部输出
void elog_flush(void)

1.9 异步输出模式
1.9.2 在异步输出模式下获取日志
size_t elog_async_get_log(char *log, size_t size)
1.9.3 在异步输出模式下获取行日志(以换行符结尾)
size_t elog_async_get_line_log(char *log, size_t size)
2.1.3 port->kernel.md文档
  • 主要是EasyLogger的移植说明,但是这个说明需要知道看到源码,所以此处不做讲解,此处将在第三讲中说明

2.2 EasyLogger之docs总结

  1. EasyLogger之docs查看,我们可以知道文档说明的结构
  2. 对于刚拿到源码的同学来说,先看api->kernel.md,然后再看port->kernel.md

3. EasyLogger之源码分析

  • 其源码的目录结构如下
easylogger
├── inc #头文件
│   ├── elog_cfg.h #EasyLogger的配置文件
│   └── elog.h #函数的头文件
├── plugins  #插件,暂时不管
│   ├── file  
│   └── flash
├── port
│   └── elog_port.c #对应不同平台的移植接口
└── src
    ├── elog_async.c #异步输出模式的代码
    ├── elog_buf.c #缓冲输出模式的代码
    ├── elog.c #核心功能源码
    └── elog_utils.c #EasyLogger常用小工具
  • 如果你只需要简单是日志功能,只需要移植以下的几个文件
    • inc中的elog_cfg.h和elog.h
    • port中的elog_port.c
    • src中的elog.c和elog_utils.c

3.1 源码分析值头文件分析

3.1.1 elog.h(EasyLogger核心函数头文件)
#ifndef __ELOG_H__
#define __ELOG_H__

#include <elog_cfg.h>  //包含了其配置文件的头文件
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/* output log's level */  //日志的输出登记0是最高,5是最低
#define ELOG_LVL_ASSERT                      0
#define ELOG_LVL_ERROR                       1
#define ELOG_LVL_WARN                        2
#define ELOG_LVL_INFO                        3
#define ELOG_LVL_DEBUG                       4
#define ELOG_LVL_VERBOSE                     5

/* the output silent level and all level for filter setting * //即当时设置输出等级是设置为5,所有日志都会输出,设置为0时,最会输出断言日志
#define ELOG_FILTER_LVL_SILENT               ELOG_LVL_ASSERT
#define ELOG_FILTER_LVL_ALL                  ELOG_LVL_VERBOSE

/* output log's level total number */
#define ELOG_LVL_TOTAL_NUM                   6  //一共有6个输出登记

/* EasyLogger software version number */
#define ELOG_SW_VERSION                      "2.2.99"  //EasyLogger的版本号

/* EasyLogger assert for developer. */ //定义断言的回调函数
#ifdef ELOG_ASSERT_ENABLE
    #define ELOG_ASSERT(EXPR)                                                 \
    if (!(EXPR))                                                              \
    {                                                                         \
        if (elog_assert_hook == NULL) {                                       \
            elog_a("elog", "(%s) has assert failed at %s:%ld.", #EXPR, __FUNCTION__, __LINE__); \
            while (1);                                                        \
        } else {                                                              \
            elog_assert_hook(#EXPR, __FUNCTION__, __LINE__);                  \
        }                                                                     \
    }
#else
    #define ELOG_ASSERT(EXPR)                    ((void)0);
#endif

#ifndef ELOG_OUTPUT_ENABLE     //定义ELOG_OUTPUT_ENABLE就可以开启log输出功能
    #define elog_assert(tag, ...)
    #define elog_error(tag, ...)
    #define elog_warn(tag, ...)
    #define elog_info(tag, ...)
    #define elog_debug(tag, ...)
    #define elog_verbose(tag, ...)
#else /* ELOG_OUTPUT_ENABLE */    //限制某级别下的输出
    #if ELOG_OUTPUT_LVL >= ELOG_LVL_ASSERT
        #define elog_assert(tag, ...) \
                elog_output(ELOG_LVL_ASSERT, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_assert(tag, ...)
    #endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_ASSERT */

    #if ELOG_OUTPUT_LVL >= ELOG_LVL_ERROR
        #define elog_error(tag, ...) \
                elog_output(ELOG_LVL_ERROR, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_error(tag, ...)
    #endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_ERROR */

    #if ELOG_OUTPUT_LVL >= ELOG_LVL_WARN
        #define elog_warn(tag, ...) \
                elog_output(ELOG_LVL_WARN, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_warn(tag, ...)
    #endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_WARN */

    #if ELOG_OUTPUT_LVL >= ELOG_LVL_INFO
        #define elog_info(tag, ...) \
                elog_output(ELOG_LVL_INFO, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_info(tag, ...)
    #endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_INFO */

    #if ELOG_OUTPUT_LVL >= ELOG_LVL_DEBUG
        #define elog_debug(tag, ...) \
                elog_output(ELOG_LVL_DEBUG, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_debug(tag, ...)
    #endif /* ELOG_OUTPUT_LVL >= ELOG_LVL_DEBUG */

    #if ELOG_OUTPUT_LVL == ELOG_LVL_VERBOSE
        #define elog_verbose(tag, ...) \
                elog_output(ELOG_LVL_VERBOSE, tag, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
    #else
        #define elog_verbose(tag, ...)
    #endif /* ELOG_OUTPUT_LVL == ELOG_LVL_VERBOSE */
#endif /* ELOG_OUTPUT_ENABLE */

/* all formats index */   //输出格式的美剧
typedef enum {
    ELOG_FMT_LVL    = 1 << 0, /**< level */   //输出等级
    ELOG_FMT_TAG    = 1 << 1, /**< tag */    //输出标识
    ELOG_FMT_TIME   = 1 << 2, /**< current time */  //输出当前时间
    ELOG_FMT_P_INFO = 1 << 3, /**< process info */ //输出进程信息
    ELOG_FMT_T_INFO = 1 << 4, /**< thread info */  //输出线程纤细
    ELOG_FMT_DIR    = 1 << 5, /**< file directory and name */  //输出目录和文件名
    ELOG_FMT_FUNC   = 1 << 6, /**< function name */  //输出函数名
    ELOG_FMT_LINE   = 1 << 7, /**< line number */  //输出行数
} ElogFmtIndex;

/* macro definition for all formats */  //输出所有格式的宏定义
#define ELOG_FMT_ALL    (ELOG_FMT_LVL|ELOG_FMT_TAG|ELOG_FMT_TIME|ELOG_FMT_P_INFO|ELOG_FMT_T_INFO| \
    ELOG_FMT_DIR|ELOG_FMT_FUNC|ELOG_FMT_LINE)

/* output log's tag filter */    //过滤按照tag输出的日志的结构体
typedef struct {
    uint8_t level;
    char tag[ELOG_FILTER_TAG_MAX_LEN + 1];
    bool tag_use_flag; /**< false : tag is no used   true: tag is used */
} ElogTagLvlFilter, *ElogTagLvlFilter_t;

/* output log's filter */   输出日志过滤器结构体
typedef struct {
    uint8_t level;
    char tag[ELOG_FILTER_TAG_MAX_LEN + 1];
    char keyword[ELOG_FILTER_KW_MAX_LEN + 1];
    ElogTagLvlFilter tag_lvl[ELOG_FILTER_TAG_LVL_MAX_NUM];
} ElogFilter, *ElogFilter_t;

/* easy logger */  EasyLogger结构体
typedef struct {
    ElogFilter filter;
    size_t enabled_fmt_set[ELOG_LVL_TOTAL_NUM];
    bool init_ok;
    bool output_enabled;
    bool output_lock_enabled;
    bool output_is_locked_before_enable;
    bool output_is_locked_before_disable;

#ifdef ELOG_COLOR_ENABLE
    bool text_color_enabled;
#endif

}EasyLogger, *EasyLogger_t;

/* EasyLogger error code */ //错误code
typedef enum {
    ELOG_NO_ERR,
} ElogErrCode;

/* elog.c */ //elog所有函数,具体可以看看之前api->kernel.md文档
ElogErrCode elog_init(void);  
void elog_start(void);  //elog初始化函数
void elog_set_output_enabled(bool enabled);
bool elog_get_output_enabled(void);
void elog_set_text_color_enabled(bool enabled);
bool elog_get_text_color_enabled(void);
void elog_set_fmt(uint8_t level, size_t set);
void elog_set_filter(uint8_t level, const char *tag, const char *keyword);
void elog_set_filter_lvl(uint8_t level);
void elog_set_filter_tag(const char *tag);
void elog_set_filter_kw(const char *keyword);
void elog_set_filter_tag_lvl(const char *tag, uint8_t level);
uint8_t elog_get_filter_tag_lvl(const char *tag);
void elog_raw(const char *format, ...);
void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
        const long line, const char *format, ...);
void elog_output_lock_enabled(bool enabled);
extern void (*elog_assert_hook)(const char* expr, const char* func, size_t line);
void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line));
int8_t elog_find_lvl(const char *log);
const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len);
void elog_hexdump(const char *name, uint8_t width, uint8_t *buf, uint16_t size);

#define elog_a(tag, ...)     elog_assert(tag, __VA_ARGS__)
#define elog_e(tag, ...)     elog_error(tag, __VA_ARGS__)
#define elog_w(tag, ...)     elog_warn(tag, __VA_ARGS__)
#define elog_i(tag, ...)     elog_info(tag, __VA_ARGS__)
#define elog_d(tag, ...)     elog_debug(tag, __VA_ARGS__)
#define elog_v(tag, ...)     elog_verbose(tag, __VA_ARGS__)

/**
 * log API short definition
 * NOTE: The `LOG_TAG` and `LOG_LVL` must defined before including the <elog.h> when you want to use log_x API.
 */
#if !defined(LOG_TAG)
    #define LOG_TAG          "NO_TAG"
#endif
#if !defined(LOG_LVL)
    #define LOG_LVL          ELOG_LVL_VERBOSE
#endif
#if LOG_LVL >= ELOG_LVL_ASSERT
    #define log_a(...)       elog_a(LOG_TAG, __VA_ARGS__)
#else
    #define log_a(...)       ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_ERROR
    #define log_e(...)       elog_e(LOG_TAG, __VA_ARGS__)
#else
    #define log_e(...)       ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_WARN
    #define log_w(...)       elog_w(LOG_TAG, __VA_ARGS__)
#else
    #define log_w(...)       ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_INFO
    #define log_i(...)       elog_i(LOG_TAG, __VA_ARGS__)
#else
    #define log_i(...)       ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_DEBUG
    #define log_d(...)       elog_d(LOG_TAG, __VA_ARGS__)
#else
    #define log_d(...)       ((void)0);
#endif
#if LOG_LVL >= ELOG_LVL_VERBOSE
    #define log_v(...)       elog_v(LOG_TAG, __VA_ARGS__)
#else
    #define log_v(...)       ((void)0);
#endif

/* assert API short definition */
#if !defined(assert)
    #define assert           ELOG_ASSERT
#endif

//以下elog_buf.c elog_async.c可以删除,如果不需要追求高速度的输出log

/* elog_buf.c */
//void elog_buf_enabled(bool enabled);
//void elog_flush(void);

/* elog_async.c */
//void elog_async_enabled(bool enabled);
//size_t elog_async_get_log(char *log, size_t size);
//size_t elog_async_get_line_log(char *log, size_t size);

/* elog_utils.c *///easyLogger常用小工具需要定义,因为在elog.c会用到
size_t elog_strcpy(size_t cur_len, char *dst, const char *src);
size_t elog_cpyln(char *line, const char *log, size_t len);
void *elog_memcpy(void *dst, const void *src, size_t count);

#ifdef __cplusplus
}
#endif

#endif /* __ELOG_H__ */

3.1.2 elog_cfg.h(EasyLogger配置函数头文件)
#ifndef _ELOG_CFG_H_
#define _ELOG_CFG_H_
/*---------------------------------------------------------------------------*/
/* enable log output. */
#define ELOG_OUTPUT_ENABLE   //开启日志功能
/* setting static output log level. range: from ELOG_LVL_ASSERT to ELOG_LVL_VERBOSE */
#define ELOG_OUTPUT_LVL                          ELOG_LVL_VERBOSE
/* enable assert check */
#define ELOG_ASSERT_ENABLE  //开启断言
/* buffer size for every line's log */
#define ELOG_LINE_BUF_SIZE                       1024   //每次日志最大输出1024个字节
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN                    5  //行号的最大长度
/* output filter's tag max length */
#define ELOG_FILTER_TAG_MAX_LEN                  30  //过滤标志tag的最大长度
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN                   16  //过滤关键字的最大长度
/* output filter's tag level max num */
#define ELOG_FILTER_TAG_LVL_MAX_NUM              5  //过滤标签的最大值
/* output newline sign */
#define ELOG_NEWLINE_SIGN                        "\n"  //换行的标志,如果是win要换回"\r\n"
/*---------------------------------------------------------------------------*/
/* enable log color */
#define ELOG_COLOR_ENABLE                           //开启分颜色输出
/* change the some level logs to not default color if you want */ 如果需要,将某些级别的日志更改为非默认颜色
#define ELOG_COLOR_ASSERT                        (F_MAGENTA B_NULL S_NORMAL)
#define ELOG_COLOR_ERROR                         (F_RED B_NULL S_NORMAL)
#define ELOG_COLOR_WARN                          (F_YELLOW B_NULL S_NORMAL)
#define ELOG_COLOR_INFO                          (F_CYAN B_NULL S_NORMAL)
#define ELOG_COLOR_DEBUG                         (F_GREEN B_NULL S_NORMAL)
#define ELOG_COLOR_VERBOSE                       (F_BLUE B_NULL S_NORMAL)
/*---------------------------------------------------------------------------*/
/* enable asynchronous output mode */   //此处和上面一样,可以忽略,等下面讲插件篇是介绍
//#define ELOG_ASYNC_OUTPUT_ENABLE
/* the highest output level for async mode, other level will sync output */
//#define ELOG_ASYNC_OUTPUT_LVL                    ELOG_LVL_ASSERT
/* buffer size for asynchronous output mode */
//#define ELOG_ASYNC_OUTPUT_BUF_SIZE               (ELOG_LINE_BUF_SIZE * 10)
/* each asynchronous output's log which must end with newline sign */
//#define ELOG_ASYNC_LINE_OUTPUT
/* asynchronous output mode using POSIX pthread implementation */
//#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
/*---------------------------------------------------------------------------*/
/* enable buffered output mode */ //此处和上面一样,可以忽略,等下面讲插件篇是介绍
//#define ELOG_BUF_OUTPUT_ENABLE
/* buffer size for buffered output mode */
//#define ELOG_BUF_OUTPUT_BUF_SIZE                 (ELOG_LINE_BUF_SIZE * 10)

#endif /* _ELOG_CFG_H_ */
3.1.3 elog_port.c(对应不同平台的移植接口)
#include <elog.h>

//初始化EasyLogger移植所需的资源,当移植插件时要初始化锁
/**
 * EasyLogger port initialize
 *
 * @return result
 */
ElogErrCode elog_port_init(void) {
    ElogErrCode result = ELOG_NO_ERR;

    /* add your code here */
    
    return result;
}
//当你开启日志,使用日志输出是,最终会跳到该函数
/**
 * output log port interface  
 *
 * @param log output of log
 * @param size log size
 */
void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    printf("%.*s", (int)size, log); //直接打印内容和大小即可,如果要输入到文件,在这里实现你的需求
    
}
//开锁,线程锁
/**
 * output lock   
 */
void elog_port_output_lock(void) {
    
    /* add your code here */
    
}
/**
 * output unlock
 */
void elog_port_output_unlock(void) {
    
    /* add your code here */
    
}

//当你设置输出时间的格式,获取时间需要这这里实现。
/**
 * get current time interface
 *
 * @return current time
 */
const char *elog_port_get_time(void) {
    
    /* add your code here */
    //添加你对应平台获取时间的代码,return就是你的时间
}

//当你设置输出进程名字格式时,获取需要在下面接口实现。
/**
 * get current process name interface
 *
 * @return current process name
 */
const char *elog_port_get_p_info(void) {
    
    /* add your code here */
    //添加你对应平台获取进程名字的代码return 对应进程的名字
}

//当你设置输出线程名字格式时,获取需要在下面接口实现。
/**
 * get current thread name interface
 *
 * @return current thread name
 */
const char *elog_port_get_t_info(void) {
    
    /* add your code here */
    //添加你对应平台获取线程名字的代码return 对应进程的名字
    
}
3.1.3 elog.c和elog_utils.c是EasyLogger对应接口的实现函数(此处不讲)
  • 此处就不做多讲,喜欢的可以看一下,我基本都看了一次了,但是由于篇幅会比较长,所以就不讲了,不明白的可以私信我

4. EasyLogger的移植(linux平台,stm平台)

4.1 linux平台

4.1.1 环境介绍
  • 参照我之前的cmake项目模板建立工程
.
├── bin
│   └── main
├── build
├── build.sh
├── CMakeLists.txt
├── include
├── lib
│   ├── CMakeLists.txt
│   └── easylogger
│       ├── CMakeLists.txt
│       ├── inc
│       │   ├── elog_cfg.h
│       │   └── elog.h 
│       ├── lib
│       │   ├── libeasylogger.a
│       │   └── libeasylogger.so
│       └── src
│           ├── elog.c
│           ├── elog_port.c
│           └── elog_utils.c
├── script
│   └── CmakeList.py
└── src
    ├── CMakeLists.txt
    └── main.c
  • 环境ubuntu 18.04
4.1.2 修改elog_port.c接口
  • 新建elog_port.c对应平台代码的实现,linux平台则建立elog_linux_port.c和elog_linux_port.h
  • 把所有elog_port.c中需要实现的代码放到elog_linux_port.c,实现easylogger和平台分离
elog_linux_port.c 代码如下

/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 02:04:24
* @LastEditors: Xiaofang
* @LastEditTime: 2020-08-31 18:13:56
  *************************************************************************/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include "elog_linux_port.h"

#ifdef ELOG_FILE_ENABLE
    const char logfilename[] = "log";
#endif

/**
  * @name: elog_file_write
  * @description: 
  * @note: 
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 成功的长度
  */
int elog_linux_file_write(const char *log, size_t size)
{
#ifdef ELOG_FILE_ENABLE
    int fd = open(logfilename, O_RDWR|O_APPEND);
    int len = write(fd, log, size);
    close(fd);
    return len;
#endif
}

/**
  * @name: elog_linux_port_output
  * @description: //void elog_port_output(const char *log, size_t size) 对应的实现代码,增加输出的模式例如,可以输出到终端,可以输出到文本
  * @note: 对应实现elog_port.c中elog_port_output的代码
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 是否输出成功
  */
int elog_linux_port_output(const char *log, size_t size)
{
    /* output to terminal */
    printf("%.*s", (int)size, log);
#ifdef ELOG_FILE_ENABLE
    /* write the file */
    elog_file_write(log, size);
#endif 
}


/**
  * @name: elog_linux_port_get_time
  * @description: 
  * @note: 
  * @param void
  * @return 时间
  */
const char *elog_linux_port_get_time(void) 
{
    static char cur_system_time[24] = { 0 };
    time_t timep;
    struct tm *p;

    time(&timep);
    p = localtime(&timep);
    if (p == NULL) {
        return "";
    }
    snprintf(cur_system_time, 18, "%02d-%02d %02d:%02d:%02d", p->tm_mon + 1, p->tm_mday,
            p->tm_hour, p->tm_min, p->tm_sec);

    return cur_system_time;
}

/**
  * @name: elog_linux_port_get_p_info
  * @description: 获取进程号
  * @note: 
  * @param void 
  * @return 进程号 
  */
const char *elog_linux_port_get_p_info(void) 
{
    static char cur_process_info[10] = { 0 };
    snprintf(cur_process_info, 10, "pid:%04d", getpid());
    return cur_process_info;
}


/**
  * @name: elog_linux_port_get_t_info
  * @description: 获取线程号
  * @note: 
  * @param void
  * @return 线程号
  */
const char *elog_linux_port_get_t_info(void) 
{
    static char cur_thread_info[10] = { 0 };
    snprintf(cur_thread_info, 10, "tid:%04ld", pthread_self());
    return cur_thread_info;
}

elog_linux_port.h 代码如下
/*
 * @Descripttion: 
 * @Version: 
 * @Author: Xiaofang
 * @Date: 2020-08-31 02:04:46
 * @LastEditors: Xiaofang
 * @LastEditTime: 2020-08-31 03:03:35
 */
#ifndef __ELOG_LINUX_PORT_H__
#define __ELOG_LINUX_PORT_H__

/*需要输出到文件中需要在头文件中定义*/
//#define ELOG_FILE_ENABLE 
#ifdef ELOG_FILE_ENABLE
int elog_linux_file_write(const char *log, size_t size);
#endif

/*定义输出时间戳还是正常的时间*/
//define TIMESTAMP



int elog_linux_port_output(const char *log, size_t size);
const char *elog_linux_port_get_p_info(void);
const char *elog_linux_port_get_t_info(void);
const char *elog_linux_port_get_time(void);

#endif
elog_port.c 代码如下
#include <elog.h>
#include "elog_linux_port.h"
/**
 * EasyLogger port initialize
 *
 * @return result
 */
ElogErrCode elog_port_init(void) {
    ElogErrCode result = ELOG_NO_ERR;

    /* add your code here */
    
    return result;
}

/**
 * output log port interface
 *
 * @param log output of log
 * @param size log size
 */
void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    elog_linux_port_output(log, size);
    
}

/**
 * output lock
 */
void elog_port_output_lock(void) {
    
    /* add your code here */
    
}

/**
 * output unlock
 */
void elog_port_output_unlock(void) {
    
    /* add your code here */
    
}

/**
 * get current time interface
 *
 * @return current time
 */
const char *elog_port_get_time(void) {
    
    /* add your code here */

    return elog_linux_port_get_time();
}

/**
 * get current process name interface
 *
 * @return current process name
 */
const char *elog_port_get_p_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_p_info();
}

/**
 * get current thread name interface
 *
 * @return current thread name
 */
const char *elog_port_get_t_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_t_info();
    
}
4.1.3 接口测试
main.c 代码如下

/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 01:41:05
* @LastEditors: Xiaofang
* @LastEditTime: 2020-08-31 19:59:51
  *************************************************************************/

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

#define TAG "main"


//断言回调函数
void assert_callback(const char* expr, const char* func, size_t line)
{
	elog_a("elog", "(%s) has assert failed at %s:%ld.\n", expr, func, line);
}

int main(int argc, char **argv)
{
	//1. easylogger的启动流程
	//1.1 关闭printf输出
	setbuf(stdout, NULL); //不在使用printf做打印信息了
	//1.2 初始化
	elog_init();

	//1.3 设置输出格式
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);  //断言所有都输出
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);

	//1.5 启动log
	elog_start();
	
	//1.6 输出日志
	elog_a(TAG, "Hello ELOG_LVL_ASSERT");
	elog_e(TAG, "Hello ELOG_LVL_ERROR!");
	elog_w(TAG, "Hello ELOG_LVL_WARN!");
	elog_i(TAG, "Hello ELOG_LVL_INFO!");
	elog_d(TAG, "Hello ELOG_LVL_DEBUG!");
	elog_v(TAG, "Hello ELOG_LVL_VERBOSE!");
	/* 
		// 打印信息如下:
		I/elog            [08-31 18:27:24] EasyLogger V2.2.99 is initialize success. //elog_start()输出
		// 下面信息是根据你上面定义的输出格式进行输出
		A/NO_TAG          [08-31 18:27:24 pid:45278 tid:14011] (/home/ubuntu/cEasyLogger/src/main.c main:36)Hello ELOG_LVL_ASSERT
		E/NO_TAG          [08-31 18:27:24] Hello ELOG_LVL_ERROR!
		W/NO_TAG          [08-31 18:27:24] Hello ELOG_LVL_WARN!
		I/NO_TAG          [08-31 18:27:24] Hello ELOG_LVL_INFO!
		D/NO_TAG          [08-31 18:27:24 pid:45278 tid:14011] (/home/ubuntu/cEasyLogger/src/main.c:40)Hello ELOG_LVL_DEBUG!
		V/NO_TAG          [08-31 18:27:24 pid:45278 tid:14011] (/home/ubuntu/cEasyLogger/src/main.c:41)Hello ELOG_LVL_VERBOSE!
	*/
	//1.7 使能颜色输出
	elog_set_text_color_enabled(true);
	//不带TAG输出
	log_a("Hello ELOG_LVL_ASSERT");
	log_e("Hello ELOG_LVL_ERROR!");
	log_w("Hello ELOG_LVL_WARN!");
	log_i("Hello ELOG_LVL_INFO!");
	log_d("Hello ELOG_LVL_DEBUG!");
	log_v("Hello ELOG_LVL_VERBOSE!");
	/*
		// 打印信息如下:
		//确实没有带TAG输出,且带上了颜色,颜色在不同要编辑器支持才能看到,我用的是vscode
		A/NO_TAG          [08-31 18:44:00 pid:45517 tid:14046] (/home/ubuntu/cEasyLogger/src/main.c main:55)Hello ELOG_LVL_ASSERT
		E/NO_TAG          [08-31 18:44:00] Hello ELOG_LVL_ERROR!
		W/NO_TAG          [08-31 18:44:00] Hello ELOG_LVL_WARN!
		I/NO_TAG          [08-31 18:44:00] Hello ELOG_LVL_INFO!
		D/NO_TAG          [08-31 18:44:00 pid:45517 tid:14046] (/home/ubuntu/cEasyLogger/src/main.c:59)Hello ELOG_LVL_DEBUG!
		V/NO_TAG          [08-31 18:44:00 pid:45517 tid:14046] (/home/ubuntu/cEasyLogger/src/main.c:60)Hello ELOG_LVL_VERBOSE!
	*/

	// 1.8 设置等级过滤
	/*
	elog_set_filter_lvl(ELOG_LVL_WARN);
	log_a("Hello ELOG_LVL_ASSERT");
	log_e("Hello ELOG_LVL_ERROR!");
	log_w("Hello ELOG_LVL_WARN!");
	log_i("Hello ELOG_LVL_INFO!");
	log_d("Hello ELOG_LVL_DEBUG!");
	log_v("Hello ELOG_LVL_VERBOSE!");*/
	/*
		// 打印信息如下:
		A/NO_TAG          [08-31 18:58:46 pid:45610 tid:14001] (/home/ubuntu/cEasyLogger/src/main.c main:74)Hello ELOG_LVL_ASSERT
		E/NO_TAG          [08-31 18:58:46] Hello ELOG_LVL_ERROR!
		W/NO_TAG          [08-31 18:58:46] Hello ELOG_LVL_WARN!
	*/
	// 1.9 设置TAG过滤,测试时先屏蔽上面的elog_set_filter_lvl(ELOG_LVL_WARN);,不然会叠加输出
	/*
	elog_set_filter_tag(TAG);
	log_a("Hello ELOG_LVL_ASSERT");
	log_e("Hello ELOG_LVL_ERROR!");
	elog_w(TAG, "Hello ELOG_LVL_WARN!");
	elog_i(TAG, "Hello ELOG_LVL_INFO!");
	elog_d(TAG, "Hello ELOG_LVL_DEBUG!");
	elog_v(TAG, "Hello ELOG_LVL_VERBOSE!");*/
	/*
		// 打印信息如下:
		W/main            [08-31 19:02:02] Hello ELOG_LVL_WARN!
		I/main            [08-31 19:02:02] Hello ELOG_LVL_INFO!
		D/main            [08-31 19:02:02 pid:45746 tid:13987] (/home/ubuntu/cEasyLogger/src/main.c:93)Hello ELOG_LVL_DEBUG!
		V/main            [08-31 19:02:02 pid:45746 tid:13987] (/home/ubuntu/cEasyLogger/src/main.c:94)Hello ELOG_LVL_VERBOSE!
	*/
	// 1.9 关键字输出
	/*
	elog_set_filter_kw("a"); //过滤信息包含你设置的输出格式信息
	log_a("a v");
	log_e("a e");
	log_w("b w");
	log_i("b i");
	log_d("b d");
	log_v("b v");*/
	/*
		// 打印信息如下:
		A/NO_TAG          [08-31 19:16:37 pid:46041 tid:14045] (/home/ubuntu/cEasyLogger/src/main.c main:105)a v
		E/NO_TAG          [08-31 19:16:37] a e

	*/

	//void elog_set_filter(uint8_t level, const char *tag, const char *keyword); //设置三种过滤方式,这些就不做测试了
	//void elog_set_filter_tag_lvl(const char *tag, uint8_t level);//设置两种,这些就不做测试了

	//2.0 查看是否开启颜色使能bool elog_get_text_color_enabled(void);,测试是否支持格式化输出
	/*
	int a = elog_get_text_color_enabled();
	log_i("%d",a);*/
	/*
		// 打印信息如下:支持格式化输出
		I/NO_TAG          [08-31 19:29:28] 1
	*/

	// 设置断言的回调函数
	elog_assert_set_hook(assert_callback);
	ELOG_ASSERT(1>2);  //当条件不满住时,进入回调函数
}

4.2 stm32平台

4.2.1 stm32平台环境
  • 芯片stm32f407vg
  • 系统Freertos
  • 编辑器IAR
4.2.2 把源码添加到工程
easylogger
|
├─inc
│      elog.h
│      elog_cfg.h
│      elog_stm_port.h #和linux一样新建一个对应平台的目录
│
└─src
        elog.c
        elog_port.c
        elog_stm_port.c #和linux一样新建一个对应平台的目录
        elog_utils.c

4.2.3 elog_stm_port.c修改
/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 02:04:24
* @LastEditors: Xiaofang
* @LastEditTime: 2020-09-01 18:40:49
  *************************************************************************/

#include <stdio.h>
#include <stdio.h>
#include "FreeRTOS.h"
#include "task.h"   //添加系统对应的头文件
#include "elog_stm_port.h" 
#include "rtc.h"

#ifdef ELOG_FILE_ENABLE
    const char logfilename[] = LOGNAME;
    static int fd=0;
#endif


static char heap[30] = {0};
static char real_time[30] = {0};


int heapsize;


/**
  * @name: elog_file_write
  * @description: 
  * @note: 
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 成功的长度
  */
int elog_stm_file_write(const char *log, size_t size)
{
    int len=0;
#ifdef ELOG_FILE_ENABLE
    len = write(fd, log, size); //要有文件系统才能用
#endif
    return len;
}

/**
  * @name: elog_linux_port_output
  * @description: //void elog_port_output(const char *log, size_t size) 对应的实现代码,增加输出的模式例如,可以输出到终端,可以输出到文本
  * @note: 对应实现elog_port.c中elog_port_output的代码
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 是否输出成功
  */
int elog_stm_port_output(const char *log, size_t size)
{
    int len=0;
    /* output to terminal */
    printf("%.*s", (int)size, log);
#ifdef ELOG_FILE_ENABLE
    /* write the file */
    len = elog_stm_file_write(log, size);
#endif 
    return len;
}


/**
  * @name: elog_linux_port_get_time
  * @description: 
  * @note: 
  * @param void
  * @return 时间
  */
const char *elog_stm_port_get_time(void)   //获取时间,这里是使用rtc来用,获取来时间戳然后转为时间
{
    struct tm t;
    long time = Read_Local_Time();
    Read_Local_TimeStamp_Tiem(time, &t);
    sprintf(real_time,"%02d:%02d:%02d",t.tm_hour+8, t.tm_min, t.tm_sec);

    return real_time;
}

/**
  * @name: elog_linux_port_get_p_info
  * @description: 剩余堆
  * @note: 
  * @param void 
  * @return 剩余堆 
  */
const char *elog_stm_port_get_heap_info(void) 
{

    sprintf(heap,"Free Heap:%d",xPortGetFreeHeapSize());  //之前是获取进程号,现在改成获取堆内存,因为freertos没有多进程说法
    return heap;
}



/**
注意我把获取线程号删来,要在源码中进行修改
*/

/**
  * @name: elog_stm_port_init
  * @description: stm平台的初始化
  * @note: 
  */
void elog_stm_port_init(void)
{
    
#ifdef ELOG_FILE_ENABLE
    /* write the file */
    fd = open(logfilename, O_RDWR|O_CREAT|O_APPEND);
#endif 
    //open

}


/**
  * @name: elog_stm_port_output_lock
  * @description: 开启调度锁
  * @note: 
  */
void elog_stm_port_output_lock(void)
{
	vTaskSuspendAll();//开启调度锁
}

/**
  * @name: elog_stm_port_output_unlock
  * @description: 关闭调度锁
  * @note: 
  */
void elog_stm_port_output_unlock(void) {
    xTaskResumeAll();//关闭调度锁
}
/*
 * @Descripttion: 
 * @Version: 
 * @Author: Xiaofang
 * @Date: 2020-08-31 02:04:46
 * @LastEditors: Xiaofang
 * @LastEditTime: 2020-09-01 18:47:00
 */
#ifndef __ELOG_STM_PORT_H__
#define __ELOG_STM_PORT_H__

/*需要输出到文件中需要在头文件中定义*/
//#define ELOG_FILE_ENABLE 
#ifdef ELOG_FILE_ENABLE
int elog_stm_file_write(const char *log, size_t size);
#define LOGNAME "LINUX_LOG"
#endif

/*定义输出时间戳还是正常的时间*/
//define TIMESTAMP



int elog_stm_port_output(const char *log, size_t size);
const char *elog_stm_port_get_heap_info(void); 
const char *elog_stm_port_get_t_info(void);
const char *elog_stm_port_get_time(void);
void elog_stm_port_init(void);
void elog_stm_port_output_lock(void);
void elog_stm_port_output_unlock(void) ;

#endif
/*
 * This file is part of the EasyLogger Library.
 *
 * Copyright (c) 2015-2018, Armink, <armink.ztl@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * 'Software'), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Function: Initialize function and other general function.
 * Created on: 2015-04-28
 */

#define LOG_TAG      "elog"

#include <elog.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

#if !defined(ELOG_OUTPUT_LVL)
    #error "Please configure static output log level (in elog_cfg.h)"
#endif

#if !defined(ELOG_LINE_NUM_MAX_LEN)
    #error "Please configure output line number max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_LINE_BUF_SIZE)
    #error "Please configure buffer size for every line's log (in elog_cfg.h)"
#endif

#if !defined(ELOG_FILTER_TAG_MAX_LEN)
    #error "Please configure output filter's tag max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_FILTER_KW_MAX_LEN)
    #error "Please configure output filter's keyword max length (in elog_cfg.h)"
#endif

#if !defined(ELOG_NEWLINE_SIGN)
    #error "Please configure output newline sign (in elog_cfg.h)"
#endif

/* output filter's tag level max num */
#ifndef ELOG_FILTER_TAG_LVL_MAX_NUM
#define ELOG_FILTER_TAG_LVL_MAX_NUM          4
#endif

#ifdef ELOG_COLOR_ENABLE
/**
 * CSI(Control Sequence Introducer/Initiator) sign
 * more information on https://en.wikipedia.org/wiki/ANSI_escape_code
 */
#define CSI_START                      "\033["
#define CSI_END                        "\033[0m"
/* output log front color */
#define F_BLACK                        "30;"
#define F_RED                          "31;"
#define F_GREEN                        "32;"
#define F_YELLOW                       "33;"
#define F_BLUE                         "34;"
#define F_MAGENTA                      "35;"
#define F_CYAN                         "36;"
#define F_WHITE                        "37;"
/* output log background color */
#define B_NULL
#define B_BLACK                        "40;"
#define B_RED                          "41;"
#define B_GREEN                        "42;"
#define B_YELLOW                       "43;"
#define B_BLUE                         "44;"
#define B_MAGENTA                      "45;"
#define B_CYAN                         "46;"
#define B_WHITE                        "47;"
/* output log fonts style */
#define S_BOLD                         "1m"
#define S_UNDERLINE                    "4m"
#define S_BLINK                        "5m"
#define S_NORMAL                       "22m"
/* output log default color definition: [front color] + [background color] + [show style] */
#ifndef ELOG_COLOR_ASSERT
#define ELOG_COLOR_ASSERT              (F_MAGENTA B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_ERROR
#define ELOG_COLOR_ERROR               (F_RED B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_WARN
#define ELOG_COLOR_WARN                (F_YELLOW B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_INFO
#define ELOG_COLOR_INFO                (F_CYAN B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_DEBUG
#define ELOG_COLOR_DEBUG               (F_GREEN B_NULL S_NORMAL)
#endif
#ifndef ELOG_COLOR_VERBOSE
#define ELOG_COLOR_VERBOSE             (F_BLUE B_NULL S_NORMAL)
#endif
#endif /* ELOG_COLOR_ENABLE */

/* EasyLogger object */
static EasyLogger elog;
/* every line log's buffer */
static char log_buf[ELOG_LINE_BUF_SIZE] = { 0 };
/* level output info */
static const char *level_output_info[] = {
        [ELOG_LVL_ASSERT]  = "A/",
        [ELOG_LVL_ERROR]   = "E/",
        [ELOG_LVL_WARN]    = "W/",
        [ELOG_LVL_INFO]    = "I/",
        [ELOG_LVL_DEBUG]   = "D/",
        [ELOG_LVL_VERBOSE] = "V/",
};

#ifdef ELOG_COLOR_ENABLE
/* color output info */
static const char *color_output_info[] = {
        [ELOG_LVL_ASSERT]  = ELOG_COLOR_ASSERT,
        [ELOG_LVL_ERROR]   = ELOG_COLOR_ERROR,
        [ELOG_LVL_WARN]    = ELOG_COLOR_WARN,
        [ELOG_LVL_INFO]    = ELOG_COLOR_INFO,
        [ELOG_LVL_DEBUG]   = ELOG_COLOR_DEBUG,
        [ELOG_LVL_VERBOSE] = ELOG_COLOR_VERBOSE,
};
#endif /* ELOG_COLOR_ENABLE */

static bool get_fmt_enabled(uint8_t level, size_t set);
static void elog_set_filter_tag_lvl_default();

/* EasyLogger assert hook */
void (*elog_assert_hook)(const char* expr, const char* func, size_t line);

extern void elog_port_output(const char *log, size_t size);
extern void elog_port_output_lock(void);
extern void elog_port_output_unlock(void);

/**
 * EasyLogger initialize.
 *
 * @return result
 */
ElogErrCode elog_init(void) {
    extern ElogErrCode elog_port_init(void);
    extern ElogErrCode elog_async_init(void);

    ElogErrCode result = ELOG_NO_ERR;

    if (elog.init_ok == true) {
        return result;
    }

    /* port initialize */
    result = elog_port_init();
    if (result != ELOG_NO_ERR) {
        return result;
    }

#ifdef ELOG_ASYNC_OUTPUT_ENABLE
    result = elog_async_init();
    if (result != ELOG_NO_ERR) {
        return result;
    }
#endif

    /* enable the output lock */
    elog_output_lock_enabled(true);
    /* output locked status initialize */
    elog.output_is_locked_before_enable = false;
    elog.output_is_locked_before_disable = false;

#ifdef ELOG_COLOR_ENABLE
    /* disable text color by default */
    elog_set_text_color_enabled(false);
#endif

    /* set level is ELOG_LVL_VERBOSE */
    elog_set_filter_lvl(ELOG_LVL_VERBOSE);

    /* set tag_level to default val */
    elog_set_filter_tag_lvl_default();

    elog.init_ok = true;

    return result;
}

/**
 * EasyLogger start after initialize.
 */
void elog_start(void) {
    /* enable output */
    elog_set_output_enabled(true);

#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
    elog_async_enabled(true);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
    elog_buf_enabled(true);
#endif

    /* show version */
    log_i("EasyLogger V%s is initialize success.", ELOG_SW_VERSION);
}

/**
 * set output enable or disable
 *
 * @param enabled TRUE: enable FALSE: disable
 */
void elog_set_output_enabled(bool enabled) {
    ELOG_ASSERT((enabled == false) || (enabled == true));

    elog.output_enabled = enabled;
}

#ifdef ELOG_COLOR_ENABLE
/**
 * set log text color enable or disable
 * 
 * @param enabled TRUE: enable FALSE:disable
 */
void elog_set_text_color_enabled(bool enabled) {
    elog.text_color_enabled = enabled;
}

/**
 * get log text color enable status
 *
 * @return enable or disable
 */
bool elog_get_text_color_enabled(void) {
    return elog.text_color_enabled;
}
#endif /* ELOG_COLOR_ENABLE */

/**
 * get output is enable or disable
 *
 * @return enable or disable
 */
bool elog_get_output_enabled(void) {
    return elog.output_enabled;
}

/**
 * set log output format. only enable or disable
 *
 * @param level level
 * @param set format set
 */
void elog_set_fmt(uint8_t level, size_t set) {
    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);

    elog.enabled_fmt_set[level] = set;
}

/**
 * set log filter all parameter
 *
 * @param level level
 * @param tag tag
 * @param keyword keyword
 */
void elog_set_filter(uint8_t level, const char *tag, const char *keyword) {
    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);

    elog_set_filter_lvl(level);
    elog_set_filter_tag(tag);
    elog_set_filter_kw(keyword);
}

/**
 * set log filter's level
 *
 * @param level level
 */
void elog_set_filter_lvl(uint8_t level) {
    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);

    elog.filter.level = level;
}

/**
 * set log filter's tag
 *
 * @param tag tag
 */
void elog_set_filter_tag(const char *tag) {
    strncpy(elog.filter.tag, tag, ELOG_FILTER_TAG_MAX_LEN);
}

/**
 * set log filter's keyword
 *
 * @param keyword keyword
 */
void elog_set_filter_kw(const char *keyword) {
    strncpy(elog.filter.keyword, keyword, ELOG_FILTER_KW_MAX_LEN);
}

/**
 * lock output 
 */
void elog_output_lock(void) {
    if (elog.output_lock_enabled) {
        elog_port_output_lock();
        elog.output_is_locked_before_disable = true;
    } else {
        elog.output_is_locked_before_enable = true;
    }
}

/**
 * unlock output
 */
void elog_output_unlock(void) {
    if (elog.output_lock_enabled) {
        elog_port_output_unlock();
        elog.output_is_locked_before_disable = false;
    } else {
        elog.output_is_locked_before_enable = false;
    }
}

/**
 * set log filter's tag level val to default
 */
static void elog_set_filter_tag_lvl_default()
{
    uint8_t i = 0;

    for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
        memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
        elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
        elog.filter.tag_lvl[i].tag_use_flag = false;
    }
}

/**
 * Set the filter's level by different tag.
 * The log on this tag which level is less than it will stop output.
 *
 * example:
 *     // the example tag log enter silent mode
 *     elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_SILENT);
 *     // the example tag log which level is less than INFO level will stop output
 *     elog_set_filter_tag_lvl("example", ELOG_LVL_INFO);
 *     // remove example tag's level filter, all level log will resume output
 *     elog_set_filter_tag_lvl("example", ELOG_FILTER_LVL_ALL);
 *
 * @param tag log tag
 * @param level The filter level. When the level is ELOG_FILTER_LVL_SILENT, the log enter silent mode.
 *        When the level is ELOG_FILTER_LVL_ALL, it will remove this tag's level filer.
 *        Then all level log will resume output.
 *
 */
void elog_set_filter_tag_lvl(const char *tag, uint8_t level)
{
    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);
    ELOG_ASSERT(tag != ((void *)0));
    uint8_t i = 0;

    if (!elog.init_ok) {
        return;
    }

    elog_port_output_lock();
    /* find the tag in arr */
    for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
        if (elog.filter.tag_lvl[i].tag_use_flag == true &&
            !strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
            break;
        }
    }

    if (i < ELOG_FILTER_TAG_LVL_MAX_NUM){
        /* find OK */
        if (level == ELOG_FILTER_LVL_ALL){
            /* remove current tag's level filter when input level is the lowest level */
             elog.filter.tag_lvl[i].tag_use_flag = false;
             memset(elog.filter.tag_lvl[i].tag, '\0', ELOG_FILTER_TAG_MAX_LEN + 1);
             elog.filter.tag_lvl[i].level = ELOG_FILTER_LVL_SILENT;
        } else{
            elog.filter.tag_lvl[i].level = level;
        }
    } else{
        /* only add the new tag's level filer when level is not ELOG_FILTER_LVL_ALL */
        if (level != ELOG_FILTER_LVL_ALL){
            for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
                if (elog.filter.tag_lvl[i].tag_use_flag == false){
                    strncpy(elog.filter.tag_lvl[i].tag, tag, ELOG_FILTER_TAG_MAX_LEN);
                    elog.filter.tag_lvl[i].level = level;
                    elog.filter.tag_lvl[i].tag_use_flag = true;
                    break;
                }
            }
        }
    }
    elog_output_unlock();
}

/**
 * get the level on tag's level filer
 *
 * @param tag tag
 *
 * @return It will return the lowest level when tag was not found.
 *         Other level will return when tag was found.
 */
uint8_t elog_get_filter_tag_lvl(const char *tag)
{
    ELOG_ASSERT(tag != ((void *)0));
    uint8_t i = 0;
    uint8_t level = ELOG_FILTER_LVL_ALL;

    if (!elog.init_ok) {
        return level;
    }

    elog_port_output_lock();
    /* find the tag in arr */
    for (i =0; i< ELOG_FILTER_TAG_LVL_MAX_NUM; i++){
        if (elog.filter.tag_lvl[i].tag_use_flag == true &&
            !strncmp(tag, elog.filter.tag_lvl[i].tag,ELOG_FILTER_TAG_MAX_LEN)){
            level = elog.filter.tag_lvl[i].level;
            break;
        }
    }
    elog_output_unlock();

    return level;
}

/**
 * output RAW format log
 *
 * @param format output format
 * @param ... args
 */
void elog_raw(const char *format, ...) {
    va_list args;
    size_t log_len = 0;
    int fmt_result;

    /* check output enabled */
    if (!elog.output_enabled) {
        return;
    }

    /* args point to the first variable parameter */
    va_start(args, format);

    /* lock output */
    elog_output_lock();

    /* package log data to buffer */
    fmt_result = vsnprintf(log_buf, ELOG_LINE_BUF_SIZE, format, args);

    /* output converted log */
    if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
        log_len = fmt_result;
    } else {
        log_len = ELOG_LINE_BUF_SIZE;
    }
    /* output log */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
    extern void elog_async_output(uint8_t level, const char *log, size_t size);
    /* raw log will using assert level */
    elog_async_output(ELOG_LVL_ASSERT, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
    extern void elog_buf_output(const char *log, size_t size);
    elog_buf_output(log_buf, log_len);
#else
    elog_port_output(log_buf, log_len);
#endif
    /* unlock output */
    elog_output_unlock();

    va_end(args);
}

/**
 * output the log
 *
 * @param level level
 * @param tag tag
 * @param file file name
 * @param func function name
 * @param line line number
 * @param format output format
 * @param ... args
 *
 */
void elog_output(uint8_t level, const char *tag, const char *file, const char *func,
        const long line, const char *format, ...) {
    extern const char *elog_port_get_time(void);
    extern const char *elog_port_get_p_info(void);
    extern const char *elog_port_get_t_info(void);

    size_t tag_len = strlen(tag), log_len = 0, newline_len = strlen(ELOG_NEWLINE_SIGN);
    char line_num[ELOG_LINE_NUM_MAX_LEN + 1] = { 0 };
    char tag_sapce[ELOG_FILTER_TAG_MAX_LEN / 2 + 1] = { 0 };
    va_list args;
    int fmt_result;

    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);

    /* check output enabled */
    if (!elog.output_enabled) {
        return;
    }
    /* level filter */
    if (level > elog.filter.level || level > elog_get_filter_tag_lvl(tag)) {
        return;
    } else if (!strstr(tag, elog.filter.tag)) { /* tag filter */
        return;
    }
    /* args point to the first variable parameter */
    va_start(args, format);
    /* lock output */
    elog_output_lock();

#ifdef ELOG_COLOR_ENABLE
    /* add CSI start sign and color info */
    if (elog.text_color_enabled) {
        log_len += elog_strcpy(log_len, log_buf + log_len, CSI_START);
        log_len += elog_strcpy(log_len, log_buf + log_len, color_output_info[level]);
    }
#endif

    /* package level info */
    if (get_fmt_enabled(level, ELOG_FMT_LVL)) {
        log_len += elog_strcpy(log_len, log_buf + log_len, level_output_info[level]);
    }
    /* package tag info */
    if (get_fmt_enabled(level, ELOG_FMT_TAG)) {
        log_len += elog_strcpy(log_len, log_buf + log_len, tag);
        /* if the tag length is less than 50% ELOG_FILTER_TAG_MAX_LEN, then fill space */
        if (tag_len <= ELOG_FILTER_TAG_MAX_LEN / 2) {
            memset(tag_sapce, ' ', ELOG_FILTER_TAG_MAX_LEN / 2 - tag_len);
            log_len += elog_strcpy(log_len, log_buf + log_len, tag_sapce);
        }
        log_len += elog_strcpy(log_len, log_buf + log_len, " ");
    }
    /* package time, process and thread info */
    if (get_fmt_enabled(level, ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
        log_len += elog_strcpy(log_len, log_buf + log_len, "[");
        /* package time info */
        if (get_fmt_enabled(level, ELOG_FMT_TIME)) {
            log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_time());
            if (get_fmt_enabled(level, ELOG_FMT_P_INFO | ELOG_FMT_T_INFO)) {
                log_len += elog_strcpy(log_len, log_buf + log_len, " ");
            }
        }
        /* package process info */
        if (get_fmt_enabled(level, ELOG_FMT_P_INFO)) {
            log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_p_info());
            /* //此处我屏蔽显示空格代码
            if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
                log_len += elog_strcpy(log_len, log_buf + log_len, " ");
            }*/
        }
        /* package thread info */
        /*
        if (get_fmt_enabled(level, ELOG_FMT_T_INFO)) {
            log_len += elog_strcpy(log_len, log_buf + log_len, elog_port_get_t_info());
        }*/ //此处我屏蔽显示线程号的代码
        log_len += elog_strcpy(log_len, log_buf + log_len, "] ");
    }
    /* package file directory and name, function name and line number info */
    if (get_fmt_enabled(level, ELOG_FMT_DIR | ELOG_FMT_FUNC | ELOG_FMT_LINE)) {
        log_len += elog_strcpy(log_len, log_buf + log_len, "(");
        /* package time info */
        if (get_fmt_enabled(level, ELOG_FMT_DIR)) {
            log_len += elog_strcpy(log_len, log_buf + log_len, file);
            if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
                log_len += elog_strcpy(log_len, log_buf + log_len, " ");
            } else if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
                log_len += elog_strcpy(log_len, log_buf + log_len, ":");
            }
        }
        /* package process info */
        if (get_fmt_enabled(level, ELOG_FMT_FUNC)) {
            log_len += elog_strcpy(log_len, log_buf + log_len, func);
            if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
                log_len += elog_strcpy(log_len, log_buf + log_len, ":");
            }
        }
        /* package thread info */
        if (get_fmt_enabled(level, ELOG_FMT_LINE)) {
            snprintf(line_num, ELOG_LINE_NUM_MAX_LEN, "%ld", line);
            log_len += elog_strcpy(log_len, log_buf + log_len, line_num);
        }
        log_len += elog_strcpy(log_len, log_buf + log_len, ")");
    }
    /* package other log data to buffer. '\0' must be added in the end by vsnprintf. */
    fmt_result = vsnprintf(log_buf + log_len, ELOG_LINE_BUF_SIZE - log_len, format, args);

    va_end(args);
    /* calculate log length */
    if ((log_len + fmt_result <= ELOG_LINE_BUF_SIZE) && (fmt_result > -1)) {
        log_len += fmt_result;
    } else {
        /* using max length */
        log_len = ELOG_LINE_BUF_SIZE;
    }
    /* overflow check and reserve some space for CSI end sign and newline sign */
#ifdef ELOG_COLOR_ENABLE
    if (log_len + (sizeof(CSI_END) - 1) + newline_len > ELOG_LINE_BUF_SIZE) {
        /* using max length */
        log_len = ELOG_LINE_BUF_SIZE;
        /* reserve some space for CSI end sign */
        log_len -= (sizeof(CSI_END) - 1);
#else
    if (log_len + newline_len > ELOG_LINE_BUF_SIZE) {
        /* using max length */
        log_len = ELOG_LINE_BUF_SIZE;
#endif /* ELOG_COLOR_ENABLE */
        /* reserve some space for newline sign */
        log_len -= newline_len;
    }
    /* keyword filter */
    if (elog.filter.keyword[0] != '\0') {
        /* add string end sign */
        log_buf[log_len] = '\0';
        /* find the keyword */
        if (!strstr(log_buf, elog.filter.keyword)) {
            /* unlock output */
            elog_output_unlock();
            return;
        }
    }

#ifdef ELOG_COLOR_ENABLE
    /* add CSI end sign */
    if (elog.text_color_enabled) {
        log_len += elog_strcpy(log_len, log_buf + log_len, CSI_END);
    }
#endif

    /* package newline sign */
    log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
    /* output log */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
    extern void elog_async_output(uint8_t level, const char *log, size_t size);
    elog_async_output(level, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
    extern void elog_buf_output(const char *log, size_t size);
    elog_buf_output(log_buf, log_len);
#else
    elog_port_output(log_buf, log_len);
#endif
    /* unlock output */
    elog_output_unlock();
}

/**
 * get format enabled
 *
 * @param level level
 * @param set format set
 *
 * @return enable or disable
 */
static bool get_fmt_enabled(uint8_t level, size_t set) {
    ELOG_ASSERT(level <= ELOG_LVL_VERBOSE);

    if (elog.enabled_fmt_set[level] & set) {
        return true;
    } else {
        return false;
    }
}

/**
 * enable or disable logger output lock
 * @note disable this lock is not recommended except you want output system exception log
 *
 * @param enabled true: enable  false: disable
 */
void elog_output_lock_enabled(bool enabled) {
    elog.output_lock_enabled = enabled;
    /* it will re-lock or re-unlock before output lock enable */
    if (elog.output_lock_enabled) {
        if (!elog.output_is_locked_before_disable && elog.output_is_locked_before_enable) {
            /* the output lock is unlocked before disable, and the lock will unlocking after enable */
            elog_port_output_lock();
        } else if (elog.output_is_locked_before_disable && !elog.output_is_locked_before_enable) {
            /* the output lock is locked before disable, and the lock will locking after enable */
            elog_port_output_unlock();
        }
    }
}

/**
 * Set a hook function to EasyLogger assert. It will run when the expression is false.
 *
 * @param hook the hook function
 */
void elog_assert_set_hook(void (*hook)(const char* expr, const char* func, size_t line)) {
    elog_assert_hook = hook;
}

/**
 * find the log level
 * @note make sure the log level is output on each format
 *
 * @param log log buffer
 *
 * @return log level, found failed will return -1
 */
int8_t elog_find_lvl(const char *log) {
    ELOG_ASSERT(log);
    /* make sure the log level is output on each format */
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ASSERT] & ELOG_FMT_LVL);
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_ERROR] & ELOG_FMT_LVL);
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_WARN] & ELOG_FMT_LVL);
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_INFO] & ELOG_FMT_LVL);
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_DEBUG] & ELOG_FMT_LVL);
    ELOG_ASSERT(elog.enabled_fmt_set[ELOG_LVL_VERBOSE] & ELOG_FMT_LVL);

#ifdef ELOG_COLOR_ENABLE
    uint8_t i;
    size_t csi_start_len = strlen(CSI_START);
    for(i = 0; i < ELOG_LVL_TOTAL_NUM; i ++) {
        if (!strncmp(color_output_info[i], log + csi_start_len, strlen(color_output_info[i]))) {
            return i;
        }
    }
    /* found failed */
    return -1;
#else
    switch (log[0]) {
    case 'A': return ELOG_LVL_ASSERT;
    case 'E': return ELOG_LVL_ERROR;
    case 'W': return ELOG_LVL_WARN;
    case 'I': return ELOG_LVL_INFO;
    case 'D': return ELOG_LVL_DEBUG;
    case 'V': return ELOG_LVL_VERBOSE;
    default: return -1;
    }
#endif
}

/**
 * find the log tag
 * @note make sure the log tag is output on each format
 * @note the tag don't have space in it
 *
 * @param log log buffer
 * @param lvl log level, you can get it by @see elog_find_lvl
 * @param tag_len found tag length
 *
 * @return log tag, found failed will return NULL
 */
const char *elog_find_tag(const char *log, uint8_t lvl, size_t *tag_len) {
    const char *tag = NULL, *tag_end = NULL;

    ELOG_ASSERT(log);
    ELOG_ASSERT(tag_len);
    ELOG_ASSERT(lvl < ELOG_LVL_TOTAL_NUM);
    /* make sure the log tag is output on each format */
    ELOG_ASSERT(elog.enabled_fmt_set[lvl] & ELOG_FMT_TAG);

#ifdef ELOG_COLOR_ENABLE
    tag = log + strlen(CSI_START) + strlen(color_output_info[lvl]) + strlen(level_output_info[lvl]);
#else
    tag = log + strlen(level_output_info[lvl]);
#endif
    /* find the first space after tag */
    if ((tag_end = memchr(tag, ' ', ELOG_FILTER_TAG_MAX_LEN)) != NULL) {
        *tag_len = tag_end - tag;
    } else {
        tag = NULL;
    }

    return tag;
}

/**
 * dump the hex format data to log
 *
 * @param name name for hex object, it will show on log header
 * @param width hex number for every line, such as: 16, 32
 * @param buf hex buffer
 * @param size buffer size
 */
void elog_hexdump(const char *name, uint8_t width, uint8_t *buf, uint16_t size)
{
#define __is_print(ch)       ((unsigned int)((ch) - ' ') < 127u - ' ')

    uint16_t i, j;
    uint16_t log_len = 0;
    char dump_string[8] = {0};
    int fmt_result;

    if (!elog.output_enabled) {
        return;
    }

    /* level filter */
    if (ELOG_LVL_DEBUG > elog.filter.level) {
        return;
    } else if (!strstr(name, elog.filter.tag)) { /* tag filter */
        return;
    }

    /* lock output */
    elog_output_lock();

    for (i = 0; i < size; i += width) {
        /* package header */
        fmt_result = snprintf(log_buf, ELOG_LINE_BUF_SIZE, "D/HEX %s: %04X-%04X: ", name, i, i + width - 1);
        /* calculate log length */
        if ((fmt_result > -1) && (fmt_result <= ELOG_LINE_BUF_SIZE)) {
            log_len = fmt_result;
        } else {
            log_len = ELOG_LINE_BUF_SIZE;
        }
        /* dump hex */
        for (j = 0; j < width; j++) {
            if (i + j < size) {
                snprintf(dump_string, sizeof(dump_string), "%02X ", buf[i + j]);
            } else {
                strncpy(dump_string, "   ", sizeof(dump_string));
            }
            log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
            if ((j + 1) % 8 == 0) {
                log_len += elog_strcpy(log_len, log_buf + log_len, " ");
            }
        }
        log_len += elog_strcpy(log_len, log_buf + log_len, "  ");
        /* dump char for hex */
        for (j = 0; j < width; j++) {
            if (i + j < size) {
                snprintf(dump_string, sizeof(dump_string), "%c", __is_print(buf[i + j]) ? buf[i + j] : '.');
                log_len += elog_strcpy(log_len, log_buf + log_len, dump_string);
            }
        }
        /* overflow check and reserve some space for newline sign */
        if (log_len + strlen(ELOG_NEWLINE_SIGN) > ELOG_LINE_BUF_SIZE) {
            log_len = ELOG_LINE_BUF_SIZE - strlen(ELOG_NEWLINE_SIGN);
        }
        /* package newline sign */
        log_len += elog_strcpy(log_len, log_buf + log_len, ELOG_NEWLINE_SIGN);
        /* do log output */
#if defined(ELOG_ASYNC_OUTPUT_ENABLE)
        extern void elog_async_output(uint8_t level, const char *log, size_t size);
        elog_async_output(ELOG_LVL_DEBUG, log_buf, log_len);
#elif defined(ELOG_BUF_OUTPUT_ENABLE)
        extern void elog_buf_output(const char *log, size_t size);
    elog_buf_output(log_buf, log_len);
#else
        elog_port_output(log_buf, log_len);
#endif
    }
    /* unlock output */
    elog_output_unlock();
}


5. EasyLogger缓冲输出和异步输出配置

  • EasyLogger设置缓冲输出和异步输出的作用是提高输出速度
  • 确实是可能会到时log混乱,如果你的cpu不错,而且不需要追求高速度的log输出可以不用开启

5.1 EasyLogger移植缓冲输出和异步输出

5.1.1 添加elog_async.c和elog_buf.c到工程中
.
├── bin
│   └── main
├── build
├── build.sh
├── CMakeLists.txt
├── include
├── lib
│   ├── CMakeLists.txt
│   └── easylogger
│       ├── CMakeLists.txt
│       ├── inc
│       │   ├── elog_cfg.h
│       │   ├── elog.h
│       │   └── elog_linux_port.h
│       ├── lib
│       │   ├── libeasylogger.a
│       │   └── libeasylogger.so
│       └── src
│           ├── elog_async.c
│           ├── elog_buf.c
│           ├── elog.c
│           ├── elog_linux_port.c
│           ├── elog_port.c
│           └── elog_utils.c
├── script
│   └── CmakeList.py
└── src
    ├── CMakeLists.txt
    └── main.c
5.1.2 添加修改elog_linux_port.c和elog_port.c
elog_linux_port.c,添加线程锁

/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 02:04:24
* @LastEditors: Xiaofang
* @LastEditTime: 2020-08-31 23:55:47
  *************************************************************************/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include "elog_linux_port.h"

#ifdef ELOG_FILE_ENABLE
    const char logfilename[] = "log";
#endif

/**
  * @name: elog_file_write
  * @description: 
  * @note: 
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 成功的长度
  */
int elog_linux_file_write(const char *log, size_t size)
{
#ifdef ELOG_FILE_ENABLE
    int fd = open(logfilename, O_RDWR|O_APPEND);
    int len = write(fd, log, size);
    close(fd);
    return len;
#endif
}

/**
  * @name: elog_linux_port_output
  * @description: //void elog_port_output(const char *log, size_t size) 对应的实现代码,增加输出的模式例如,可以输出到终端,可以输出到文本
  * @note: 对应实现elog_port.c中elog_port_output的代码
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 是否输出成功
  */
int elog_linux_port_output(const char *log, size_t size)
{
    /* output to terminal */
    printf("%.*s", (int)size, log);
#ifdef ELOG_FILE_ENABLE
    /* write the file */
    elog_file_write(log, size);
#endif 
}


/**
  * @name: elog_linux_port_get_time
  * @description: 
  * @note: 
  * @param void
  * @return 时间
  */
const char *elog_linux_port_get_time(void) 
{
    static char cur_system_time[24] = { 0 };
    time_t timep;
    struct tm *p;

    time(&timep);
    p = localtime(&timep);
    if (p == NULL) {
        return "";
    }
    snprintf(cur_system_time, 18, "%02d-%02d %02d:%02d:%02d", p->tm_mon + 1, p->tm_mday,
            p->tm_hour, p->tm_min, p->tm_sec);

    return cur_system_time;
}

/**
  * @name: elog_linux_port_get_p_info
  * @description: 获取进程号
  * @note: 
  * @param void 
  * @return 进程号 
  */
const char *elog_linux_port_get_p_info(void) 
{
    static char cur_process_info[10] = { 0 };
    snprintf(cur_process_info, 10, "pid:%04d", getpid());
    return cur_process_info;
}


/**
  * @name: elog_linux_port_get_t_info
  * @description: 获取线程号
  * @note: 
  * @param void
  * @return 线程号
  */
const char *elog_linux_port_get_t_info(void) 
{
    static char cur_thread_info[10] = { 0 };
    snprintf(cur_thread_info, 10, "tid:%04ld", pthread_self());
    return cur_thread_info;
}

/**
  * @name: elog_linux_port_init
  * @description: linux平台的初始化
  * @note: 
  */
void elog_linux_port_init(void)
{
    //初始化线程锁
    pthread_mutex_init(&output_lock, NULL);
}


/**
  * @name: elog_linux_port_output_lock
  * @description: 开启线程锁
  * @note: 
  */
void elog_linux_port_output_lock(void)
{
    pthread_mutex_lock(&output_lock);
}

/**
  * @name: elog_linux_port_output_unlock
  * @description: 关闭线程锁
  * @note: 
  */
void elog_linux_port_output_unlock(void) {
    pthread_mutex_unlock(&output_lock);
}
elog_port.c


#include <elog.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>

#include "elog_linux_port.h"

static pthread_mutex_t output_lock;
/**
 * EasyLogger port initialize
 *
 * @return result
 */
ElogErrCode elog_port_init(void) {
    ElogErrCode result = ELOG_NO_ERR;

    /* add your code here */
    elog_linux_port_init();
    
    return result;
}

/**
 * output log port interface
 *
 * @param log output of log
 * @param size log size
 */
void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    elog_linux_port_output(log, size);
    
}


/**
 * output lock
 */
void elog_port_output_lock(void) {
    elog_linux_port_output_lock();
}

/**
 * output unlock
 */
void elog_port_output_unlock(void) {
    elog_linux_port_output_unlock();
}

/**
 * get current time interface
 *
 * @return current time
 */
const char *elog_port_get_time(void) {
    
    /* add your code here */
    return elog_linux_port_get_time();
}

/**
 * get current process name interface
 *
 * @return current process name
 */
const char *elog_port_get_p_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_p_info();
}

/**
 * get current thread name interface
 *
 * @return current thread name
 */
const char *elog_port_get_t_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_t_info();
    
}

5.1.3 修改elog_cfg.h
#ifndef _ELOG_CFG_H_
#define _ELOG_CFG_H_
/*---------------------------------------------------------------------------*/
/* enable log output. */
#define ELOG_OUTPUT_ENABLE
/* setting static output log level. range: from ELOG_LVL_ASSERT to ELOG_LVL_VERBOSE */
#define ELOG_OUTPUT_LVL                          ELOG_LVL_VERBOSE
/* enable assert check */
#define ELOG_ASSERT_ENABLE
/* buffer size for every line's log */
#define ELOG_LINE_BUF_SIZE                       1024
/* output line number max length */
#define ELOG_LINE_NUM_MAX_LEN                    5
/* output filter's tag max length */
#define ELOG_FILTER_TAG_MAX_LEN                  30
/* output filter's keyword max length */
#define ELOG_FILTER_KW_MAX_LEN                   16
/* output filter's tag level max num */
#define ELOG_FILTER_TAG_LVL_MAX_NUM              5
/* output newline sign */
#define ELOG_NEWLINE_SIGN                        "\n"
/*---------------------------------------------------------------------------*/
/* enable log color */
#define ELOG_COLOR_ENABLE
/* change the some level logs to not default color if you want */
#define ELOG_COLOR_ASSERT                        (F_MAGENTA B_NULL S_NORMAL)
#define ELOG_COLOR_ERROR                         (F_RED B_NULL S_NORMAL)
#define ELOG_COLOR_WARN                          (F_YELLOW B_NULL S_NORMAL)
#define ELOG_COLOR_INFO                          (F_CYAN B_NULL S_NORMAL)
#define ELOG_COLOR_DEBUG                         (F_GREEN B_NULL S_NORMAL)
#define ELOG_COLOR_VERBOSE                       (F_BLUE B_NULL S_NORMAL)
/*---------------------------------------------------------------------------*/
/* enable asynchronous output mode */
#define ELOG_ASYNC_OUTPUT_ENABLE
/* the highest output level for async mode, other level will sync output */
#define ELOG_ASYNC_OUTPUT_LVL                    ELOG_LVL_ASSERT
/* buffer size for asynchronous output mode */
#define ELOG_ASYNC_OUTPUT_BUF_SIZE               (ELOG_LINE_BUF_SIZE * 10)
/* each asynchronous output's log which must end with newline sign */
#define ELOG_ASYNC_LINE_OUTPUT
/* asynchronous output mode using POSIX pthread implementation */
#define ELOG_ASYNC_OUTPUT_USING_PTHREAD
/*---------------------------------------------------------------------------*/
/* enable buffered output mode */
#define ELOG_BUF_OUTPUT_ENABLE
/* buffer size for buffered output mode */
#define ELOG_BUF_OUTPUT_BUF_SIZE                 (ELOG_LINE_BUF_SIZE * 10)

#endif /* _ELOG_CFG_H_ */

5.2 测试开启和没开启缓冲输出和异步输出的速度

main 
/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 01:41:05
* @LastEditors: Xiaofang
* @LastEditTime: 2020-09-01 02:23:20
  *************************************************************************/

#include <stdio.h>
#include <pthread.h>
#include "elog.h"
#include <unistd.h> 
#include <stdlib.h>

#define TAG "main"


void *easylogger1(void *arg)
{
	struct  timeval tpstart, tpend;
	float   timeuse;
	while(1)
	{
        gettimeofday(&tpstart,NULL);
		for(int i=0;i<100;i++)
		{
			elog_a(TAG, "%d\n",i);
		}

		gettimeofday(&tpend,NULL);
        timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
        timeuse/=1000000;
		printf("----------Used Time:%f--------------\n",timeuse);
		sleep(0.5);
	}
}

void *easylogger2(void *arg)
{
	struct  timeval tpstart, tpend;
	float   timeuse;
	while(1)
	{
        gettimeofday(&tpstart,NULL);
		for(int i=0;i<100;i++)
		{
			elog_a(TAG, "%d\n",i);
		}

		gettimeofday(&tpend,NULL);
        timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
        timeuse/=1000000;
		printf("----------Used Time:%f--------------\n",timeuse);
		sleep(0.5);
	}
}


int main(int argc, char **argv)
{
	struct  timeval tpstart, tpend;
	float   timeuse;

	//1. easylogger的启动流程
	//1.1 关闭printf输出
	//setbuf(stdout, NULL); //不在使用printf做打印信息了
	//1.2 初始化
	elog_init();

	//1.3 设置输出格式
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);  //断言所有都输出
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);

	//elog_set_output_enabled(true);
	//elog_buf_enabled(true);

	//1.5 启动log
	elog_start();
	
	//开启线程

	pthread_t tid1, tid2;
 
	pthread_create(&tid1, NULL, easylogger1, NULL);
	pthread_create(&tid2, NULL, easylogger2, NULL);
	while(1)
	{

		gettimeofday(&tpstart,NULL);
		for(int i=0;i<100;i++)
		{
			elog_a(TAG, "%d\n",i);
		}

		gettimeofday(&tpend,NULL);
        timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+tpend.tv_usec-tpstart.tv_usec;
        timeuse/=1000000;
		printf("----------Used Time:%f--------------\n",timeuse);

		sleep(0.5);
		
	}
	
}

输出100个log的时间大概0.000948
如果通过上面宏关闭异步输出和缓冲输出大概时间0.003662

6. 将日志输出到文本(最后的源码,可直接使用)

修改了一下elog_linux_port.c
/*************************************************************************
* @Descripttion: 
* @Version: 
* @Author: Xiaofang
* @Date: 2020-08-31 02:04:24
* @LastEditors: Xiaofang
* @LastEditTime: 2020-09-01 18:20:38
  *************************************************************************/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include "elog_linux_port.h"

#ifdef ELOG_FILE_ENABLE
    const char logfilename[] = LOGNAME;
#endif

static int fd;
static pthread_mutex_t output_lock;


/**
  * @name: elog_file_write
  * @description: 
  * @note: 
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 成功的长度
  */
int elog_linux_file_write(const char *log, size_t size)
{
    int len=0;
#ifdef ELOG_FILE_ENABLE
    len = write(fd, log, size);
    //close(fd);
    return len;
#endif
}

/**
  * @name: elog_linux_port_output
  * @description: //void elog_port_output(const char *log, size_t size) 对应的实现代码,增加输出的模式例如,可以输出到终端,可以输出到文本
  * @note: 对应实现elog_port.c中elog_port_output的代码
  * @param log:传入的log信息
  * @param size:log信息的大小
  * @return 是否输出成功
  */
int elog_linux_port_output(const char *log, size_t size)
{
    /* output to terminal */
    printf("%.*s", (int)size, log);
#ifdef ELOG_FILE_ENABLE
    /* write the file */
    elog_linux_file_write(log, size);
#endif 
}


/**
  * @name: elog_linux_port_get_time
  * @description: 
  * @note: 
  * @param void
  * @return 时间
  */
const char *elog_linux_port_get_time(void) 
{
    static char cur_system_time[24] = { 0 };
    time_t timep;
    struct tm *p;

    time(&timep);
    p = localtime(&timep);
    if (p == NULL) {
        return "";
    }
    snprintf(cur_system_time, 18, "%02d-%02d %02d:%02d:%02d", p->tm_mon + 1, p->tm_mday,
            p->tm_hour, p->tm_min, p->tm_sec);

    return cur_system_time;
}

/**
  * @name: elog_linux_port_get_p_info
  * @description: 获取进程号
  * @note: 
  * @param void 
  * @return 进程号 
  */
const char *elog_linux_port_get_p_info(void) 
{
    static char cur_process_info[10] = { 0 };
    snprintf(cur_process_info, 10, "pid:%04d", getpid());
    return cur_process_info;
}


/**
  * @name: elog_linux_port_get_t_info
  * @description: 获取线程号
  * @note: 
  * @param void
  * @return 线程号
  */
const char *elog_linux_port_get_t_info(void) 
{
    static char cur_thread_info[10] = { 0 };
    snprintf(cur_thread_info, 10, "tid:%04ld", pthread_self());
    return cur_thread_info;
}

/**
  * @name: elog_linux_port_init
  * @description: linux平台的初始化
  * @note: 
  */
void elog_linux_port_init(void)
{
    //初始化线程锁
    pthread_mutex_init(&output_lock, NULL);
    
#ifdef ELOG_FILE_ENABLE
    /* write the file */
        //open
    fd = open(logfilename, O_RDWR|O_CREAT|O_APPEND);
#endif 


}


/**
  * @name: elog_linux_port_output_lock
  * @description: 开启线程锁
  * @note: 
  */
void elog_linux_port_output_lock(void)
{
    pthread_mutex_lock(&output_lock);
}

/**
  * @name: elog_linux_port_output_unlock
  * @description: 关闭线程锁
  * @note: 
  */
void elog_linux_port_output_unlock(void) {
    pthread_mutex_unlock(&output_lock);
}
elog_linux_port.h
/*
 * @Descripttion: 
 * @Version: 
 * @Author: Xiaofang
 * @Date: 2020-08-31 02:04:46
 * @LastEditors: Xiaofang
 * @LastEditTime: 2020-09-01 02:48:22
 */
#ifndef __ELOG_LINUX_PORT_H__
#define __ELOG_LINUX_PORT_H__

/*需要输出到文件中需要在头文件中定义*/
#define ELOG_FILE_ENABLE 
#ifdef ELOG_FILE_ENABLE
int elog_linux_file_write(const char *log, size_t size);
const char logfilename[] = "log";
#endif


int elog_linux_port_output(const char *log, size_t size);
const char *elog_linux_port_get_p_info(void);
const char *elog_linux_port_get_t_info(void);
const char *elog_linux_port_get_time(void);
void elog_linux_port_init(void);
void elog_linux_port_output_lock(void);
void elog_linux_port_output_unlock(void) ;

#endif

elog_port.c:

#include <elog.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>

#include "elog_linux_port.h"


/**
 * EasyLogger port initialize
 *
 * @return result
 */
ElogErrCode elog_port_init(void) {
    ElogErrCode result = ELOG_NO_ERR;

    /* add your code here */
    elog_linux_port_init();
    
    return result;
}

/**
 * output log port interface
 *
 * @param log output of log
 * @param size log size
 */
void elog_port_output(const char *log, size_t size) {
    
    /* add your code here */
    elog_linux_port_output(log, size);
    
}


/**
 * output lock
 */
void elog_port_output_lock(void) {
    elog_linux_port_output_lock();
}

/**
 * output unlock
 */
void elog_port_output_unlock(void) {
    elog_linux_port_output_unlock();
}

/**
 * get current time interface
 *
 * @return current time
 */
const char *elog_port_get_time(void) {
    
    /* add your code here */
    return elog_linux_port_get_time();
}

/**
 * get current process name interface
 *
 * @return current process name
 */
const char *elog_port_get_p_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_p_info();
}

/**
 * get current thread name interface
 *
 * @return current thread name
 */
const char *elog_port_get_t_info(void) {
    
    /* add your code here */
    return elog_linux_port_get_t_info();
    
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GeekFong

记录不易,坚持更新

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值