关于C#:使用glog记录无法正常工作

logging with glog is not working properly

当我使用:

时,我正在使用glog进行日志记录

1
LOG(INFO) <<"something";

它按预期工作,但是当我使用如下所示的多个日志时,直到程序停止,它才会记录日志。当programm停止时,它将按预期记录所有内容。

1
2
3
4
LOG(INFO) <<"111111111111111";
LOG(INFO) <<"222222222222222";
LOG(INFO) <<"333333333333333";
LOG(INFO) <<"444444444444444";

但是这里令人困惑的是,当我多次使用LOG(WARNING)时,它可以完美地工作,即即使程序正在运行,它也会记录所有内容,而以前的情况是在程序停止时记录所有内容。

1
2
3
4
LOG(WARNING) <<"111111111111111";
LOG(WARNING) <<"222222222222222";
LOG(WARNING) <<"333333333333333";
LOG(WARNING) <<"444444444444444";

**对此行为的任何帮助将不胜感激**


这是因为默认情况下glog缓冲INFO日志。缓冲由标志FLAG_logbuflevel控制,标志的默认值为0,即所有严重性<=该值都将被缓冲。

可接受的答案是可行的,因为google::FlushLogFiles(min_severity)会强制刷新> = min_severity的所有日志,但是在生产代码库中定义我们的自定义宏可能不可行。因此,防止缓冲INFO日志的最简单解决方案是将FLAG_logbuflevel设置为-1

另一个答案提出了一个有趣的想法,即LogMessage::~LogMessage()具有对Flush()的调用,因此不需要接受的答案中建议的显式刷新。这是不正确的,因为在dtor中对Flush()的调用是有条件的。这是调用堆栈-

1
2
3
4
5
6
LogMessage::~LogMessage()
|__LogMessage::Flush()
   |__(LogMessage::*send_method_)() == LogMessage::SendToLog()
       |__LogDestination::LogToAllLogfiles()
          |__LogDestination::MaybeLogToLogfile()
             |__Logger::Write(should_flush = log_severity > FLAGS_logbuflevel )

如在调用堆栈的最后一帧中所见,

到日志目标(文件)的实际Write包含一个布尔值should_flush,它取决于我之前提到的标志FLAGS_logbuflevel。铅>

因此,默认情况下,即使LogMessage

的dtor中有一个Flush调用,也不会实际将数据刷新到磁盘上


问题很简单。默认情况下,glog为每个严重性使用一个日志文件,以防止两个流打开同一文件。如果通过不同的流在c++中打开同一文件,则优先选择其中一个(打开文件的第一个)以写入文件。当第一个流关闭时,另一个只能开始写入该文件。

您必须为每种严重性声明不同的日志文件,或者将所有日志消息都存储在一个文件中,您只需编写自己的小日志库即可。

似乎特别是需要使用google::FlushLogFiles(google::INFO)刷新INFO流。为此,在每个要记录的信息之后,我将为自己定义一个宏以调用flush函数,如下所示:

1
#define log(severity, msg) LOG(severity) << msg; google::FlushLogFiles(google::severity);

这确保流将被刷新,并且您的所有消息将出现在日志文件中


尽管以上答案已被接受并且可能有助于解决问题,但我不确定这是否是解决问题的正确方法,甚至是正确的解释。

如果检查glog的代码,则会发现:

1
#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()

因此在最初的问题中,LOG(INFO)将被定义为类似于

1
#define COMPACT_GOOGLE_LOG_INFO google::LogMessage(__FILE__, __LINE__, google::GLOG_INFO).stream()

将创建一个临时流对象,并将日志记录内容写入该流对象。之后,将调用LogMessage LogMessage::~LogMessage()的析构函数。在该析构函数内部,实际上将调用Flush()将记录内容刷新到I / O设备。

也就是说,对于每个LOG(INFO)语句,将创建并销毁一个临时流对象,并在销毁Flush()之前调用它。因此,恕我直言,不需要对google::LogMessage::Flush()甚至google::FlushLogFiles(google::INFO)进行额外的调用。