01=上期内容回顾
本期我们将继续深入浅出思科vpp24.02系列专题,介绍VPP的日志log功能初始化的函数的业务逻辑介绍。
02=vlib_log_init函数介绍
在往期的内容中,我们介绍了思科VPP软件对日志功能的初始化的函数vlib_log_init()的业务逻辑介绍,其在vlib_main()中备调用的。
log模块初始化逻辑如下所示
clib_error_t *vlib_log_init (vlib_main_t *vm)
{
vlib_log_main_t *lm = &log_main;
vlib_log_class_registration_t *r = lm->registrations;
gettimeofday (&lm->time_zero_timeval, 0);
lm->time_zero = vlib_time_now (vm);
vec_validate (lm->entries, lm->size);
while (r)
{
r->class = vlib_log_register_class (r->class_name, r->subclass_name);
if (r->default_level)
vlib_log_get_subclass_data (r->class)->level = r->default_level;
if (r->default_syslog_level)
vlib_log_get_subclass_data (r->class)->syslog_level =
r->default_syslog_level;
r = r->next;
}
r = lm->registrations;
while (r)
{
vlib_log_debug (r->class, "initialized");
r = r->next;
}
return 0;
}
函数声明:clib_error_t *vlib_log_init (vlib_main_t *vm);
返回值:此处应该返回clib_error_t 类型的更佳。
03=函数工程意义分析
1、日志系统的主要结构体:这里lm是指向日志系统主要结构的指针,它引用了全局变量log_main。这个结构包含了日志系统的各种状态和配置。。
vlib_log_main_t *lm = &log_main;
vlib_log_class_registration_t *r = lm->registrations;
结构体介绍:vlib_log_main_t用于管理和配置日志记录的行为:
typedef struct
{
vlib_log_entry_t *entries;
vlib_log_class_data_t *classes;
int size, next, count;
int default_rate_limit;
int default_log_level;
int default_syslog_log_level;
int unthrottle_time;
u32 max_class_name_length;
/* time zero */
struct timeval time_zero_timeval;
f64 time_zero;
/* config */
vlib_log_class_config_t *configs;
uword *config_index_by_name;
int add_to_elog;
/* registrations */
vlib_log_class_registration_t *registrations;
} vlib_log_main_t
结构体参数解释:
next
指向下一个将要写入的日志条目的索引。count
表示当前已记录的日志条目数量。u32 max_class_name_length;
日志类别名称的最大长度。vlib_log_class_registration_t *registrations;
指向日志类别注册信息的指针,用于跟踪哪些日志类别已经被注册。2、时间戳操作
gettimeofday (&lm->time_zero_timeval, 0);
lm->time_zero = vlib_time_now (vm);
gettimeofday 是linux系统函数,它的目的是获取当前时间戳,并将其存储在lm->time_zero_timeval中。
lm->time_zero = vlib_time_now(vm);使用VPP时间函数获取时间戳,将其存放在lm->time_zero 之中。
3、验证日志条目数量的大小,确保其大小够用,该部分会采用vpp的vec机制,如果空间大小不够,会自动拓展来确保空间足够。
vec_validate (lm->entries, lm->size);
4、注册日志类别和日志的level等级
while (r)
{
r->class = vlib_log_register_class (r->class_name, r->subclass_name);
if (r->default_level)
vlib_log_get_subclass_data (r->class)->level = r->default_level;
if (r->default_syslog_level)
vlib_log_get_subclass_data (r->class)->syslog_level = r->default_syslog_level;
r = r->next;
}
技术点补充:syslog的日志等级介绍,其level分为如下所示的等级,一般默认使用log_info等级。
LOG_EMERG system is unusable
LOG_ALERT action must be taken immediately
LOG_CRIT critical conditions
LOG_ERR error conditions
LOG_WARNING warning conditions
LOG_NOTICE normal, but significant, condition
LOG_INFO informational message
LOG_DEBUG debug-level message
5、输出初始化标志
r = lm->registrations;
while (r)
{
vlib_log_debug (r->class, "initialized");
r = r->next;
}
6、返回值:源代码中为return 0 建议修改为返回clib_error_t 里面的参数
04=log模块的使用方法介绍
1、首先在vpp启动配置文件中配置文件生成的路径,配置文件的详细参数可以参考如下文所述。
Ubuntu系统运行VPP24.02系列:startup.conf配置文件解读
unix {
nodaemon
log /var/log/vpp/vpp.log
full-coredump
cli-listen /run/vpp/cli.sock
gid vpp
startup-config /etc/vpp/start.txt
}
在unix的配置参数下,配置的是log文件生成的路径,如果不存在OS下创建该路径即可,也可以按照需求设置指定的日志路径下。
2、配置log模块的默认level参数,也是在startup.conf文件中配置,这里的level 等级可以按照需求自行配置syslog的告警等级。
logging {
default-log-level info
default-syslog-log-level info
}
3、查询配置信息,将lm里面存储的log 配置信息输出,该输出工作在管理线程main线程上。
static clib_error_t *show_log_config (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
clib_error_t *error = 0;
vlib_log_main_t *lm = &log_main;
vlib_log_class_data_t *c;
vlib_log_subclass_data_t *sc;
vlib_cli_output (vm, "%-20s %u entries", "Buffer Size:", lm->size);
vlib_cli_output (vm, "Defaults:\n");
vlib_cli_output (vm, "%-20s %U", " Log Level:",
format_vlib_log_level, lm->default_log_level);
vlib_cli_output (vm, "%-20s %U", " Syslog Log Level:",
format_vlib_log_level, lm->default_syslog_log_level);
vlib_cli_output (vm, "%-20s %u msgs/sec", " Rate Limit:",
lm->default_rate_limit);
vlib_cli_output (vm, "\n");
vlib_cli_output (vm, "%-22s %-14s %-14s %s",
"Class/Subclass", "Level", "Syslog Level", "Rate Limit");
u8 *defstr = format (0, "default");
vec_foreach (c, lm->classes)
{
vlib_cli_output (vm, "%v", c->name);
vec_foreach (sc, c->subclasses)
{
vlib_cli_output (vm, " %-20v %-14U %-14U %d",
sc->name ? sc->name : defstr,
format_vlib_log_level, sc->level,
format_vlib_log_level, sc->syslog_level,
sc->rate_limit);
}
}
vec_free (defstr);
return error;
}
VLIB_CLI_COMMAND (cli_show_log_config, static) = {
.path = "show logging configuration",
.short_help = "show logging configuration",
.function = show_log_config,
};
4、查询生成的log日志方法,通过show logging命令输出
static clib_error_t *show_log (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
clib_error_t *error = 0;
vlib_log_main_t *lm = &log_main;
vlib_log_entry_t *e;
int i = last_log_entry ();
int count = lm->count;
f64 time_offset;
time_offset = (f64) lm->time_zero_timeval.tv_sec
+ (((f64) lm->time_zero_timeval.tv_usec) * 1e-6) - lm->time_zero;
while (count--)
{
e = vec_elt_at_index (lm->entries, i);
vlib_cli_output (vm, "%U %-10U %-14U %v", format_time_float, NULL,
e->timestamp + time_offset, format_vlib_log_level,
e->level, format_vlib_log_class, e->class, e->string);
i = (i + 1) % lm->size;
}
return error;
}
VLIB_CLI_COMMAND (cli_show_log, static) = {
.path = "show logging",
.short_help = "show logging",
.function = show_log,
};
5、清除操作,通过clear logging命令进行清理
static clib_error_t *clear_log (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
clib_error_t *error = 0;
vlib_log_main_t *lm = &log_main;
vlib_log_entry_t *e;
int i = last_log_entry ();
int count = lm->count;
while (count--)
{
e = vec_elt_at_index (lm->entries, i);
vec_free (e->string);
i = (i + 1) % lm->size;
}
lm->count = 0;
lm->next = 0;
vlib_log_info (log_log.class, "log cleared");
return error;
}
VLIB_CLI_COMMAND (cli_clear_log, static) = {
.path = "clear logging",
.short_help = "clear logging",
.function = clear_log,
};
05=本次内容总结
本次内容主要是介绍了VPP中日志模块log的初始化操作、使用方法、查询方法、清理方法的介绍,其思维导图可以总结为:
总的来说,在vpp的vlib_log_init()这个函数中,日志系统被初始化,包括设置时间戳参数、创建/验证日志条目数组的大小、注册日志类别以及设置默认的日志级别和syslog级别等的功能。在使用章节中,我们介绍log功能在vpp上的使用方法,有需要的小伙伴们可以根据项目需要自己修改相关的逻辑和配置。好了,本次介绍就到此为止。小伙伴们,你们学会了吗?