BRPC关于日志的描述比较模糊,因此记录下BRPC中日志的使用,内容包括BRPC日志重定向,BRPC日志自定义日志格式,BRPC日志实现不同级别打印到不同的文件去
BRPC日志默认打印在STDERR
,但是可以重定向,也可以重新实现,先说最简单的重定向,只需要添加以下代码:
std::string log_path = "SB_YOYO.log";
::logging::LoggingSettings log_setting; # 创建LoggingSetting对象进行设置
log_setting.log_file = log_path.c_str(); # 设置日志路径
log_setting.logging_dest = logging::LOG_TO_FILE; # 设置日志写到文件,不写的话不生效
::logging::InitLogging(log_setting); # 应用日志设置
默认的BPRC日志格式如下:
I0716 17:09:08.911966 22206 core/listener.cpp:111] Create socket success.
但是默认个格式感觉有点长,其实我根本不需要毫秒,线程ID这种信息,所以需要去除这些信息。
BRPC日志支持自定义格式,只需要继承LogSink对象即可,示例如下:
FILE* bili_log = fopen("SB_YOYO.log", "a");
class BiliLogSink : public ::logging::LogSink
{
public:
BiliLogSink();
~BiliLogSink();
// 一定要写这个方法,用这个OnLogMessage去替换原本的方法,实现自定义日志格式
bool OnLogMessage(int severity,
const char* file,
int line,
const butil::StringPiece& content)
{
// 写的方式模仿BRPC默认的OnLogMessage
// 这里只写Linux下的日志,Windows参考BRPC/src/butil/logging.cc
std::ostringstream os; // BRPC默认的就用的是ostringstream
// 仅打印日志级别,文件,行数,日志内容
os << severity << ' ' << file << ':' << line << ']' << content << '\n';
// 大于ERROR级别的日志,都要打印到STDERR中去
if (severity >= kAlwaysPrintErrorLevel) {
fwrite(log.data(), log.size(), 1, stderr);
fflush(stderr);
}
// 开始打日志,logging_destination这种东西都自己参考logging.cc定义下
if ((logging_destination & LOG_TO_FILE) != 0) {
// 为了线程安全,这种日志需要加锁,锁的实现我直接抄logging.cc了
// BRPC内部logging.cc的锁是匿名空间的内容,外部是看不到的
// 为了尽量不修改BRPC代码,自己抄一份锁
LoggingLock::Init(LOCK_LOG_FILE, NULL);
LoggingLock logging_lock;
if (bili_log) {
fwrite(log.data(), log.size(), 1, bili_log);
fflush(bili_log_file);
}
}
return true;
}
};
继承了LogSink
还不够,还需要再应用以下BRPC的日志,应用示例如下:
::logging::LogSink* new_sink = new BiliLogSink();
::logging::LogSink* old_sink = ::logging::SetLogSink(new_sink);
if (old_sink) {
delete old_sink;
}
应用了之后,日志就会按照我们写的OnLogMessage
进行打印,效果如下:
0 core/listener.cpp:111] Create socket success.
BRPC默认只打印到一个文件内,但是我希望INFO
级别的日志打印到INFO.log
,ERROR
级别的日志打印到ERROR.log
中去,怎么做?
我们其实还是可以通过继承LogSink
进行编写自己的方法,只需要将刚才的代码修改一下即可:
FILE* bili_info_log = fopen("SB_YOYO.info.log", "a");
FILE* bili_error_log = fopen("SB_YOYO.error.log", "a");
class BiliLogSink : public ::logging::LogSink
{
public:
BiliLogSink();
~BiliLogSink();
// 一定要写这个方法,用这个OnLogMessage去替换原本的方法,实现自定义日志格式
bool OnLogMessage(int severity,
const char* file,
int line,
const butil::StringPiece& content)
{
// 写的方式模仿BRPC默认的OnLogMessage
// 这里只写Linux下的日志,Windows参考BRPC/src/butil/logging.cc
std::ostringstream os; // BRPC默认的就用的是ostringstream
// 仅打印日志级别,文件,行数,日志内容
os << severity << ' ' << file << ':' << line << ']' << content << '\n';
// 大于ERROR级别的日志,都要打印到STDERR中去
if (severity >= kAlwaysPrintErrorLevel) {
fwrite(log.data(), log.size(), 1, stderr);
fflush(stderr);
}
// 开始打日志,logging_destination这种东西都自己参考logging.cc定义下
if ((logging_destination & LOG_TO_FILE) != 0) {
// 为了线程安全,这种日志需要加锁,锁的实现我直接抄logging.cc了
// BRPC内部logging.cc的锁是匿名空间的内容,外部是看不到的
// 为了尽量不修改BRPC代码,自己抄一份锁
LoggingLock::Init(LOCK_LOG_FILE, NULL);
LoggingLock logging_lock;
if (bili_info_log && bili_error_log) {
// 唯一不同的就是这里,根据日志级别不同,打印到不同文件就好了
// 这样做的话,LogSetting中的log_file就没有设置的意义了,
// 因为根本没用到
if (severity == ::logging::BLOG_INFO) {
fwrite(log.data(), log.size(), 1, bili_info_log);
fflush(bili_info_log);
} else if (severity == ::logging::BLOG_INFO) {
fwrite(log.data(), log.size(), 1, bili_error_log);
fflush(bili_error_log);
}
}
}
return true;
}
};