远程日志errDump调试教程
一、errdump 概述
LuatOS 错误日志上报功能模块名叫:errDump,errDump 对“量产投放市场的设备,远程调试初步定位问题”至关重要, 强烈建议客户一定要使用此功能
原理:errDump 就是将模块运行过程中产生的错误信息或者应用日志通过 TCP/UDP 上报到互联网上的指定服务器,技术人员可以在服务器上查阅日志,协助远程了解设备运行情况,或者故障诊断。
使用合宙云服务器时,迫于服务器压力,只有手动打开 debug 开关(见后面第六章云平台配置有介绍),才有日志上报。
1.1 errDump 有什么用?
errDump 是 LuatOS 系统中的错误日志上报模块,主要用于远程调试与故障诊断。其核心价值体现在:
- 实时监控设备状态:将设备运行时的错误信息(如系统崩溃、协程异常、网络故障等)通过 TCP/UDP/HTTP 协议上报到指定服务器。
- 支持量产设备维护:对于已投放市场的设备,无需现场调试即可远程定位问题,显著降低维护成本。
- 灵活配置:用户可自定义上报周期、服务器地址及日志类型,适应不同场景需求。
二、演示功能概述
本示例将演示 errdump 异常日志上报的功能。下面是 errdump 功能的详细解析:
2.1 errDump 中存储的错误信息及日志类型
目前 errdump 支持 2 类错误日志的储存与上报:
- 系统任务报错
脚本报错属于系统异常日志,程序报错时会自动写入,如果使用自动上报到 iot 平台则在下次重启会自动读取并上报,如果是自行读取上报的话可通过 errDump.dump(buff,errDump.TYPE_SYS, ture)
** ** 来读取系统异常日志并根据自己需求自定义传输。
- 用户自行写入
用户自行写入异常日志是通过 errDump.record()
接口来保存的异常日志,如果设置了定时上报周期的话则会定期上报到服务器中,如果自行读取上报的话可以通过 errDump.dump(nil, errDump.TYPE_SYS, true)
来读取用户异常日志并根据自己需求自定义传输。
2.2 存储区域与空间管理
日志文件都是储存在文件系统中。
系统异常日志文件和用户异常日志文件最大都是 4KB。
当存储空间不足时,新日志会覆盖最旧的数据。用户可通过 errDump.dump()
手动读取并清理日志,避免自动覆盖。
2.3 日志上报与读取方式
自动上报
通过 errDump.config(enable, period, user_flag, custom_id, host, port)
配置服务器地址和周期(默认 600 秒)。上报成功后,本地日志自动清空。
--每小时上报到一次
errDump.config(true, 3600, nil, nil, "dev_msg1.openluat.com", 12425)
手动读取
使用 errDump.dump(zbuff, type, isDelete)
读取日志,支持指定类型(如系统日志、用户日志)并选择是否删除。
-- 读取系统日志并保留副本
local log_data = errDump.dump(nil, errDump.TYPE_SYS, false)
-- 读取用户日志后立即删除
local result = errDump.dump(nil, errDump.TYPE_USR, true)
注意:errDump.dump
接口返回值 true 表示本次读取前并没有写入数据,false 反之,在删除日志前,最好再读一下确保没有新的数据写入了
自定义传输
禁用自动上报后,用户可通过 errDump.dump()
获取日志内容,再通过 MQTT、HTTP API 等方式发送到自有服务器。
2.4 日志清除机制
自动清除:
设置自动模式的话,上报到服务器成功后,本地日志自动删除。
手动清除:
设置手动读取模组,调用 errDump.dump(nil, type, true)
指定日志类型并删除。
覆盖策略:
系统/用户日志达到 4KB 时,新写入内容覆盖旧数据。
三、准备硬件环境
3.1 Air8101 开发板底板
淘宝购买链接:Air8101 开发板淘宝购买链接 ;
3.2 USB 转串口供电下载扩展板
参考:硬件环境清单,准备以及组装好硬件环境。
四、软件环境
在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。
1. Luatools 工具;
2. 内核固件文件(底层 core 固件文件):固件和 Demo - luatos@air8101 - 合宙模组资料中心
3. LuatOS 需要的脚本和资源文件:https://gitee.com/openLuat/LuatOS-Air8101/tree/master/demo/errdump
4. lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
5. 合宙 IOT 平台账号
准备好软件环境之后,接下来查看如何烧录项目文件到 Air8101 开发板 - luatos@air8101 - 合宙文档中心,将本篇文章中演示使用的项目文件烧录到 Air8101 开发板中。
五、errdump 软件参考
https://docs.openluat.com/air8101/luatos/api/core/errDump/
六、代码示例介绍
6.1 代码实现
使用 Air8101 开发板来演示 errdump 日志上报功能:
在此 demo 中除了 main.lua 外还有三个不同使用场景的 demo 脚本,演示使用 iot 平台的自动上传 errdump_test.lua,手动读取通过串口上传的 errdump_uart.lua,手动读取通过 tcp 上传的 errdump_tcp.lua
main.lua
--[[
必须定义PROJECT和VERSION变量,Luatools工具会用到这两个变量,远程升级功能也会用到这两个变量
PROJECT:项目名,ascii string类型
可以随便定义,只要不使用,就行
VERSION:项目版本号,ascii string类型
如果使用合宙iot.openluat.com进行远程升级,必须按照"XXX.YYY.ZZZ"三段格式定义:
X、Y、Z各表示1位数字,三个X表示的数字可以相同,也可以不同,同理三个Y和三个Z表示的数字也是可以相同,可以不同
因为历史原因,YYY这三位数字必须存在,但是没有任何用处,可以一直写为000
如果不使用合宙iot.openluat.com进行远程升级,根据自己项目的需求,自定义格式即可
本demo演示的功能为:
使用Air8101开发板来演示errdumpy异常日志上报功能
]]
PROJECT = "errdump_demo"
VERSION = "001.000.000"
-- 在日志中打印项目名和项目版本号
log.info("main", PROJECT, VERSION)
-- 加载必须用到的sys功能模块
-- sys功能模块是LuatOS运行框架的基础模块
_G.sys = require("sys")
-- 加载大部分情况下会用到的sysplus功能模块
-- sysplus功能模块是sys功能模块的强力补充
-- 如果项目脚本中用到了sysplus的接口,则打开此处的注释
-- _G.sysplus = require("sysplus")
-- 如果内核固件支持wdt看门狗功能,此处对看门狗进行初始化和定时喂狗处理
-- 如果脚本程序死循环卡死,就会无法及时喂狗,最终会自动重启
if wdt then
--配置喂狗超时时间为9秒钟
wdt.init(9000)
--启动一个循环定时器,每隔3秒钟喂一次狗
sys.timerLoopStart(wdt.feed, 3000)
end
-- 使用LuatOS开发的任何一个项目,都强烈建议使用远程升级FOTA功能
-- 可以使用合宙的iot.openluat.com平台进行远程升级
-- 也可以使用客户自己搭建的平台进行远程升级
-- 远程升级的详细用法,可以参考fota的demo进行使用
PRODUCT_KEY = "XPwaCKtrZywvcwTMvvdGUTtuiP6zLRTY" --换成自己的
-- 启动一个循环定时器
-- 每隔3秒钟打印一次总内存,实时的已使用内存,历史最高的已使用内存情况
-- 方便分析内存使用是否有异常
sys.timerLoopStart(function()
log.info("mem.lua", rtos.meminfo())
log.info("mem.sys", rtos.meminfo("sys"))
end, 10000)
-- 加载errdump测试模块
-- require "errdump_test" --自动上报异常日志到iot平台
-- require "errdump_uart" --手动读取异常日志并通过串口传输
require "errdump_tcp" --手动读取异常日志并通过tcp协议传输
-- 用户代码已结束---------------------------------------------
-- 结尾总是这一句
sys.run()
-- sys.run()之后不要加任何语句!!!!!因为添加的任何语句都不会被执行
errdump_test.lua
--[[
本功能模块演示的内容为:
使用Air8101开发板来演示errdump日志上报功能
使用自动上报异常日志到iot平台
]]
-- 统一联网函数
sys.taskInit(function()
sys.wait(1000)
-----------------------------
---------wifi 联网-----------
-----------------------------
if wlan and wlan.connect then
-- wifi 联网, Air8101系列均支持
local ssid = "kfyy123"
local password = "kfyy123456"
log.info("wifi", ssid, password)
wlan.init()
wlan.setMode(wlan.STATION)
wlan.connect(ssid, password, 1)
local result, data = sys.waitUntil("IP_READY")
log.info("wlan", "IP_READY", result, data)
device_id = wlan.getMac()
end
log.info("已联网")
sys.publish("net_ready")
end)
local function test_user_log()
sys.waitUntil("net_ready") --等待网络连接成功
-- 下面演示自动发送异常日志到iot平台
errDump.config(true, 600, "user_id") -- 默认是关闭,用这个可以额外添加用户标识,比如用户自定义的ID之类
while true do
sys.wait(15000)
errDump.record("测试一下用户的记录功能")
end
end
local function test_error_log() --故意写错用来触发系统异常日志记录
sys.wait(60000)
lllllllllog.info("测试一下用户的记录功能") --默认写错代码死机
end
sys.taskInit(test_user_log) -- 启动errdemp测试任务
sys.taskInit(test_error_log)--启动错误函数任务
errdump_uart.lua
--[[
本功能模块演示的内容为:
使用Air8101开发板来演示errdump日志上报功能
使用手动读取异常日志并通过串口传出
]]
local function test_user_log()
-- 下面演示手动获取异常日志信息,手动读取到异常日志可以上报到自己服务器,或者输出到串口。下面演示通过串口输出系统异常日志和用户记录日志数据,
errDump.config(true, 0,nil,nil) --配置为手动读取,如果配置为自动上报将无法手动读取系统异常日志
-- --初始化串口,用于输出读取到的错误日志
local uartid = 1 -- 根据实际设备选取不同的uartid
uart.setup(
uartid, --串口id
115200, --波特率
8, --数据位
1 --停止位
)
local buff = zbuff.create(4096)
local new_flag = errDump.dump(buff, errDump.TYPE_SYS) -- 开机手动读取一次异常日志
if buff:used() > 0 then
log.info("errBuff",buff:toStr(0, buff:used())) -- 打印出异常日志
uart.write(uartid, buff:toStr(0, buff:used()))
--这里读取到的系统异常日志通过串口输出
end
new_flag = errDump.dump(buff, errDump.TYPE_SYS)
if not new_flag then
log.info("没有新数据了,删除系统错误日志")
errDump.dump(nil, errDump.TYPE_SYS, true)
end
while true do
sys.wait(15000)
errDump.record("测试一下用户的记录功能") --写入用户的日志,注意最大只有4KB,超过部分新的覆盖旧的
local new_flag = errDump.dump(buff, errDump.TYPE_USR)
if new_flag then
log.info("errBuff", buff:toStr(0, buff:used()))
uart.write(uartid, buff:toStr(0, buff:used()))
--这里读取到的用户写入日志通过串口输出
end
new_flag = errDump.dump(buff, errDump.TYPE_USR)
if not new_flag then
log.info("没有新数据了,删除用户错误日志")
errDump.dump(nil, errDump.TYPE_USR, true)
end
end
end
local function test_error_log() --故意写错用来触发系统异常日志记录
sys.wait(60000)
lllllllllog.info("测试一下用户的记录功能") --默认写错代码死机
end
sys.taskInit(test_user_log) -- 启动errdemp测试任务
sys.taskInit(test_error_log)--启动错误函数任务
errdump_tcp.lua
--[[
本功能模块演示的内容为:
使用Air8101开发板来演示errdump日志上报功能
手动读取异常日志上传到自己平台
]]
local taskName = "TCP_TASK"
local libnet = require "libnet" -- libnet库,支持tcp、udp协议所用的同步阻塞接口
local ip = "112.125.89.8" -- 连接tcp服务器的ip地址
local port = 47772 -- 连接tcp服务器的端口
local netCB = nil -- socket服务的回调函数
local connect_state = false -- 连接状态 true:已连接 false:未连接
local protocol = false -- 通讯协议 true:UDP协议 false:TCP协议
local ssl = false -- 加密传输 true:加密 false:不加密
local tx_buff = zbuff.create(1024) -- 发送至tcp服务器的数据
local rx_buff = zbuff.create(1024) -- 从tcp服务器接收到的数据
-- 统一联网函数
sys.taskInit(function()
sys.wait(1000)
-----------------------------
---------wifi 联网-----------
-----------------------------
if wlan and wlan.connect then
-- wifi 联网, Air8101系列均支持
local ssid = "kfyy123"
local password = "kfyy123456"
log.info("wifi", ssid, password)
wlan.init()
wlan.setMode(wlan.STATION)
wlan.connect(ssid, password, 1)
local result, data = sys.waitUntil("IP_READY")
log.info("wlan", "IP_READY", result, data)
device_id = wlan.getMac()
end
log.info("已联网")
sys.publish("net_ready")
end)
function TCP_TASK()
-- 打印一下连接的目标ip和端口号
log.info("connect ip: ", ip, "port:", port)
sys.waitUntil("IP_READY") -- 等待联网成功
netCB = socket.create(nil, taskName) -- 创建socket对象
socket.debug(netCB, true) -- 打开调试日志
socket.config(netCB, nil, protocol, ssl) -- 此配置为TCP连接,无SSL加密
while true do
-- 连接服务器,返回是否连接成功
result = libnet.connect(taskName, 15000, netCB, ip, port)
-- 如果连接成功,则改变连接状态参数,并且随便发一条数据到服务器,看服务器能不能收到
if result then
connect_state = true
libnet.tx(taskName, 0, netCB, "TCP CONNECT")
end
while result do
succ, param, _, _ = socket.rx(netCB, rx_buff) -- 接收数据
if not succ then
log.info("服务器断开了", succ, param, ip, port)
break
end
if rx_buff:used() > 0 then
log.info("收到服务器数据,长度", rx_buff:used())
rx_buff:del()
end
if tx_buff:used() > 0 then
log.info("发送到服务器数据,长度", tx_buff:used())
local result = libnet.tx(taskName, 0, netCB, tx_buff) -- 发送数据
if not result then
log.info("发送失败了", result, param)
break
end
end
tx_buff:del()
if tx_buff:len() > 1024 then
tx_buff:resize(1024)
end
if rx_buff:len() > 1024 then
rx_buff:resize(1024)
end
result, param = libnet.wait(taskName, 15000, netCB)
if not result then
log.info("服务器断开了", result, param)
break
end
end
-- 服务器断开后的行动,由于while true的影响,所以会再次重新执行进行 重新连接。
connect_state = false
libnet.close(d1Name, 5000, netCB)
tx_buff:clear(0)
rx_buff:clear(0)
sys.wait(1000)
end
end
local function test_user_log()
-- 下面演示手动获取异常日志信息,手动读取到异常日志可以上报到自己服务器
errDump.config(true, 0) --配置为手动读取,如果配置为自动上报将无法手动读取系统异常日志
local err_buff = zbuff.create(4096)
local new_flag = errDump.dump(err_buff, errDump.TYPE_SYS) -- 开机手动读取一次异常日志
if err_buff:used() > 0 then
-- log.info(err_buff:toStr(0, err_buff:used())) -- 打印出异常日志
tx_buff:copy(nil, err_buff)
err_buff:del()
if d1Online then -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
sys_send(d1Name, socket.EVENT, 0)
end
end
new_flag = errDump.dump(err_buff, errDump.TYPE_SYS) -- errDump.dumpf返回值:true表示本次读取前并没有写入数据,false反之,在删除日志前,最好再读一下确保没有新的数据写入了
if not new_flag then
log.info("没有新数据了,删除系统错误日志")
errDump.dump(nil, errDump.TYPE_SYS, true)
end
while true do
sys.wait(15000)
errDump.record("测试一下用户的记录功能") --写入用户的日志,注意最大只有4KB,超过部分新的覆盖旧的
local new_flag = errDump.dump(err_buff, errDump.TYPE_USR)
if new_flag then
log.info("errBuff", err_buff:toStr(0, err_buff:used()))
tx_buff:copy(nil, err_buff)
err_buff:del()
if d1Online then -- 如果已经在线了,则发送socket.EVENT消息来打断任务里的阻塞等待状态,让任务循环继续
sys_send(d1Name, socket.EVENT, 0)
end
end
new_flag = errDump.dump(err_buff, errDump.TYPE_USR)
if not new_flag then
log.info("没有新数据了,删除用户错误日志")
errDump.dump(nil, errDump.TYPE_USR, true)
end
end
end
local function test_error_log() --故意写错用来触发系统异常日志记录
sys.wait(60000)
lllllllllog.info("测试一下用户的记录功能") --默认写错代码死机
end
-- libnet库依赖于sysplus,所以只能通过sysplus.taskInitEx创建的任务函数中运行
sysplus.taskInitEx(TCP_TASK, taskName, netCB) --启动tcp task
sys.taskInit(test_user_log) -- 启动errdemp测试任务
sys.taskInit(test_error_log)--启动错误函数任务
6.2 自动上传 iot 平台
6.2.1 云平台配置
合宙云平台:https://iot.openluat.com
6.2.1.1 打开 IOT 平台
客户采购了模块时,如果客户采购人员没有告知这批模块应该放在 IOT 平台的哪个产品下,合宙则会以采购人的手机号为账号,默认密码 888888,为客户创建一个 IOT 账号,用这个账号,可以访问合宙的 IOT 平台,然后会将 8101 的 sta mac 归属到此账号的名下。
6.2.1.2 新建一个项目
6.2.1.3 将你自己建的项目 key 复制到 demo 中
6.2.1.4 打开设备 DEBUG 开关
6.2.2 自动上传 iot 平台功能验证
6.2.2.1 Luatools 日志打印
6.2.2.2 云平台查看错误上报
6.3 手动读取通过串口上传功能验证
手动读取系统异常日志和用户自定义消息,并通过串口输出
6.3.1 Luatools 日志打印
6.3.2 串口打印异常日志
6.4 手动读取通过 tcp 上传功能验证
手动读取系统异常日志和用户自定义消息,并通过 TCP 协议上报到服务器中,本文使用下面这个 TCP 服务器来演示 https://netlab.luatos.com/
6.4.1 启动 TCP 服务器
启动 TCP 服务器并修改 demo 中的 ip 和端口号。
6.4.2 Luatools 日志打印
6.4.3 服务器日志打印
七、总结
本示例介绍了将错误日志上报到合宙云平台的功能。