在《Vela rpmsg log 实现原理》中提到 vela 日志输出支持多通道日志输出,它们是在系统运行前期配置好的,所以无法将它们动态删除。但是可以控制使能、禁用某通道,达到相应通道输出、不输出日志的目的。接下来篇章将讲述"动态管理日志输出通道方法"和"动态管理日志输出通道原理"。
动态管理日志输出通道方法
-
列出当前已配置的所有输出通道及它们各自的状态
在 nuttx shell 中执行
setlogmask list命令,输出 "通道":"状态" 格式的信息。如下结果显示:"default 通道"(物理串口)已打开、"ramlog 通道" 已打开。
bash
ap> setlogmask list
Channels:
default: enable
ramlog: enable
- 禁用(启用)日志输出通道
bash
ap> setlogmask disable default
ap> setlogmask enable default
动态管理日志输出通道原理
从代码角度来看禁止某(些)通道输出日志的方式是在写日志时候跳过禁用通道,如下代码片段:
cpp
ssize_t syslog_write_foreach(FAR const char *buffer,
size_t buflen, bool force)
{
//...
for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++) {
FAR syslog_channel_t *channel = g_syslog_channel[i];
if (channel == NULL) break;
#ifdef CONFIG_SYSLOG_IOCTL
/// 根据"禁用"状态,忽略写相应通道
if (channel->sc_state & SYSLOG_CHANNEL_DISABLE)
continue;
#endif
/// ...
/// 调用通道的写函数
}
}
命令 setlogmask enable(disable) out_channel_name 的本质是:修改对应通道变量的 sc_state。为了实现此目的:
-
Vela 注册了一个虚拟设备,生成一个设备节点------"/dev/log";
-
setlogmask 命令会打开此设备并通过ioctl调用传递命令参数;
-
sys log 驱动的 syslog_chardev_ioctl 接收到命令参数后,进行名字匹配找到对应通道变量并更新sc_state。
cpp
int main(int argc, FAR char *argv[])
{
if (argc < 2)
{
show_usage(argv[0], EXIT_FAILURE);
}
#ifdef CONFIG_SYSLOG_IOCTL
if (strcmp(argv[1], "list") == 0)
{
print_channels();
return EXIT_SUCCESS;
}
else if (argc == 3)
{
if (strcmp(argv[1], "enable") == 0)
{
return disable_channel(argv[2], false);
}
else if (strcmp(argv[1], "disable") == 0)
{
return disable_channel(argv[2], true);
}
else
{
show_usage(argv[0], EXIT_FAILURE);
}
}
#endif
cpp
static int disable_channel(FAR const char *name, bool disable)
{
fd = open("/dev/log", O_WRONLY);
info.sc_disable = disable;
strlcpy(info.sc_name, name, sizeof(info.sc_name));
ret = ioctl(fd, SYSLOGIOC_SETFILTER, (unsigned long)&info);
close(fd);
return ret;
}
cpp
#ifdef CONFIG_SYSLOG_IOCTL
static int syslog_chardev_ioctl(FAR struct file *filep,
int cmd, unsigned long arg)
{
if (cmd == SYSLOGIOC_GETCHANNELS) {
// ...
} else if (cmd == SYSLOGIOC_SETFILTER) {
info = (FAR struct syslog_channel_info_s *)arg;
for (i = 0; i < CONFIG_SYSLOG_MAX_CHANNELS; i++)
{
if (strncmp(g_syslog_channel[i]->sc_name, info->sc_name,
sizeof(info->sc_name)) == 0)
{
channel = g_syslog_channel[i];
break;
}
}
// ...
// 修改日志输出状态
channel->sc_state = info->sc_disable ?
channel->sc_state | SYSLOG_CHANNEL_DISABLE :
channel->sc_state & ~SYSLOG_CHANNEL_DISABLE;
}
return OK;
}
#endif