跳到主要内容

7.2.8 Log 使用指南

Log 系统分区规划

Log 分区

分类log 类型存储位置单个 log 最大大小log 文件数量是否压缩内容
基础系统 logkernel/var/log/NA4内核、驱动、syslog 的 log 信息
基础系统 logpstore/log/pstore4M100内核 crash 的 log 信息
基础系统 logcoredump/log/coredumpNANA应用 crash 的 coredump 文件,目录大小限制2G
基础系统 logcoredump/log/stackdumpNA20应用 crash 的 log 信息
基础系统 logremoteproc/log/dsp01M200DSP0固件输出的 log 信息
基础系统 logremoteproc/log/bl311M200BL31固件输出的 log 信息
基础系统 logremoteproc/log/optee1M200optee 固件输出的 log 信息
基础系统 logremoteproc/log/mcu*2M200mcu 固件输出的 log 信息
基础系统 logremoteproc/log/bpu01M200bpu0固件输出的 log 信息
基础系统 logremoteproc/log/hsm1M200hsm 固件输出的 log 信息
基础系统 logremoteproc/log/uboot8KB100uboot 输出的 log 信息
基础系统 logreset/log/reset_reason.txt1M1记录每次系统启动原因
基础系统 logreset/log/reset_count.txt4KB1记录当前系统重启次数
ALOG 系统ALOG/log/usr2M200ALOG 接口的 log 信息
systemdjournal/log/journalNANAsystemd journal,总大小约100MB

Log 内容

  1. Kernel Log

    • 内核 log:通过 rsyslog 转存到/var/log/目录下
    • pstore log:当内核 crash 重启时,移动/sys/fs/pstore目录日志到/log/pstore目录下,记录系统 panic 前后的内核日志
  2. 启动原因 log

    • reset_reason.txt 信息介绍:
      • poweroff:断电后等待30s 后正常上电(零下10度以下需要断电时间更长)
      • hwreset:拉 reset pin 重启
      • ddrtrainfail:ddr training 失败重启
      • pmicwdt:pmic watchdog 重启
      • mreboot:mcu 正常重启
      • mpanic:mcu panic 重启
      • mwdt:系统各种原因导致的 hang 住引起的 watchdog 复位
      • mhlost:Acore 丢心跳重启
      • deepsleep:深睡眠重启
      • lightsleep:浅睡眠唤醒
      • scpreboot:scp 正常重启
      • splreboot:spl 正常重启
      • splpanic:spl panic 重启
      • freboot:bl31正常重启
      • fpanic:bl31 panic 重启
      • oreboot:optee 正常重启
      • opanic:optee panic 重启
      • ureboot:uboot 正常重启
      • upanic:uboot panic 重启
      • kreboot:kernel 正常重启
      • kpanic:kernel panic 重启
      • lmbistfail:硬件 bist 失败重启
      • sblpanic:sbl panic 重启
      • mbdiso:bdiso 错误重启
      • offsleep:main off + mcu sleep 重启
      • mainreboot:main reboot 重启
      • invalidtemp:异常温度重启
    • reset_count.txt:当前系统重启次数,0到9999循环计数
  3. remoteproc log

    • dsp*:dsp*固件输出的 log 信息
    • bl31:bl31固件输出的 log 信息
    • optee:optee 固件输出的 log 信息
    • mcu:mcu 固件输出的 log 信息
    • bpu*:bpu*固件输出的 log 信息
    • hsm:hsm 固件输出的 log 信息,加密保存
    • uboot:uboot 输出的 log 信息
  4. ALOG 系统

    • 使用 libalog 库的 pr_*接口打印的 log 信息
    • 应用软件推荐使用 libalog 库的 pr_*接口
  5. systemd journal log

    • systemd 运行过程中的日志,目前配置大小100MB,实际占用会更大,大约达到102MB
    • systemd journal 在应对异常掉电、系统时间异常等情况时,可能会出现丢失本次启动日志的情况
  6. 应用 crash log

    • coredump:储存进程在突然崩溃那一刻的内存快照,会把进程此刻内存、寄存器状态、运行堆栈等信息转储保存在该目录文件中,量产建议关闭
    • stackdump:debug 版本开启,储存 systemd 服务进程在突然崩溃那一刻的状态信息,占用空间小

Log 管理

Log 进程

  1. 进程信息

    • 板端 log 进程运行信息如下,不同设备的 log 进程有所区别,以实际命令结果为准:
    root@ubuntu:/userdata# ps -ef | grep log | grep -v -e grep -e login -e dbus-daemon
    root 1083 1 0 11:16 ? 00:00:00 /bin/bash /usr/bin/hobot-log
    root 1514 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start bl31
    root 1518 1514 0 11:16 ? 00:00:00 hrut_remoteproc_log -b /dev/bl31_log_dev -f /log/bl31/message -r 1024 -n 200
    root 1520 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start bpu0
    root 1521 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start dsp0
    root 1523 1520 0 11:16 ? 00:00:00 hrut_remoteproc_log -b /proc/bpu0_msg -f /log/bpu0/message -r 1024 -n 200
    root 1525 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-init-hb_hsm_log_server.sh
    root 1526 1521 0 11:16 ? 00:00:00 hrut_remoteproc_log -b /sys/class/remoteproc/remoteproc_vdsp0/log -f /log/dsp0/message -r 1024 -n 200
    root 1527 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start logcat
    root 1529 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start mcu
    root 1530 1527 0 11:16 ? 00:00:00 logcat -v time -f /log/usr/message -r2048 -n 200
    root 1531 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start optee
    root 1536 1529 0 11:16 ? 00:00:00 hrut_remoteproc_log -b /proc/remoteproc_mcu0 -f /log/mcu0/message -r 2048 -n 200
    root 1538 1525 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start hsm
    root 1539 1 0 11:16 ? 00:00:00 python3 /usr/bin/hobot-log-rename.py /log -m auto
    root 1541 1529 0 11:16 ? 00:00:00 hrut_remoteproc_log -b /proc/remoteproc_mcu1 -f /log/mcu1/message -r 2048 -n 200
    root 1542 1 0 11:16 ? 00:00:00 /usr/hobot/bin/syslogd -n -O /log/kernel/message -s 2048 -b 200
    root 1545 1 0 11:16 ? 00:00:00 /bin/sh /usr/bin/hobot-log-start klogd
    root 1546 1538 0 11:16 ? 00:00:00 hsm_log -f /log/hsm/message -r 1024 -n 200
    root 1547 1531 0 11:16 ? 00:00:00 optee_log -f /log/optee/message -r 1024 -n 200
    • kernel: rsyslog

      • 获取内核记录的消息,将消息数据转存到文件中
    • usr: ALOG(libalog.so)和 logcat

      • 通过 ALOG 接口 pr_*向 log buffer 写入 log 信息,logcat 从 log buffer 中获取 log 信息,将其写入文件中
    • remoteproc_log:hrut_remoteproc_log、hsm_log、optee_log 进程

      • 通过 remoteproc 节点获取 MCU,DSP,BL31,BPU,HSM,OPTEE 的 log 信息,将其写入文件中
    • 日志管理:hobot-log 和 hobot-log-rename.py

      • log 记录:记录 reset,pstore,uboot 的 log 信息

      • log 管理:定期每10分钟将原始 log 文件转存成固定格式文件,管控各个分区目录的存储空间, 超过固定容量会进行删除,删除时间比较早产生的文件

  2. 启动顺序

    • hobot-log-daemon.service 服务开机自启,启动 hobot-log 守护进程,去启动相关 log 服务,并管理日志,启动顺序如下:

      |- /usr/bin/hobot-log
      |- record_reset_count(shell function)
      |- record_reset_reason(shell function)
      |- message_rotate_and_add_resetcount(shell function)
      |- wait_for_timesync(shell function)
      |- set_pstore(shell function)
      |- set_uboot(shell function)
      |- systemd_journal_config(shell function)
      |- check_first_log(shell function)
      |- 启动相关log服务,启动各个模块日志记录进程
      |- hobot-log-rename.py脚本进行日志重命名归档、空间管理

Log 管理方式

log 的文件生成和目录空间管控主要是由 hobot-log 和 hobot-log-rename.py 去管理的。

  1. log 管理

    • 容量管控:

      • 在 hobot-log 脚本中配置了各个模块的日志文件大小和数量限制,这些限制会通过入参传递给各个模块日志进程。每个模块日志文件限制说明见:log分区
      • 各个模块的进程管理各自的日志文件大小和数量限制,超过限制后会删除产生时间比较早的文件
    • log 文件重命名归档:

      • 启动时,转存 uboot 和 pstore log,命名格式如下:
        • SuperSoC_Uboot-count-time.Log:当系统启动时,将 uboot log 转存到 uboot 的 archive 目录下
        • SuperSoC_Pstore-count-time(文件夹):当系统启动时,如果检测到上次系统是异常重启,则创建该格式文件夹,并将对应的异常 log 信息记录到该文件夹下
      • 运行时,log 文件通过 hobot-log-rename.py 进程重命名归档,每10分钟各模块目录下的 message.*文件重命名归档到模块的 archive 目录下,并根据容量管控删除 archive 目录下旧文件
        • 该进程由 hobot-log-rename.service 服务启动,根据 hobot-log 生成的配置文件/log/hb_log_rename.conf管理各模块
        • 如果不希望运行过程中重命名日志文件,通过修改hbre/boot-utils/hb-init-scripts/DEBIAN/postinst文件,关闭该服务自启
        • 关闭后如果还希望对当前的 log 文件重命名归档,可以手动执行如下命令:python3 /usr/bin/hobot-log-rename.py /log -m manual
        • log 文件重命名格式如下:
          • 示例:SuperSoC_Usr-0003~2025_05_06_08_01_00_131599.Log
          • 命名说明:[board]_[module]-[count]-[time]_<inode>.Log
            • board:SuperSoC
            • module:Usr,Uboot,Pstore 等首字母大写
            • count:4位数字,0000到9999,示例中代表第3次重启
            • time:如2025_05_06_08_01_00
            • inode:如131599,但正常情况下没有,只有当出现同一秒转存多个文件命名存在重合时,加入 inode 号来做区分
    • 内核日志使用 ubuntu 系统自带的 rsyslog 服务管理,因此这里对内核 log 管理方式做单独介绍。

      • 容量管控:
        • 不会限制单个 kern.log 的大小
        • 日志每周进行一次轮转
        • 系统最多保留4个历史日志文件
      • log 归档:
        • 当日志轮转发生时,当前日志文件会按照编号进行重命名归档。归档原则:kern.log 达到轮转周期,logrotate 将 kern.log 重命名为 kern.log.1,创建新的 kern.log,rsyslog 继续写入日志。当超过最大数量限制后,最开始产生的日志文件会被删除
        • 为减少磁盘占用,系统会对历史日志进行压缩。压缩策略:最近一次轮转日志延迟一轮再解压缩
      • 参数配置:
        • 如果用不想使用 ubuntu 默认配置参数来配置日志管理策略,可以通过修改/etc/logrotate.d/rsyslog文件中的配置实现。
        {
        rotate 4 //最大保留历史日志文件个数
        weekly //轮转周期
        missingok //如果日志丢失,不报错继续滚动下一个日志
        notifempty //当前日志为空时,不进行轮转
        compress //通过gzip压缩
        delaycompress //和compress一起使用时,转储的日志文件到下一次转储时才压缩
        sharedscripts
        postrotate
        /usr/lib/rsyslog/rsyslog-rotate
        endscript
        }
  2. 定制 log 系统

    • log 大小和数量修改
      • 日志大小在 hobot-log 中修改,修改ROTATESIZEROTATESIZE_REMOTE变量的定义,单位是 KB
      • 日志数量在 hobot-log 中修改,修改ROTATEGENS_USR、ROTATEGENS_REMOTE、UBOOT_LOGMAX、PSTORE_LOGMAX变量的定义,对应的分别是 usr、remoteproc_log、uboot、pstore 的日志数量限制,当前值分别是200、200、100、100
      • systemd journal log 大小配置在源码debian/source/scripts/general.sh脚本中修改 SystemMaxUse 值,同时需要注意文件大小 SystemMaxFileSize 和文件数量 SystemMaxFiles 限制相乘要大于 SystemMaxUse
    • log 命名修改
      • 当前命名规范是[board]_[module]-[count]-[time]_<inode>.Log,在 hobot-log 脚本中修改前缀和尾缀,即[board]_[module]和.Log。在 hobot-log-rename.py 脚本中修改[count]和[time],涉及get_reset_countget_file_time两个函数
    • log 进程的裁剪
      • 可以通过增减 systemd 的 log service,来增减 log 进程,通过修改hbre/boot-utils/hb-init-scripts/DEBIAN/postinst文件实现。部分 log 相关服务如下:

        /etc/systemd/system/basic.target.wants/hobot-log-bl31.service
        /etc/systemd/system/basic.target.wants/hobot-log-bl31-timesync.service
        /etc/systemd/system/basic.target.wants/hobot-log-bpu0.service
        /etc/systemd/system/basic.target.wants/hobot-log-daemon.service
        /etc/systemd/system/basic.target.wants/hobot-log-dsp0.service
        /etc/systemd/system/basic.target.wants/hobot-log-hsm.service
        /etc/systemd/system/basic.target.wants/hobot-log-logcat.service
        /etc/systemd/system/basic.target.wants/hobot-log-mcu.service
        /etc/systemd/system/basic.target.wants/hobot-log-optee.service
      • 以 hobot-log-logcat.service 为例,介绍设备端如何控制 log 服务启停:

        # 开启服务开机自启
        systemctl enable hobot-log-logcat.service
        # 关闭服务开机自启
        systemctl disable hobot-log-logcat.service
        # 查看服务状态
        systemctl status hobot-log-logcat.service
        # 启动服务
        systemctl start hobot-log-logcat.service
        # 停止服务
        systemctl stop hobot-log-logcat.service
  3. log 时间

    • hobot-log 提供了等待时间同步完成的功能,以确保日志中的时间戳准确。该功能可通过YEAR_LIMIT 和 WAIT_FOR_TIMESYNC_TIMEOUT 两个变量进行配置,分别用于设定时间同步成功的阈值以及超时时间。需要注意的是,Debian 系统的默认时间为其发行版本的发布时间。因此,在每次更新 Debian 版本时,应相应修改YEAR_LIMIT的值,使其大于该版本的发布时间。通常情况下,将其配置为最新日期即可。

Log 接口使用推荐

Kernel

  1. 在驱动中推荐使用如下接口 dev_err, dev_warn, dev_info, dev_dbg。
  2. 没有设备结构的场合使用如下接口 pr_error, pr_warn, pr_info, pr_debug。
  3. pr_debug,dev_dbg 可通过如下方法动态开启。
    • echo "file drivers/mmc/host/* +p" > /sys/kernel/debug/dynamic_debug/control
    • echo "module mmc_core +p" > /sys/kernel/debug/dynamic_debug/control
    • echo "func mmc_detect_change +p" > /sys/kernel/debug/dynamic_debug/control
  4. 对于出错后可能重复非常多次的打印,用如下接口。
    • printk_once: 只打印一次
    • printk_ratelimited: 限制每秒打印次数,默认每5秒最多打印10次
  5. 内核敏感地址打印方法。
    • 内核敏感地址使用%pK 替代%p, 配置/proc/sys/kernel/kptr_restrict为2后,打印地址为全0

应用程序

  1. 推荐使用 pr 的接口,对应的打印级别有pr_verbose、pr_debug、pr_info、pr_warn、pr_err、pr_fatal、pr_verbose_with_tag、pr_debug_with_tag、pr_info_with_tag、pr_warn_with_tag、pr_err_with_tag、pr_fatal_with_tag

  2. 使用 pr* 接口时,各个模块在输出 Log 时,可以通过定义 LOG_TAG 宏来打印自身模块名,logcat 支持使用 tag 筛选日志。其可通过 Makefile 传入,如:DLOG_TAG=camera;或者在代码开头声明。

  3. 使用 pr* _tag 接口时,各个模块在输出 Log 时,可以通过第一个参数来打印自身模块名,logcat 支持使用 tag 筛选日志。

  4. log 系统支持1个2MB 的 log_main 缓冲区,1个256KB 的 log_radio 缓冲区,建议使用 log_main 缓冲区。

    • 当 LOG_TAG 是"HTC_RIL"、"RIL"、"IMS"、"AT"、"GSM"、"STK"、"CDMA"、"PHONE"、"SMS"时,日志保存到 log_radio 缓冲区,其他的都保存到 log_main 缓冲区。
  5. 代码示例和测试结果如下:

    //gcc logtest.c -o logtest -L . -lalog -I /usr/hobot/include/
    #define LOG_TAG "alog_test"
    #include <stdio.h>
    #include <logging.h>

    int main(int argc, char **argv)
    {
    pr_verbose("*ALOG test start*n");
    pr_debug("********1********n");
    pr_info("********2********n");
    pr_warn("********3********n");
    pr_err("********4********n");
    pr_verbose("*ALOG test end***n");
    return 0;
    }
    # 测试结果:
    root@ubuntu:/# ./logtest

    # 不设置过滤:
    root@ubuntu:/# logcat
    logcat test start !!!
    --------- beginning of /dev/log_main
    V/alog_test(21590): *ALOG test start*
    D/alog_test(21590): ********1********
    I/alog_test(21590): ********2********
    W/alog_test(21590): ********3********
    E/alog_test(21590): ********4********
    V/tag (21590): ********1********
    D/tag (21590): ********1********
    I/tag (21590): ********2********
    W/tag (21590): ********3********
    E/tag (21590): ********4********
    F/tag (21590): ********1********
    V/alog_test(21590): *ALOG test end***

    设置过滤-s *:F
    root@ubuntu:/# logcat -s *:F
    logcat test start !!!
    --------- beginning of /dev/log_main
    F/tag (21590): ********1********

    设置过滤-s *:E
    root@ubuntu:/# logcat -s *:E
    logcat test start !!!
    --------- beginning of /dev/log_main
    E/alog_test(21590): ********4********
    E/tag (21590): ********4********
    F/tag (21590): ********1********

    设置过滤-s tag:E
    root@ubuntu:/# logcat -s tag:E
    logcat test start !!!
    --------- beginning of /dev/log_main
    E/tag (21590): ********4********
    F/tag (21590): ********1********

MCU

LogSync/LogNotice/LogAsync接口支持将 log 输出到串口以及转存到 Acore。

其中,转存到 Acore 的临时文件节点在:/proc/remoteproc_mcu0/proc/remoteproc_mcu1,Acore 会启动 hrut_remoteproc_log 进程周期性的获取 proc 节点中的日志写入/log/mcu*的 messag 文件实现转存。

由于单个文件可以存储的日志大小有限,加上重启后上一次存储的 message 日志会被启动的 log 进程重写覆盖。所以实现了 log 管理机制支持对 log 文件重命名归档,具体描述见:log管理

  1. LogSync 用于同步打印优先级较低的日志。

在 debug 镜像中使用 LogSync 接口,日志会正常输出到串口和转存到 Acore。在 release 镜像中不会向串口输出,只保留转存到 Acore 的功能。

  1. LogNotice 用于同步打印优先级较高的日志。

LogNotice 无论是在 debug 还是 release 镜像,日志都会正常输出到串口和转存到 Acore。

  1. LogAsync 用于异步打印。

LogAsync 输出原则同 LogSync。

接口使用说明

编译路径添加Service/Log,代码引用Service/Log/Common/inc/下的头文件Log.h,即可调用 LogSync、LogNotice 以及 LogAsync 接口。

串口打印和转存 Acore 的功能由Service/Log/Config/inc/Log_Cfg.h中的两个宏LOG_SEND_TO_UARTLOG_SEND_TO_ACORE控制:

#define LOG_SEND_TO_ACORE  (STD_ON)
#ifdef MCU_RELEASE
#define LOG_SEND_TO_UART (STD_OFF) // LogSync 和 LogAsync 打印到串口通路关闭,必要信息将通过 LogNotice 临时开启串口通路来打印。
#else
#define LOG_SEND_TO_UART (STD_ON) // LogSync、LogNotice以及LogAsync 打印到串口通路始终开启。
#endif

MCU Log 使用注意事项,请参考:MCU Log简介

DSP

  1. 推荐使用DSP_ERR、DSP_WARN、DSP_INFO、DSP_DBG接口。

Log 使用注意

Log 调试注意点

  1. 调试时大量日志可以单独保存,防止丢失,方便查看
    • 内核日志:dmesg -w > /userdata/dmesg.log &
    • ALOG 日志:logcat -v time -f /userdata/logcat.log &
  2. 每个转存周期(10min)内产生超过 rotate 数量的日志会造成日志丢失
    • 首先应只输出必要的日志
    • 如果输出较多 log,在设置 rotate 的数量时候,要考虑好所需大小
  3. 不要在串口、ssh 窗口实时查看日志。可能会发现丢日志,原因是输出慢,覆盖导致。如果必须,建议 ssh 窗口实时查看日志。
    • 比如使用 logcat 在串口实时查看输出,内核若输出"logcat lost message",则说明有日志丢失。
  1. S100日志写入存储设备保存。考虑到存储设备的寿命有限和大量存储日志对 IO/CPU 性能的影响,应只输出必要的日志,正式版本不应输出大量调试日志。
    • 比如当 S100 存储设备是 eMMC(64GB、MLC、3000次擦写)时,若每分钟写入10MB 日志,则连续工作十年消耗27%寿命,考虑写入放大,消耗更多。
  1. S600日志写入存储设备保存。考虑到存储设备的寿命有限和大量存储日志对 IO/CPU 性能的影响,应只输出必要的日志,正式版本不应输出大量调试日志。
    • 比如当 S600 存储设备是 eMMC(64GB、MLC、3000次擦写)时,若每分钟写入10MB 日志,则连续工作十年消耗27%寿命,考虑写入放大,消耗更多。

logcat 使用

  1. logcat 命令格式
#参数描述
1-b <buffer>加载一个可使用的日志缓冲区供查看,比如 event 和 radio,默认值是 main
2-c清除缓冲区中的全部日志并退出(清除完后可以使用 -g 查看缓冲区)
3-d将缓冲区的 log 转存到屏幕中然后退出
4-f <filename>将 log 输出到指定的文件 <filename>,默认为标准输出(stdout)
5-g打印日志缓冲区的大小并退出
6-n <count>设置日志的最大数目 <count>,默认值是 4,需要和 -r 选项一起使用
7-r <kbytes>每输出 <kbytes> 时轮替日志文件,默认值是 16,需要和 -f 选项一起使用
8-s设置过滤器
9-v <format>设置日志消息的输出格式,默认是短格式

Log debug

死机情况如何保存有效日志记录

  1. 在出现系统 panic 死机的时候,pstore 的机制是可以将发生 panic 的内核 log 信息存储到 pstore 的目录中的,但 BL31和 mcu 的 panic 信息没法保存,需要注意。

有效获取问题时刻日志

  1. 在 log 分区中的文件的命名字段中包含对应 log 文件的最后修改时间的信息,可以去文件中查找问题时刻的 log。