EasyLogger | A lightweight and high-performance log library

Selected columns of embedded open source projects

This column was created by Mculover666, the main content is to find high-quality open source projects in the embedded field, one is to help developers use open source projects to achieve more functions, and the other is to learn the code and the implementation ideas behind these open source projects through these open source projects To improve your own code level, compared with other columns, the advantages of this column are:

It does not simply introduce the sharing project, but also includes the process of sharing the author's personal practice, and even an interpretation of the design ideas behind it .

The open source projects currently included in this column are:

If the open source project you wrote or found is good, welcome to leave a message or private message to this column to share double the happiness!

1. EasyLogger

The open source project brought to you in this issue is EasyLogger, a lightweight and high-performance log library , author armink, currently harvesting 1.1K stars, following the MIT open source license agreement.

EasyLogger is an ultra-lightweight, high-performance C / C ++ log library, which is very suitable for resource-sensitive software projects. In contrast, EasyLogger has simpler functions, fewer interfaces to users, and faster start , More practical functions support dynamic expansion in the form of plug-ins.

Currently EasyLogger supports the following functions:

  • Log output mode supports serial port, flash, file, etc .;
  • The log content can include level, timestamp, thread information, process information, etc .;
  • Support multiple operating systems, support bare metal;
  • Different levels of logs support different colors;

Project address: https://github.com/armink/EasyLogger

2. Port EasyLogger

2.1. Porting ideas

During the migration process, there are two main references: the project's readme document and demo project.

For these open source projects, in fact, there are only two steps to port:

  • ① Add source code to bare metal project;
  • ② The required interface can be realized;

2.2. Preparing the bare metal project

In this article, I am using the Winnie the Pooh IoT development kit. The main control chip is STM32L431RCT6:

Before transplanting, I need to prepare a bare metal project. I use STM32CubeMX to generate, use the USART1 query method to send data, and redirect printf to USART1 . The specific process Please refer to:

The serial port USART1 is configured as follows:

after the project is generated, the printf redirection code is as follows:

#include <stdio.h>

int fputc(int ch, FILE *stream)
{
    /* 堵塞判断串口是否发送完成 */
    while((USART1->ISR & 0X40) == 0);

    /* 串口发送完成,将该字符发送 */
    USART1->TDR = (uint8_t) ch;

    return ch;
}

After the bare metal project is ready, easylogger will be transplanted.

2.3. Add elog to the project

① Copy the source code to the project:

② Add the easylogge component source code file in keil:

  • port/elog_port.c: Elog port interface file;
  • src/elog.c: Source code of elog core function;
  • src/elog_utils.c: Some c library tool function implementations used by elog;
  • src/elog_buf.c(Optional addition): elog buffer output mode source code;
  • src/elog_async.c(Optional addition): elog asynchronous output mode source code;

③ Add the easylogger/incheader file path to keil:

2.4. Implement the elog port

The port of elog has been written. In the elog_port.cfile, you only need to add code in the function body.

① elog initialization interface

ElogErrCode elog_port_init(void);

If it involves the subsequent initialization of resources used by elog, such as dynamically applying for the allocation of buffer memory, you can put it in this interface, and keep the default in this article.

② elog output interface (emphasis)

//开头添加
#include <stdio.h>

……

//接口实现
void elog_port_output(const char *log, size_t size) {
	//日志使用printf输出,printf已经重定向到串口USART1
	printf("%.*s", size, log);
}

There is a small knowledge point here, which %smeans that the string output .<十进制数>is a precision control format character. When outputting characters, it means the number of output characters. During precision control, the decimal number after the decimal point can be used *to occupy a place. The specific value of precision control.

③ Log output lock / unlock interface

This interface can lock / unlock the log output interface to ensure the correctness of the log during concurrent output. The bare metal program is used in this article, so use the global interrupt to close the lock and the global interrupt to unlock:

//开头添加
#include <stm32l4xx_hal.h>

……

//接口实现
void elog_port_output_lock(void) {
    
    //关闭全局中断
	__set_PRIMASK(1);
  
}
void elog_port_output_unlock(void) {
    
    //开启全局中断
	__set_PRIMASK(0);
    
}

There are many ways for STM32 to switch global interrupts. In this article, directly operate the PRIMASK register to quickly mask / open global interrupts. Refer to the article:

https://blog.csdn.net/working24hours/article/details/88323241

④ System information acquisition interface

elog provides three interfaces for obtaining the current time, obtaining the process number, and obtaining the thread number. Because this article is ported to the bare metal project and does not provide time support, all three interfaces return empty strings, as follows:

const char *elog_port_get_time(void) {
    
	return "";
    
}
const char *elog_port_get_p_info(void) {

	return "";
    
}
const char *elog_port_get_t_info(void) {

	return "";
    
}

2.5. Configure elog

The core functions of elog, macro definition and core parameter macro definition, are in the configuration file elog_cfg.h. In this article, only the important macro definitions are described.

Log output master switch:

/* enable log output. */
#define ELOG_OUTPUT_ENABLE

The newline macro definition is modified as follows:

/* output newline sign */
#define ELOG_NEWLINE_SIGN                        "\r\n"

Log output switch with color:

/* enable log color */
#define ELOG_COLOR_ENABLE

The source code for asynchronous output and buffer output is not added during the migration, so turn off these two functions:

At this point, the migration configuration is complete, and you can start using it happily!

3. Use easylogger

3.1. Initializing elog

The elog needs to be initialized before use. There are three steps in the process:
① Initialize the elog

ElogErrCode elog_init(void);

② Set log output format

void elog_set_fmt(uint8_t level, size_t set);

The first parameter indicates the output format corresponding to which log output level is set. Choose one from the following macro definitions:

/* output log's level */
#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 second parameter is the log output format, given by the enumeration, which can be freely combined and matched:

/* 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)

③ Start elog

void elog_start(void);

Next, after the usart1 initialization function in the main function, write the elog initialization code before while (1):

/* USER CODE BEGIN 2 */
/* 初始化elog */
elog_init();

/* 设置每个级别的日志输出格式 */
//输出所有内容
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
//输出日志级别信息和日志TAG
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TAG);
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG);
//除了时间、进程信息、线程信息之外,其余全部输出
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~(ELOG_FMT_TIME | ELOG_FMT_P_INFO | ELOG_FMT_T_INFO));
//输出所有内容
elog_set_fmt(ELOG_LVL_VERBOSE, ELOG_FMT_ALL);

/* 启动elog */
elog_start();

/* USER CODE END 2 */

3.2. Elog log output

Each level in elog has a complete way, two simplified ways, you can choose when you use it:

#define elog_assert(tag, ...) 
#define elog_a(tag, ...) //简化方式1,每次需填写 LOG_TAG
#define log_a(...)       //简化方式2,LOG_TAG 在文件顶部定义,使用前无需填写 LOG_TAG

#define elog_error(tag, ...)
#define elog_e(tag, ...)
#define log_e(...)

#define elog_warn(tag, ...)
#define elog_w(tag, ...)
#define log_w(...)

#define elog_info(tag, ...)
#define elog_i(tag, ...)
#define log_i(...)

#define elog_debug(tag, ...)
#define elog_d(tag, ...)
#define log_d(...)

#define elog_verbose(tag, ...)
#define elog_v(tag, ...)
#define log_v(...)

The first two only need to include the <elog.h>header file when using it . In addition to the header file, the third method also needs to define the TAG macro definition at the beginning of the file, which is the same as printf, so I use the third method here Demo.

First define the TAG macro in the main.c file, including the header file:

/* USER CODE BEGIN Includes */
#define LOG_TAG    "main"

#include <elog.h>

/* USER CODE END Includes */

Then after the elog initialization code written in the main function, continue to add code to test the use of elog:

log_a("Hello EasyLogger!");
log_e("Hello EasyLogger!");
log_w("Hello EasyLogger!");
log_i("Hello EasyLogger!");
log_d("Hello EasyLogger!");
log_v("Hello EasyLogger!");

Compile, burn, and use the serial terminal (Mobaxterm) to view the serial output:

3.3. Colorful output

To elog_cfg.henable colorful logs, it is not enough to enable color output only in . You also need to enable the output using the API:

void elog_set_text_color_enabled(bool enabled);

Enable text color output when initializing elog:

compile, download, and view output again:

the foreground color, background color, and font of each level of log can be elog_cfg.hmodified in the macro definition, the value of the macro definition elog.cis given in View, for example, here I am modifying the ERROR level log to flash font:

compile, download, view output:

3.4. Memory usage before and after migration

The bare metal project before migration only has the usart1 transceiver function, and the memory comparison between the two after transplanting easylogger is as follows:

3.5. Advanced features of elog

In addition to the basic logging function, elog also provides some advanced functions, such as:

  • Log output filtering function: log can be filtered by level, TAG, keywords;
  • Buffered output mode;
  • Asynchronous output mode;

How to use these functions is described in detail in the project's readme document. This article is limited to space. These advanced functions are not described in detail. If you are interested in depth, you can study by yourself.

4. Interpretation of design ideas

4.1. Data processing

The most basic difference between using the log printing component and using printf is that it outputs more information that is helpful for debugging, which can be understood as a processing of the output data.

The information of the file, function name, and line number where the print statement is located makes use of the functions of the compiler's built-in macros :

  • __FILE__:file name
  • __FUNCTION__:Function name
  • __LINE__: Line number

The output of colored characters in the terminal is to use the ANSI escape code, which is the Escape sequence screen control code. For a detailed explanation and examples of these two knowledge points, please read:

The function for processing the output content in elog is:

/**
 * 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, ...) ;

4.2. Log output mode

As the saying goes, the master leads the door, and the practice is personal. This article describes only the basic functions of the log printing component. Using printf to directly implement the log output interface, so there is no difference between the log output mode and the printf output, but there is more information .

elog supports asynchronous output mode . When the asynchronous output mode is turned on, it will improve the execution efficiency of user applications. When the application is performing log output, it can return directly without waiting for the log to be completely output .

elog also supports the buffered output mode . After the buffered output mode is turned on, if the buffer is not full, the user thread can directly return without waiting for the complete output of the log when the log is output . However, when the log buffer is full, it will occupy user threads and automatically output all the logs in the buffer clean.

These two log output modes that do not need to wait and return directly are very important when printing a large amount of log information. The code that prints the log has less effect on normal applications. The article is no longer described, and readers are encouraged to study it by themselves.

5. Project engineering source code acquisition and problem communication

At present, I uploaded the Easylogger source code and the project source code I transplanted to the Xiongpai STM32L431RCT6 development board to the QQ group (including several copies of the HAL library, and the relative speed of the QQ is faster). It can be downloaded in the QQ group. Exchange, of course, everyone is welcome to share their own transplanted projects into the QQ group :

put the QR group QR code:

To receive more exciting articles and resource pushes, please subscribe to my WeChat public account: "mculover666".

Published 277 original articles · praised 992 · 350,000 views

Guess you like

Origin blog.csdn.net/Mculover666/article/details/105371993