Debug Configuration API

命名空间:mc::app 头文件:#include <mc/app/debug.h> 源文件:libraries/mcapp/src/micro_component/debug.cpp

目录


概述

mc/app/debug.h 中的七个函数均通过 MC_API 从 mcapp 共享库导出,包括本地持久化入口;外部消费者无需链接库内部对象。

mc::app::debug 模块提供 MicroComponent 日志配置的持久化功能,支持本地和远程两种持久化方式:

  • 本地持久化:maca 和 persistence 服务使用本地 SQLite 数据库
  • 远程持久化:其他服务通过 DBus 调用 persistence 服务

该模块在 MCDBUS_USE_OLD_SHM 模式下可用。

核心能力包括:

  • 服务识别: 自动判断服务应使用本地还是远程持久化
  • 应用名提取: 从完整服务名中提取应用名
  • 配置持久化: 将调试配置(日志级别、输出类型、有效时长)保存到数据库
  • 配置恢复: 从数据库加载调试配置,支持服务重启后恢复状态

主要特性

特性 说明
自动选择持久化方式 本地服务用 SQLite,其他服务用 DBus
本地持久化路径 根据服务类型选择:
- mini_system_app: /data/trust/persistence.local/{app_name}.db
- 其他: /data/opt/bmc/persistence.local/{app_name}.db
远程持久化表名 _t_mc_properties_{app_name}(通过 DBus)
服务识别 通过 is_local_persist_service() 判断服务类型
应用名提取 extract_app_name() 从服务名提取应用名
异常安全 所有数据库操作都有 try-catch 保护
线程安全 配合 micro_component_object 的互斥锁使用

API 参考

is_local_persist_service

判断服务是否使用本地持久化存储。

bool is_local_persist_service(mc::string_view service_name);

参数:

  • service_name: 服务名(如 bmc.kepler.maca)

返回值:

  • true: 使用本地 SQLite 存储(maca 或 persistence 服务)
  • false: 使用远程持久化存储

说明:

  • 该函数提取服务名的最后一部分,转为小写后与 maca 或 persistence 比较
  • 使用精确匹配,避免子串误判

extract_app_name

从服务名中提取应用名。

mc::string extract_app_name(mc::string_view service_name);

参数:

  • service_name: 服务名(如 bmc.kepler.maca)

返回值:

  • 应用名(如 maca)

save_debug_config

保存调试配置(自动选择持久化方式)。

void save_debug_config(mc::engine::service* svc,
                       mc::string_view level,
                       mc::string_view type,
                       uint8_t duration_hours);

参数:

  • svc: 服务对象(用于获取 DBus 连接和判断持久化方式)
  • level: 日志级别(all, trace, debug, info, notice, warn, error, fatal, off)
  • type: 日志输出类型(如 file, socket 等)
  • duration_hours: 剩余有效时长(半小时数),0 表示永久

持久化方式:

  • 本地持久化(maca/persistence):保存到本地 SQLite 数据库
  • 远程持久化(其他服务):通过 DBus 调用 persistence 服务的 Save 方法

远程持久化参数:

  • 表名:_t_mc_properties_{app_name}
  • 主键:Id=1(固定值)
  • persist_type:protect_power_off

load_debug_config

从数据库加载调试配置(自动选择持久化方式)。

bool load_debug_config(mc::engine::service* svc,
                       mc::string& level,
                       mc::string& type,
                       uint8_t& duration_hours);

参数:

  • svc: 服务对象
  • level: [out] 日志级别
  • type: [out] 日志输出类型
  • duration_hours: [out] 剩余有效时长(半小时数)

返回值:

  • true: 加载成功
  • false: 加载失败(数据库文件不存在、表不存在、无记录等)

持久化方式:

  • 本地持久化:从本地 SQLite 数据库加载
  • 远程持久化:通过 DBus 调用 persistence 服务的 BatchRead 方法

数据库路径

本地持久化

maca 和 persistence 服务使用本地 SQLite 数据库:

// 根据 is_mini_system_app 判断路径
if (is_mini_system_app(app_name)) {
    // mini_system_app: /data/trust/persistence.local/{app_name}.db
} else {
    // 其他服务: /data/opt/bmc/persistence.local/{app_name}.db
}

表名:_t_mc_properties

表结构:

CREATE TABLE _t_mc_properties (
    DlogLevel INTEGER,      -- 日志级别(数值)
    DlogType TEXT,          -- 日志输出类型
    DlogDuration INTEGER    -- 剩余有效时长(半小时数)
)

远程持久化

其他服务通过 DBus 与 persistence 服务通信:

DBus 接口:

  • 服务名:bmc.kepler.persistence
  • 对象路径:/bmc/kepler/persistence
  • 接口:bmc.kepler.persistence

表名:_t_mc_properties_{app_name}(动态生成)

表结构:

CREATE TABLE _t_mc_properties_{app_name} (
    Id INTEGER PRIMARY KEY,         -- 主键(固定值 1)
    DlogLevel INTEGER,              -- 日志级别(数值)
    DlogDuration INTEGER            -- 剩余有效时长(半小时数)
)

示例数据:

Id=1, DlogLevel=5, DlogDuration=48  -- 24 小时 = 48 个半小时

使用示例

示例 1:服务启动时恢复配置

void micro_component_object::init(mc::string_view service_name)
{
    mc::string app_name = mc::app::extract_app_name(service_name);

    // 恢复持久化配置(自动判断本地或远程)
    auto* svc = get_service();
    if (svc) {
        mc::string saved_level, saved_type;
        uint8_t saved_duration = 0;

        if (mc::app::load_debug_config(svc, saved_level, saved_type, saved_duration)) {
            m_mc_debug_iface.m_dlog_level = saved_level;
            m_mc_debug_iface.m_dlog_type = saved_type;
            m_mc_debug_iface.m_dlog_remaining_half_hours = saved_duration;

            // 应用日志级别
            auto lvl_opt = mc::log::to_level(saved_level.view());
            if (lvl_opt) {
                mc::log::log_manager::instance().set_dlog_level(*lvl_opt);
                ilog("Restored debug log level: ${level}, duration=${duration}h",
                     ("level", saved_level)("duration", static_cast<int>(saved_duration)));
            }
        }
    }
}

示例 2:动态修改并持久化

void set_dlog_level(mc::string level, uint8_t effective_hours)
{
    auto lvl_opt = mc::log::to_level(level.view());
    if (!lvl_opt) {
        elog("Invalid log level: ${level}", ("level", level));
        return;
    }

    // 应用日志级别
    mc::log::log_manager::instance().set_dlog_level(*lvl_opt);

    // 持久化(自动判断本地或远程)
    auto* service = get_service();
    if (service) {
        mc::app::save_debug_config(service, level,
                                   m_mc_debug_iface.m_dlog_type.value(),
                                   static_cast<uint8_t>(effective_hours * 2));
    }
}

编译条件

该模块仅在 MCDBUS_USE_OLD_SHM=1 时可用:

#if defined(MCDBUS_USE_OLD_SHM) && MCDBUS_USE_OLD_SHM
    // 完整实现
#else
    // 空实现,所有函数返回 false 或空操作
#endif

安全特性

1. SQL 注入防护

所有数据库操作使用参数化查询:

auto stmt = db->prepare("INSERT INTO table VALUES (?, ?, ?)");
stmt->bind_values(mc::variant(level_value), mc::variant(type), mc::variant(duration));

2. 异常处理

所有数据库操作都有 try-catch 保护:

try {
    db->exec(create_sql);
    db->flush();
} catch (const std::exception& e) {
    elog("Failed to save debug config: ${error}", ("error", e.what()));
    return;
}

3. 线程安全

配合 micro_component_object 的互斥锁使用:

std::lock_guard<std::mutex> lock(m_dlog_level_mutex);
// 访问 m_dlog_remaining_half_hours