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查看
对于所有源码,先看其说明文档,其目录结构如下
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
有些人对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总结
EasyLogger之docs查看,我们可以知道文档说明的结构 对于刚拿到源码的同学来说,先看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 环境介绍
.
├── 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
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();
}