mirror of
https://github.com/NevermindZZT/letter-shell.git
synced 2025-01-01 09:58:41 +08:00
新增 日志组件
This commit is contained in:
parent
0532f7529b
commit
9015128b06
BIN
doc/img/log_preview.png
Normal file
BIN
doc/img/log_preview.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.7 KiB |
202
extensions/log/log.c
Normal file
202
extensions/log/log.c
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file log.c
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief log
|
||||
* @version 1.0.0
|
||||
* @date 2020-07-30
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "log.h"
|
||||
#include "stdio.h"
|
||||
#include "stdarg.h"
|
||||
#include "shell.h"
|
||||
|
||||
#if LOG_USING_COLOR == 1
|
||||
#define memPrintHead CSI(31) \
|
||||
" Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" \
|
||||
CSI(39)
|
||||
#define memPrintAddr CSI(31)"0x%08x: "CSI(39)
|
||||
#else
|
||||
#define memPrintHead " Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"
|
||||
#define memPrintAddr "0x%08x: "
|
||||
#endif
|
||||
|
||||
Log *logList[LOG_MAX_NUMBER] = {0};
|
||||
|
||||
|
||||
/**
|
||||
* @brief 注册log对象
|
||||
*
|
||||
* @param log log对象
|
||||
*/
|
||||
void logRegister(Log *log, Shell *shell)
|
||||
{
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
if (shell)
|
||||
{
|
||||
log->shell = shell;
|
||||
shellCompanionAdd(shell, SHELL_COMPANION_ID_LOG, log);
|
||||
}
|
||||
#endif
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] == 0)
|
||||
{
|
||||
logList[i] = log;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 注销log对象
|
||||
*
|
||||
* @param log log对象
|
||||
*/
|
||||
void logUnRegister(Log *log)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] == log)
|
||||
{
|
||||
logList[i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置log日志级别
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level 日志级别
|
||||
*/
|
||||
void logSetLevel(Log *log, LogLevel level)
|
||||
{
|
||||
logAssert(log, return);
|
||||
log->level = level;
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
|
||||
logSetLevel, logSetLevel, set log level);
|
||||
|
||||
|
||||
/**
|
||||
* @brief log格式化写入数据
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level log级别
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
void logWrite(Log *log, LogLevel level, char *fmt, ...)
|
||||
{
|
||||
char buffer[LOG_BUFFER_SIZE];
|
||||
va_list vargs;
|
||||
short len;
|
||||
|
||||
va_start(vargs, fmt);
|
||||
len = vsnprintf(buffer, LOG_BUFFER_SIZE - 1, fmt, vargs);
|
||||
va_end(vargs);
|
||||
|
||||
if (log == LOG_ALL_OBJ)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i]
|
||||
&& logList[i]->active
|
||||
&& logList[i]->level >= level)
|
||||
{
|
||||
logList[i]->write(buffer, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (log && log->active && log->level >= level)
|
||||
{
|
||||
log->write(buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 16进制输出
|
||||
*
|
||||
* @param log log对象
|
||||
* @param base 内存基址
|
||||
* @param length 长度
|
||||
*/
|
||||
void logHexDump(Log *log, void *base, unsigned int length)
|
||||
{
|
||||
unsigned char *address;
|
||||
unsigned int len = length;
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
logWrite(log, LOG_NONE, "memory of 0x%08x, size: %d:\r\n", (unsigned int)base, length);
|
||||
|
||||
address = (unsigned char *)((unsigned int)base & (~0x0000000F));
|
||||
length += (unsigned int)base - (unsigned int)address;
|
||||
length = (length + 15) & (~0x0000000F);
|
||||
|
||||
logWrite(log, LOG_NONE, memPrintHead"\r\n");
|
||||
|
||||
while (length)
|
||||
{
|
||||
logWrite(log, LOG_NONE, memPrintAddr, (unsigned int)address);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((unsigned int)(address + i) < (unsigned int)base
|
||||
|| (unsigned int)(address + i) >= (unsigned int)base + len)
|
||||
{
|
||||
logWrite(log, LOG_NONE, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrite(log, LOG_NONE, "%02x ", *(address + i));
|
||||
}
|
||||
}
|
||||
logWrite(log, LOG_NONE, "| ");
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((unsigned int)(address + i) < (unsigned int)base
|
||||
|| (unsigned int)(address + i) >= (unsigned int)base + len)
|
||||
{
|
||||
logWrite(log, LOG_NONE, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*(address + i) >= 32 && *(address + i) <= 126)
|
||||
{
|
||||
logWrite(log, LOG_NONE, "%c", *(address + i));
|
||||
}
|
||||
else
|
||||
{
|
||||
logWrite(log, LOG_NONE, ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
logWrite(log, LOG_NONE, " |\r\n");
|
||||
address += 16;
|
||||
length -= 16;
|
||||
}
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
|
||||
hexdump, logHexDump, hex dump\r\n hexdump [log] [base] [len]);
|
||||
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
void logSwitchLevel(Shell *shell)
|
||||
{
|
||||
Log *log = shellCompanionGet(shell, SHELL_COMPANION_ID_LOG);
|
||||
SHELL_ASSERT(log, return);
|
||||
log->level = (LogLevel)(log->level >= LOG_ALL ? LOG_NONE : (log->level + 1));
|
||||
logPrintln("set log level: %d", log->level);
|
||||
}
|
||||
SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x04000000, logSwitchLevel, switch log level);
|
||||
|
||||
#endif /** SHELL_USING_COMPANION == 1 */
|
191
extensions/log/log.h
Normal file
191
extensions/log/log.h
Normal file
@ -0,0 +1,191 @@
|
||||
/**
|
||||
* @file log.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief log
|
||||
* @version 1.0.0
|
||||
* @date 2020-07-30
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __LOG_H__
|
||||
#define __LOG_H__
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#define LOG_VERSION "1.0.0"
|
||||
|
||||
#define SHELL_COMPANION_ID_LOG -2
|
||||
|
||||
#define LOG_BUFFER_SIZE 256 /**< log输出缓冲大小 */
|
||||
#define LOG_USING_COLOR 1 /**< 是否使用颜色 */
|
||||
#define LOG_MAX_NUMBER 5 /**< 允许注册的最大log对象数量 */
|
||||
#define LOG_AUTO_TAG 1 /**< 是否自动添加TAG */
|
||||
#define LOG_END "\r\n" /**< log信息结尾 */
|
||||
#define LOG_TAG __FUNCTION__ /**< 自定添加的TAG */
|
||||
#define LOG_TIME_STAMP 0 /**< 设置获取系统时间戳 */
|
||||
|
||||
#ifndef LOG_ENABLE
|
||||
#define LOG_ENABLE 1 /**< 使能log */
|
||||
#endif
|
||||
|
||||
#define LOG_ALL_OBJ ((Log *)-1) /**< 所有已注册的log对象 */
|
||||
|
||||
/**
|
||||
* 终端字体颜色代码
|
||||
*/
|
||||
#define CSI_BLACK 30 /**< 黑色 */
|
||||
#define CSI_RED 31 /**< 红色 */
|
||||
#define CSI_GREEN 32 /**< 绿色 */
|
||||
#define CSI_YELLOW 33 /**< 黄色 */
|
||||
#define CSI_BLUE 34 /**< 蓝色 */
|
||||
#define CSI_FUCHSIN 35 /**< 品红 */
|
||||
#define CSI_CYAN 36 /**< 青色 */
|
||||
#define CSI_WHITE 37 /**< 白色 */
|
||||
#define CSI_BLACK_L 90 /**< 亮黑 */
|
||||
#define CSI_RED_L 91 /**< 亮红 */
|
||||
#define CSI_GREEN_L 92 /**< 亮绿 */
|
||||
#define CSI_YELLOW_L 93 /**< 亮黄 */
|
||||
#define CSI_BLUE_L 94 /**< 亮蓝 */
|
||||
#define CSI_FUCHSIN_L 95 /**< 亮品红 */
|
||||
#define CSI_CYAN_L 96 /**< 亮青 */
|
||||
#define CSI_WHITE_L 97 /**< 亮白 */
|
||||
#define CSI_DEFAULT 39 /**< 默认 */
|
||||
|
||||
#define CSI(code) "\033["#code"m" /**< ANSI CSI指令 */
|
||||
|
||||
/**
|
||||
* log级别字符(包含颜色)
|
||||
*/
|
||||
#if LOG_USING_COLOR == 1
|
||||
#define ERROR_TEXT CSI(31)"E(%d) %s:"CSI(39) /**< 错误标签 */
|
||||
#define WARNING_TEXT CSI(33)"W(%d) %s:"CSI(39) /**< 警告标签 */
|
||||
#define INFO_TEXT CSI(32)"I(%d) %s:"CSI(39) /**< 信息标签 */
|
||||
#define DEBUG_TEXT CSI(34)"D(%d) %s:"CSI(39) /**< 调试标签 */
|
||||
#define VERBOSE_TEXT CSI(36)"V(%d) %s:"CSI(39) /**< 冗余信息标签 */
|
||||
#else
|
||||
#define ERROR_TEXT "E(%d) %s:"
|
||||
#define WARNING_TEXT "W(%d) %s:"
|
||||
#define INFO_TEXT "I(%d) %s:"
|
||||
#define DEBUG_TEXT "D(%d) %s:"
|
||||
#define VERBOSE_TEXT "V(%d) %s:"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志级别定义
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LOG_NONE = 0, /**< 无级别 */
|
||||
LOG_ERROR = 1, /**< 错误 */
|
||||
LOG_WRANING = 2, /**< 警告 */
|
||||
LOG_INFO = 3, /**< 消息 */
|
||||
LOG_DEBUG = 4, /**< 调试 */
|
||||
LOG_VERBOSE = 5, /**< 冗余 */
|
||||
LOG_ALL = 6, /**< 所有日志 */
|
||||
} LogLevel;
|
||||
|
||||
|
||||
/**
|
||||
* @brief log对象定义
|
||||
*
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void (*write)(char *, short); /**< 写buffer */
|
||||
char active; /**< 是否激活 */
|
||||
LogLevel level; /**< 日志级别 */
|
||||
Shell *shell; /**< 关联shell对象 */
|
||||
} Log;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief log打印(自动换行)
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logPrintln(format, ...) \
|
||||
logWrite(LOG_ALL_OBJ, LOG_NONE, format"\r\n", ##__VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志格式化输出
|
||||
*
|
||||
* @param text 消息文本
|
||||
* @param level 日志级别
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logFormat(text, level, fmt, ...) \
|
||||
if (LOG_ENABLE) {\
|
||||
logWrite(LOG_ALL_OBJ, level, text" "fmt""LOG_END, \
|
||||
LOG_TIME_STAMP, LOG_TAG, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
* @brief 错误log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logError(fmt, ...) \
|
||||
logFormat(ERROR_TEXT, LOG_ERROR, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 警告log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logWarning(fmt, ...) \
|
||||
logFormat(WARNING_TEXT, LOG_WRANING, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 信息log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logInfo(fmt, ...) \
|
||||
logFormat(INFO_TEXT, LOG_INFO, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 调试log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logDebug(fmt, ...) \
|
||||
logFormat(DEBUG_TEXT, LOG_DEBUG, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 冗余log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logVerbose(fmt, ...) \
|
||||
logFormat(VERBOSE_TEXT, LOG_VERBOSE, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 断言
|
||||
*
|
||||
* @param expr 表达式
|
||||
* @param action 断言失败操作
|
||||
*/
|
||||
#define logAssert(expr, action) \
|
||||
if (!(expr)) { \
|
||||
logError("\"" #expr "\" assert failed at file: %s, line: %d", __FILE__, __LINE__); \
|
||||
action; \
|
||||
}
|
||||
|
||||
void logRegister(Log *log, Shell *shell);
|
||||
void logUnRegister(Log *log);
|
||||
void logSetLevel(Log *log, LogLevel level);
|
||||
void logWrite(Log *log, LogLevel level, char *fmt, ...);
|
||||
void logHexDump(Log *log, void *base, unsigned int length);
|
||||
|
||||
#endif
|
214
extensions/log/readme.md
Normal file
214
extensions/log/readme.md
Normal file
@ -0,0 +1,214 @@
|
||||
# log
|
||||
|
||||
![version](https://img.shields.io/badge/version-1.0.0-brightgreen.svg)
|
||||
![standard](https://img.shields.io/badge/standard-c99-brightgreen.svg)
|
||||
![build](https://img.shields.io/badge/build-2020.08.02-brightgreen.svg)
|
||||
![license](https://img.shields.io/badge/license-MIT-brightgreen.svg)
|
||||
|
||||
嵌入式日志打印工具
|
||||
|
||||
![preview](../../doc/img/log_preview.png)
|
||||
|
||||
- [log](#log)
|
||||
- [简介](#简介)
|
||||
- [使用](#使用)
|
||||
- [配置](#配置)
|
||||
- [API](#api)
|
||||
- [logPrintln](#logprintln)
|
||||
- [logError](#logerror)
|
||||
- [logWarning](#logwarning)
|
||||
- [logInfo](#loginfo)
|
||||
- [logDebug](#logdebug)
|
||||
- [logVerbose](#logverbose)
|
||||
- [logAssert](#logassert)
|
||||
- [logRegister](#logregister)
|
||||
- [logSetLevel](#logsetlevel)
|
||||
- [logHexDump](#loghexdump)
|
||||
- [结合letter shell尾行模式](#结合letter-shell尾行模式)
|
||||
- [其他用法](#其他用法)
|
||||
- [单独控制某个文件日志](#单独控制某个文件日志)
|
||||
|
||||
## 简介
|
||||
|
||||
log是一个用于嵌入式系统的日志打印工具,可以为日志定义不同的级别,然后设置日志工具的打印级别,可以进行日志打印的控制
|
||||
|
||||
此外,log通过letter shell的伴生对象功能,可以和letter shell结合,实现log和shell的绑定等功能
|
||||
|
||||
## 使用
|
||||
|
||||
1. 实现log写buffer函数
|
||||
|
||||
```C
|
||||
void uartLogWrite(char *buffer, short len)
|
||||
{
|
||||
serialTransmit(&debugSerial, (uint8_t *)buffer, len, 0x100);
|
||||
}
|
||||
```
|
||||
|
||||
2. 定义log对象
|
||||
|
||||
```C
|
||||
Log uartLog = {
|
||||
.write = uartLogWrite,
|
||||
.active = true,
|
||||
.level = LOG_DEBUG
|
||||
};
|
||||
```
|
||||
|
||||
3. 注册log对象
|
||||
|
||||
```C
|
||||
logRegister(&uartLog, NULL);
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
通过修改log.h文件中的宏,可以对log工具进行配置
|
||||
|
||||
| 宏 | 意义 |
|
||||
| --------------- | ------------------------- |
|
||||
| LOG_BUFFER_SIZE | log输出缓冲大小 |
|
||||
| LOG_USING_COLOR | 是否使用颜色 |
|
||||
| LOG_MAX_NUMBER | 允许注册的最大log对象数量 |
|
||||
| LOG_AUTO_TAG | 是否自动添加TAG |
|
||||
| LOG_END | log信息结尾 |
|
||||
| LOG_TAG | 自定添加的TAG |
|
||||
| LOG_TIME_STAMP | 设置获取系统时间戳 |
|
||||
|
||||
## API
|
||||
|
||||
以下是log工具部分API的说明
|
||||
|
||||
### logPrintln
|
||||
|
||||
宏声明,用于一般的打印输出
|
||||
|
||||
```C
|
||||
#define logPrintln(format, ...)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `format` 输出格式
|
||||
- `...` 可变参数
|
||||
|
||||
### logError
|
||||
|
||||
宏声明,错误日志级别输出
|
||||
|
||||
```C
|
||||
#define logError(fmt, ...)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `fmt` 输出格式
|
||||
- `...` 可变参数
|
||||
|
||||
### logWarning
|
||||
|
||||
宏声明,警告日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logInfo
|
||||
|
||||
宏声明,信息日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logDebug
|
||||
|
||||
宏声明,调试日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logVerbose
|
||||
|
||||
宏声明,冗余日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logAssert
|
||||
|
||||
宏声明,断言
|
||||
|
||||
```C
|
||||
#define logAssert(expr, action)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `expr` 表达式
|
||||
- `action` 断言失败执行操作
|
||||
|
||||
### logRegister
|
||||
|
||||
注册log对象
|
||||
|
||||
```C
|
||||
void logRegister(Log *log, Shell *shell)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `shell` 关联的shell对象
|
||||
|
||||
### logSetLevel
|
||||
|
||||
设置日志级别
|
||||
|
||||
```C
|
||||
void logSetLevel(Log *log, LogLevel level)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `level` 日志级别
|
||||
|
||||
### logHexDump
|
||||
|
||||
数据16进制打印
|
||||
|
||||
```C
|
||||
void logHexDump(Log *log, void *base, unsigned int length)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `base` 数据基址
|
||||
- `length` 数据长度
|
||||
|
||||
## 结合letter shell尾行模式
|
||||
|
||||
log工具可以结合letter shell的尾行模式,实现log和shell共用一个终端,但不影响shell交互体验
|
||||
|
||||
1. 使用`shellWriteEndLine`事项log写buffer函数
|
||||
|
||||
```C
|
||||
void uartLogWrite(char *buffer, short len)
|
||||
{
|
||||
if (uartLog.shell)
|
||||
{
|
||||
shellWriteEndLine(uartLog.shell, buffer, len);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. 定义log对象
|
||||
|
||||
```C
|
||||
Log uartLog = {
|
||||
.write = uartLogWrite,
|
||||
.active = true,
|
||||
.level = LOG_DEBUG
|
||||
};
|
||||
```
|
||||
|
||||
3. 注册log对象
|
||||
|
||||
```C
|
||||
logRegister(&uartLog, &shell);
|
||||
```
|
||||
|
||||
## 其他用法
|
||||
|
||||
### 单独控制某个文件日志
|
||||
|
||||
log工具可以单独对某个文件的日志进行打印控制,使用时,在对应的.c文件中加入
|
||||
|
||||
```C
|
||||
#undef LOG_ENABLE
|
||||
#define LOG_ENABLE 1
|
||||
```
|
||||
|
||||
即可单独控制某个文件的日志开关
|
Loading…
x
Reference in New Issue
Block a user