提供与日志消息格式化相关的两个函数:
void LogEvent::format(const char* fmt, ...) {
va_list al;
va_start(al, fmt);
format(fmt, al);
va_end(al);
}
这个format
函数是LogEvent
类的成员函数,它设计为接受一个格式化字符串和随后的可变数量的参数(如printf
函数)。它是一个可变参数函数,这由参数列表中的省略号(...
)表示。
va_list al;
声明了一个名为al
的变量,类型为va_list
,该变量将保存参数列表。va_start(al, fmt);
将al
初始化,使其指向参数fmt
之后的第一个可变参数。format(fmt, al);
调用了重载版本的format
函数,该函数的第二个参数是va_list
类型。va_end(al);
清理了与al
相关的资源。
void LogEvent::format(const char* fmt, va_list al) {
char* buf = nullptr;
int len = vasprintf(&buf, fmt, al);
if(len != -1) {
m_ss << std::string(buf, len);
free(buf);
}
}
这个重载的format
函数与第一个函数紧密相关,但它直接接受一个va_list
参数。这个函数是实际执行字符串格式化的地方。
char* buf = nullptr;
定义了一个指向字符的指针buf
,并将其初始化为nullptr
。int len = vasprintf(&buf, fmt, al);
使用vasprintf
函数根据格式化字符串fmt
和参数列表al
来分配足够的内存,并写入格式化后的字符串。vasprintf
函数返回写入的字符数(不包括结尾的空字符)。- 如果
len
不是-1,代表格式化成功,然后创建一个std::string
对象并将其内容添加到LogEvent
类内部的字符串流m_ss
中。 free(buf);
释放vasprintf
函数分配的内存。
以下是如何使用这个函数的示例:
Logger::ptr logger = LoggerMgr::GetInstance()->getLogger("system");
// 假设 LogEvent 类和 LoggerMgr 类已经定义好了
LogEvent::ptr event(new LogEvent(logger, LogLevel::INFO, __FILE__, __LINE__, 0, GetThreadId(), GetFiberId(), time(nullptr), "main"));
// 创建日志事件实例
event->format("This is a formatted number: %d, and a string: %s", 42, "hello world");
// 使用 format 方法添加格式化信息
在这个示例中,format
方法使用类似于 C 标准库中 printf
函数的语法,接受一个格式化字符串和一系列可变参数。它会根据格式化字符串和提供的参数来构建最终的日志消息。
它的底层实现逻辑是:
第一个format
函数接受一个格式化字符串fmt
,随后是一个可变数量的参数,这与printf
函数的使用方式类似。这个函数的目的是为了直接被调用时提供方便,允许在代码中直接传入多个参数,并按照fmt
指定的格式将它们格式化为字符串。
第二个format
函数接受相同的格式化字符串fmt
,但第二个参数是va_list
类型,它代表一个已经初始化的可变参数列表。这个函数通常用在你已经有一个va_list
的情况下,或者当你需要将参数列表传递给另一个函数进行格式化。在这个函数内部,它使用va_start
和va_end
宏来处理可变参数列表,并将这个列表传递给第二个format
函数。
使用第一个format
函数进行可变参数列表的初始化和清理,第二个format
函数提供了更多的灵活性,但是需要手动处理va_list
的生命周期,包括它的初始化和清理。