跳转至

04 远程日志errDump调试教程

作者:孟伟

一、errdump 概述

LuatOS 异常日志上报功能模块名叫:errDump,errDump 对"量产投放市场的设备,远程调试初步定位问题"至关重要,强烈建议客户一定要使用此功能

原理:errDump 就是将模块运行过程中产生的异常信息或者用户调试日志通过 UDP 上报到互联网上的指定服务器,技术人员可以在服务器上查阅日志,协助远程了解设备运行情况,或者故障诊断。

支持日志自动上报到合宙 IOT 平台,也支持自动上报到用户自己的 UDP 服务器,也支持手动读取出异常日志,通过 tcp 或者串口发送出去 使用合宙云服务器时,迫于服务器压力,只有在合宙 IOT 平台手动打开 debug 开关,才有日志上报。 需要注意的是,使用自动上报到自己的 UDP 服务器时,收到上报的 errdump 日志需要返回一个大写的“OK”,否则模组会认为没有上报成功,会重复上报。

下面是使用 errdump 的几种情况:

1.1 errDump 有什么用?

errDump 是 LuatOS 系统中的异常日志上报模块,主要用于远程调试与故障诊断。其核心价值体现在:

  • 实时监控设备状态:将设备运行时的错误信息或用户调试日志通过 UDP 协议上报到指定服务器。
  • 支持量产设备维护:对于已投放市场的设备,无需现场调试即可远程定位问题,显著降低维护成本。
  • 灵活配置:用户可自定义上报周期、服务器地址及日志类型,适应不同场景需求。

二、演示功能概述

主要是使用 Air8101 核心板演示四种 errdump 异常日志上报功能,使用的时候根据自己需求在 main.lua 文件中选择要使用的功能,注意不能同时使用自动上报和手动读取功能。

(1)自动上报异常日志到合宙IOT平台

(2)自动上报异常日志到自建udp服务器

(3)手动读取异常日志并通过串口传输

(4)手动读取异常日志并通过tcp传输

下面是 errdump 功能的详细解析:

2.1 errDump 中存储的错误信息及日志类型

目前 errdump 支持 2 类错误日志的储存与上报:

  1. errDump.TYPE_SYS

系统异常日志是指程序运行过程中产生的异常信息,例如程序崩溃、内存泄漏、死循环、脚本错误等。系统异常日志会自动写入到 errDump 模块中,如果使用自动上报到合宙 IOT 平台则在异常重启后会自动读取并上报,如果是自行读取上报的话可通过 errDump.dump(buff,errDump.TYPE_SYS, ture) 来读取系统异常日志并根据自己需求自定义传输。

  1. errDump.TYPE_USR

用户自行写入调试日志是通过 errDump.record() 接口来保存的,如果设置了定时上报周期的话则会定期上报到服务器中,如果自行读取上报的话可以通过 errDump.dump(buff, errDump.TYPE_USR, true) 来读取用户写入的调试日志并根据自己需求自定义传输。

2.2 存储区域与空间管理

日志文件都是储存在文件系统中。

errDump.TYPE_SYS 和 errDump.TYPE_USR 的日志文件最大分别都是 4KB;日志达到 4KB 时,新写入内容覆盖旧数据。

2.3 日志上报与读取方式

  1. 自动上报

通过 errDump.config(enable, period, user_flag, custom_id, host, port)配置服务器地址和周期(默认 600 秒)。上报成功后,本地日志自动清空。

--每小时上报到一次errDump.config(true, 3600, nil, nil, "dev_msg1.openluat.com", 12425)
  1. 手动读取 使用 errDump.dump(zbuff, type, isDelete)读取日志,支持指定类型(如系统日志、用户日志)并选择是否删除。
  2. 自定义传输

禁用自动上报后,用户可通过 errDump.dump()获取日志内容,再通过 MQTT、TCP、UART 等方式发送出去。

2.4 日志清除机制

  1. 自动清除:

设置自动模式的话,上报到服务器成功后,本地日志自动删除。

  1. 手动清除:

设置手动读取模式,调用 errDump.dump(nil, type, true)指定日志类型并删除。

  1. 覆盖策略:

系统/用户日志达到 4KB 时,新写入内容覆盖旧数据。

三、准备硬件环境

1、Air8101 核心板一块

2、TYPE-C USB 数据线一根

3、USB 转串口数据线一根

4、Air8101 核心板和数据线的硬件接线方式为

  • Air8101 核心板通过 TYPE-C USB 口供电;(核心板背面的功耗测试开关拨到 OFF 一端)
  • 如果测试发现软件频繁重启,重启原因值为:poweron reason 0,可能是供电不足,此时再通过直流稳压电源对核心板的 vbat 管脚进行 4V 供电,或者 VIN 管脚进行 5V 供电;
  • TYPE-C USB 数据线直接插到核心板的 TYPE-C USB 座子,另外一端连接电脑 USB 口;
  • USB 转串口数据线,一般来说,白线连接核心板的 12/U1TX,绿线连接核心板的 11/U1RX,黑线连接核心板的 gnd,另外一端连接电脑 USB 口;

5、可选 AirPHY_1000 配件板一块,Air8101 核心板和 AirPHY_1000 配件板的硬件接线方式为:

Air8101核心板 AirPHY_1000配件板
59/3V3 3.3v
gnd gnd
5/D2 RX1
72/D1 RX0
71/D3 CRS
4/D0 MDIO
6/D4 TX0
74/PCK MDC
70/D5 TX1
7/D6 TXEN
不接 NC
69/D7 CLK

6、可选 AirETH_1000 配件板一块,Air8101 核心板和 AirETH_1000 配件板的硬件接线方式为:

Air8101核心板 AirETH_1000配件板
59/3V3 3.3v
gnd gnd
28/DCLK SCK
54/DISP CSS
55/HSYN SDO
57/DE SDI
14/GPIO8 INT

四、软件环境

在详细阐述本功能示例之前,我们需先精心筹备好以下软件环境。

1. Luatools 工具;点击查看 Air8101 的烧录教程可查看

2. 内核固件文件(底层 core 固件文件):https://docs.openluat.com/air8101/luatos/firmware/

3. LuatOS 需要的脚本和资源文件:https://gitee.com/openLuat/LuatOS/tree/master/module/Air8101/demo/errdump

4. lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;

5. 合宙 IOT 平台账号

五、API 接口说明

https://docs.openluat.com/osapi/core/errDump/

六、代码示例介绍

下面将演示使用 errdump 的几种场景,使用的时候根据自己需求在 main.lua 文件中选择要使用的功能,注意不能同时使用自动上报和手动读取功能。

(1)自动上报异常日志到合宙 IOT 平台

(2)自动上报异常日志到自建 UDP 服务器

(3)手动读取异常日志并通过 TCP 和串口传输

6.1 自动上报异常日志到合宙 IOT 平台

6.1.1 主要代码分析

-- 使用合宙iot平台时需要这个参数
PRODUCT_KEY = "123" -- 到 iot.openluat.com 创建项目,获取正确的项目id

local function test_user_log()
    -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
    while not socket.adapter(socket.dft()) do
        log.warn("auto_dump_air_srv_task_func", "wait IP_READY", socket.dft())
        -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
        -- 或者等待1秒超时退出阻塞等待状态;
        -- 注意:此处的1000毫秒超时不要修改的更长;
        -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
        -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
        -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
        sys.waitUntil("IP_READY", 1000)
    end
    -- 下面演示自动发送异常日志到合宙iot平台,如果是系统异常日志,则会在重启后自动上报,如果是用户写入调试日志,则周期性上报。
    errDump.config(true, 600)
    while true do
        sys.wait(15000)
        -- 上报用户调试日志
        errDump.record("测试一下用户的调试日志记录功能")
    end
end

--故意写错用来触发系统异常日志记录
local function test_error_log()
    sys.wait(60000)
    --故意写错代码死机
    lllllllllog.info("此处使用一个不存在的库文件,导致出现异常")
end

 -- 启动errdemp测试任务
sys.taskInit(test_user_log)
--启动错误函数任务
sys.taskInit(test_error_log)

6.1.2 云平台配置

使用合宙 iot 服务器的话,需要先登录合宙 IOT 平台,如下图所示,没有账号的,可以先注册一个 客户向合宙采购 4G 模块时,如果采购人员没有告知合宙这批模块放在 iot.openluat.com 上的哪个产品下,则合宙会以采购人的手机号为账号,默认密码 888888,创建一个“合宙标准模块”的项目,此次采购的所有模块都会放在这个项目下,如果你的账号下没有对应 imei,可以联系合宙销售帮忙添加模块进对应项目下(最好还是从哪里买的模块,就让他给你转移到你自己名下)

如果不在自己账号下,也可以通过烧录专属固件的方法,把模块归属到您指定的项目下,可以通过点击帮助中心,查看详细说明。

登录以后点击红框所示位置

然后依次点击如下图所示红框所示的地方,创建一个新项目

在所有项目的最后,找到自己刚刚新建的项目,并且点击红框内的"查看/点击复制"复制后面升级所需要的校验码,复制到自己剪切板中

打开设备 DEBUG 开关

对于淘宝购买的核心板或者测试模组,可以通过烧录合宙 IOT 平台生成的专属固件,来将设备归属带次项目名下,对于批量采购的模组,可以联系对接商务,帮助完成设备归属。

至此,合宙云平台上的预备动作就做完了

6.1.3 功能验证

6.1.3.1 Luatools 日志

6.1.3.2 云平台查看异常日志

6.2 自动上报异常日志到自建 UDP 服务器

6.2.1 主要代码分析

local function test_user_log()
    -- 如果当前时间点设置的默认网卡还没有连接成功,一直在这里循环等待
    while not socket.adapter(socket.dft()) do
        log.warn("auto_dump_udp_srv_task_func", "wait IP_READY", socket.dft())
        -- 在此处阻塞等待默认网卡连接成功的消息"IP_READY"
        -- 或者等待1秒超时退出阻塞等待状态;
        -- 注意:此处的1000毫秒超时不要修改的更长;
        -- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时,会隐式的修改默认使用的网卡
        -- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配
        -- 此处的1秒,能够保证,即使时序不匹配,也能1秒钟退出阻塞状态,再去判断socket.adapter(socket.dft())
        sys.waitUntil("IP_READY", 1000)
    end
    -- 下面演示自动发送异常日志到自建udp服务器,如果是系统异常日志,则会在重启后自动上报,如果是用户写入调试日志,则周期性上报。
    errDump.config(true,600,"123456","ABC","112.125.89.8",48095)
    while true do
        sys.wait(15000)
        -- 上报用户调试日志
        errDump.record("测试一下用户的调试日志记录功能")
    end
end

--故意写错用来触发系统异常日志记录
local function test_error_log()
    sys.wait(60000)
    --故意写错代码死机
    lllllllllog.info("此处使用一个不存在的库文件,导致出现异常")
end

 -- 启动errdemp测试任务
sys.taskInit(test_user_log)
--启动错误函数任务
sys.taskInit(test_error_log)

6.2.2 UDP 服务器建立

合宙测试服务器链接:https://netlab.luatos.com/

打开一个 UDP 服务器

记住 UDP 服务器的 ip 和端口,并在代码中修改

6.2.3 功能验证

6.2.3.1 Luatools 日志

6.2.3.2 UDP 服务器查看异常日志

注意:UDP 服务器需要回复"OK",不然模组会认为没有发送成功会重复发送。

6.3 手动读取异常日志并通过 TCP 和串口传输

6.3.1 主要代码分析

--加载uart模块
require "uart_app"
--加载tcp主应用模块
require "tcp_client_main"

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())) -- 打印出异常日志
        -- 将数据data通过"ERRDUMP_DATA_SEND_UART"消息publish给串口发送出去
        sys.publish("ERRDUMP_DATA_SEND_UART", err_buff:toStr(0, err_buff:used()))
        -- 将读取到的系统异常日志通过"SEND_DATA_REQ"消息publish给tcp发送出去
        sys.publish("SEND_DATA_REQ", err_buff:toStr(0, err_buff:used()))
    end
    --手动读取的话需要手动删除日志,否则下次读取会继续读取上次的日志
    --  errDump.dumpf返回值:true表示本次读取前并没有写入数据,false反之,在删除日志前,最好再读一下确保没有新的数据写入了
    new_flag = errDump.dump(err_buff, errDump.TYPE_SYS)
    if not new_flag then
        log.info("没有新数据了,删除系统错误日志")
        errDump.dump(nil, errDump.TYPE_SYS, true)
    end
    -- 开机读取完系统异常日志后循环读取用户调试日志
    while true do
        local new_flag = errDump.dump(err_buff, errDump.TYPE_USR)
        if new_flag then
            log.info("errBuff", err_buff:toStr(0, err_buff:used()))
            -- 将数据data通过"ERRDUMP_DATA_SEND_UART"消息publish给串口发送出去
            sys.publish("ERRDUMP_DATA_SEND_UART", err_buff:toStr(0, err_buff:used()))
            -- 将读取到的用户调试日志通过"SEND_DATA_REQ"消息publish给tcp发送出去
            sys.publish("SEND_DATA_REQ", err_buff:toStr(0, err_buff:used()))
        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
        sys.wait(15000)
        errDump.record("测试一下用户的调试日志记录功能") --写入用户的调试日志,注意最大只有4KB,超过部分新的覆盖旧的
    end
end

local function test_error_log() --故意写错用来触发系统异常日志记录
    sys.wait(60000)
    --故意写错代码死机
    lllllllllog.info("此处使用一个不存在的库文件,导致出现异常")
end

sys.taskInit(test_user_log)  -- 启动errdemp测试任务
sys.taskInit(test_error_log) --启动错误函数任务

tcp 和 uart 相关代码不做过多介绍,详细介绍可看对应教程。

6.3.2 TCP 服务器建立以及串口初始化

合宙测试服务器链接:https://netlab.luatos.com/

打开一个 TCP 服务器

记住 TCP 服务器的 ip 和端口,并在代码中修改

准备串口工具:LLCOM 是另外一种简单实用的串口通信工具,可以在计算机与设备之间建立串口通信连接,实现数据的发送与接收。

详情参考:LLCOM | 能跑 Lua 代码的串口调试工具!,详细使用说明可以直接参考下载网站

Air8101 核心板支持 3 路串口,分别为 UART0、UART1、UART2。在本文中,将会使用到 UART1 和 UART2。本次演示使用的是主串口 UART1。

6.3.3 功能验证

6.3.1 Luatools 日志

6.4.3 TCP 服务器查看日志以及串口查看日志

tcp 服务器日志:

串口日志:

七、总结

至此,本示例介绍了如何使用 errdump 的功能。