模块: Logger
约 3045 字大约 10 分钟
2026-05-21
构建固件和导入到JS
在 C++ 里加入以下代码, 然后重新编译构建固件:
// 为了控制固件的尺寸,BeShell 的 module 是按需引入的。
beshell.use<be::Logger>() ;在JS中导入 logger module:
import * as logger from 'logger'import logger简介
日志模块:将系统输出捕获并以循环日志形式持久化到 flash 分区
logger 模块把 console.log/printf/write 等输出自动捕获,写入指定的 flash 分区(循环覆盖,写满后回绕覆盖最旧数据),设备重启后仍可读取历史日志, 适用于现场问题追踪与远程诊断。
使用前准备
- 分区表:需要一个专用于日志的 data 分区,例如:
log, data, nvs, , 0x10000 - 捕获 printf/write 输出(可选):在 menuconfig 中启用
CONFIG_BESHELL_LOGGER_ENABLE_WRAP(BeShell Configuration → Logger)。 启用后通过链接器--wrap拦截write/printf/vprintf。 不启用时仅捕获 BeConsole 协议通道的输出(console.log 产生的 OUTPUT/EXCEPTION 包)。
特性
- 异步写入:日志经队列交由独立后台任务写 flash,不阻塞业务逻辑
- 循环覆盖:写满分区后自动回绕,覆盖最旧数据
- 时间戳:每条日志自动添加
[YYYY-mm-dd HH:MM:SS]前缀(基于开机时间)
示例
import * as logger from "logger"
// 启动日志功能(分区名需与分区表一致)
logger.setup({ partition: "log" })
console.log("这条输出会被写入日志分区")
// 主动写入一条日志
logger.write("custom log entry")
// 读取日志
console.log("日志长度:", logger.length())
logger.tail() // 在控制台显示最后 20 行模块函数
函数 setup
原型: setup (options:object)
启动日志功能
传入配置对象指定日志分区名称。成功启动后,printf/write 输出(需启用 CONFIG_BESHELL_LOGGER_ENABLE_WRAP)与 console.log 输出都会被自动捕获, 以循环日志形式写入该分区:写满后自动回绕覆盖最旧数据,每条日志自动添加 时间戳前缀。写入由独立后台任务异步完成,不阻塞业务逻辑。
只能启动一次,重复调用直接返回成功(不会重新初始化)。
配置对象格式:
{
partition: string // 日志分区名称(必需,需与分区表一致)
bufferSize: number // 可选,保留参数,当前版本未生效
}参数:
options
类型object
参数说明配置选项
异常:
- 分区不存在或名称非法
- 内存分配失败
返回值:
类型undefined
函数 pause
原型: pause ()
暂停日志捕获功能
调用此函数后,printf 和 write 的输出将停止被捕获到日志分区中。
返回值:
类型undefined
函数 resume
原型: resume ()
恢复日志捕获功能
调用此函数后,printf 和 write 的输出将重新开始被捕获到日志分区中。
返回值:
类型undefined
函数 clear
原型: clear ()
逻辑清空日志数据
将写入位置重置到分区起始状态,此后 length() 返回 0、从新位置开始记录。 旧数据物理上仍留在 flash 中,会被后续写入逐渐覆盖;操作由后台任务异步执行。 如需物理擦除整个分区,请使用 erase()。
返回值:
类型undefined
函数 length
原型: length ()
获取日志数据长度
返回当前日志分区中已写入的日志数据总字节数。 如果日志发生了循环写入,返回值为可用空间大小(分区大小减去元数据大小)。 如果未发生循环,返回值为当前写入位置。
返回值:
类型number
说明日志数据字节数
函数 read
原型: read (start_pos:number=0, length:number=1024)
从日志分区读取数据
从指定位置开始读取指定长度的原始日志数据。返回的数据包含时间戳前缀和原始日志内容。
使用示例:
// 读取前1024字节的日志数据
const data = logger.read(0, 1024);
console.log(data.asString());
// 从第512字节开始读取512字节
const data2 = logger.read(512, 512);参数:
start_pos
类型number
默认值0
参数说明读取起始位置(相对于日志数据区)
length
类型number
默认值1024
参数说明读取长度(字节数)
返回值:
类型ArrayBuffer
说明读取到的原始数据
函数 write
原型: write (data:string|ArrayBuffer, timestampPrefix:boolean=true)
向日志分区写入数据
将指定的数据直接写入到日志分区中,支持字符串和ArrayBuffer两种数据类型。 写入的数据可以选择是否添加时间戳前缀。
使用示例:
// 写入字符串(默认添加时间戳前缀)
logger.write("Hello, World!");
// 写入字符串(不添加时间戳前缀)
logger.write("Hello, World!", false);
// 写入ArrayBuffer(添加时间戳前缀)
const buffer = new ArrayBuffer(10);
const view = new Uint8Array(buffer);
view.fill(65); // 填充字母'A'
logger.write(buffer, true);
// 写入格式化字符串(通过模板字符串)
const value = 42;
logger.write(`Value is: ${value}`);参数:
data
类型string, ArrayBuffer
参数说明要写入的数据
timestampPrefix
类型boolean
默认值true
参数说明是否添加时间戳前缀
返回值:
类型number
说明实际写入的字节数
函数 flush
原型: flush ()
将缓冲区中的数据立即写入到flash分区
当前版本的日志写入由后台任务自动完成,此函数为占位接口(调用后立即返回, 不执行实际操作),保留供将来使用。
返回值:
类型number
说明实际写入的字节数
函数 erase
原型: erase ()
物理擦除日志分区
擦除整个日志分区(整片 flash 擦除,耗时较长、会消耗 flash 寿命), 并将写入位置重置到起始状态。此操作不可逆,所有日志数据将被永久删除。 操作由后台任务异步执行。如只需逻辑清空(不擦除 flash),请使用 clear()。
返回值:
类型undefined
函数 top
原型: top (page:number=0, linesPerPage:number=20)
从日志区头部分页显示日志内容
从日志分区的开头开始,按行分页显示日志内容。每行最多1024字符,超出按新行计算。 直接输出到控制台,不返回JavaScript变量。
使用示例:
// 显示第一页,每页20行
logger.top();
// 显示第2页,每页10行
logger.top(1, 10);参数:
page
类型number
默认值0
参数说明页码(从0开始)
linesPerPage
类型number
默认值20
参数说明每页显示的行数
返回值:
类型undefined
函数 tail
原型: tail (page:number=0, linesPerPage:number=20)
从日志区尾部分页显示日志内容
从日志分区的末尾开始,按行分页显示日志内容。每行最多1024字符,超出按新行计算。 直接输出到控制台,不返回JavaScript变量。
使用示例:
// 显示最后一页,每页20行
logger.tail();
// 显示倒数第2页,每页10行
logger.tail(1, 10);参数:
page
类型number
默认值0
参数说明页码(从0开始,0表示最后一页)
linesPerPage
类型number
默认值20
参数说明每页显示的行数
返回值:
类型undefined
函数 setWriteOffset
原型: setWriteOffset (offset:number)
设置日志分区的写入偏移位置(危险调试接口)
⚠️ 警告:此函数直接改写元数据中的写入偏移,不移动、不校验任何实际日志数据, 属危险调试接口,仅供开发调试/测试使用。
不当的偏移设置会破坏日志结构:
- 偏移指向已有数据中间时,后续写入会从中间覆盖有效日志
- 偏移大于实际数据长度时,read()/top()/tail() 会读到未写入的脏数据
- 日志发生回绕后偏移语义更加复杂,随意修改将导致读取混乱
使用示例:
// 设置写入偏移到1024字节位置
logger.setWriteOffset(1024);
// 从头开始写入(等效于逻辑清空)
logger.setWriteOffset(0);参数:
offset
类型number
参数说明写入偏移位置(字节数)
返回值:
类型undefined
函数 getWriteOffset
原型: getWriteOffset ()
获取当前的写入偏移位置
返回当前日志数据在分区中的写入位置偏移。这可以用于了解当前的写入位置。 由于底层实现限制,此函数返回当前日志数据的总长度作为近似的写入偏移。
使用示例:
// 获取当前写入偏移
const offset = logger.getWriteOffset();
console.log(`Current write offset: ${offset}`);返回值:
类型number
说明当前写入偏移位置(字节数)
函数 fill
原型: fill (data:string|number)
使用指定的数据填充日志分区
使用指定的字符或字节值填充整个日志分区。这通常用于初始化或清除分区数据。 支持字符串(使用第一个字符)或数字(取低8位作为字节值)作为填充数据。
使用示例:
// 使用0填充分区
logger.fill(0);
// 使用字符'A'填充分区
logger.fill('A');
// 使用字符串的首字符填充分区
logger.fill("Hello"); // 使用'H'填充
// 使用0xFF填充分区
logger.fill(255);参数:
data
类型string, number
参数说明填充数据,字符串取首字符,数字取低8位
返回值:
类型undefined
