写日志的一个流程:
(1)logging.h中MYLOG宏定义(源码是LOG宏,稍微改了一点源码):
这里是一个宏连接,上面的switch(GLOG_DEBUD)等价于
COMPACT_GOOGLE_LOG_DEBUG.mystream(m_baseName.c_str()) << message;
(2)再来看看logging.h关于 COMPACT_GOOGLE_LOG_DEBUG的宏定义是什么:
原来是调用LogMessage的构造函数,生成一个LogMessage对象,那么这就很好理解了:
mystream方法:
COMPACT_GOOGLE_LOG_DEBUG.mystream(m_baseName.c_str()) << message等价于:
先调用LogMessage(...)构造函数构造对象,然后调用该对象的mystream()方法,并把message拼接到mystream的返回值;
(3)接下来再看看构造函数干了什么事情:
调用Init()函数:
初始化LogMessageData结构体,把SendToLog函数地址给结构体(LogMessage销毁时调用,进行日志输出),初始化日志前缀
即把日志前缀初始化用data_->stream_保存起来,然后函数结束时通过<<message拼接到后面
void LogMessage::Init(const char* file,
int line,
LogSeverity severity,
void (LogMessage::*send_method)()) {
allocated_ = NULL;
if (severity != GLOG_FATAL || !exit_on_dfatal) {
#ifdef GLOG_THREAD_LOCAL_STORAGE
// No need for locking, because this is thread local.
if (thread_data_available) {
thread_data_available = false;
#ifdef HAVE_ALIGNED_STORAGE
data_ = new (&thread_msg_data) LogMessageData;
#else
const uintptr_t kAlign = sizeof(void*) - 1;
char* align_ptr =
reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(thread_msg_data + kAlign) & ~kAlign);
data_ = new (align_ptr) LogMessageData;
assert(reinterpret_cast<uintptr_t>(align_ptr) % sizeof(void*) == 0);
#endif
} else {
allocated_ = new LogMessageData();
data_ = allocated_;
}
#else // !defined(GLOG_THREAD_LOCAL_STORAGE)
allocated_ = new LogMessageData();
data_ = allocated_;
#endif // defined(GLOG_THREAD_LOCAL_STORAGE)
data_->first_fatal_ = false;
} else {
MutexLock l(&fatal_msg_lock);
if (fatal_msg_exclusive) {
fatal_msg_exclusive = false;
data_ = &fatal_msg_data_exclusive;
data_->first_fatal_ = true;
} else {
data_ = &fatal_msg_data_shared;
data_->first_fatal_ = false;
}
}
stream().fill('0');
data_->preserved_errno_ = errno;
data_->severity_ = severity;
data_->line_ = line;
data_->send_method_ = send_method;
data_->sink_ = NULL;
data_->outvec_ = NULL;
WallTime now = WallTime_Now();
data_->timestamp_ = static_cast<time_t>(now);
localtime_r(&data_->timestamp_, &data_->tm_time_);
int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
data_->num_chars_to_log_ = 0;
data_->num_chars_to_syslog_ = 0;
data_->basename_ = const_basename(file);
data_->fullname_ = file;
data_->has_been_flushed_ = false;
// If specified, prepend a prefix to each line. For example:
// I1018 160715 f5d4fbb0 logging.cc:1153]
// (log level, GMT month, date, time, thread_id, file basename, line)
// We exclude the thread_id for the default thread.
if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
stream() << LogSeverityNames[severity][0]
<< setw(2) << 1+data_->tm_time_.tm_mon
<< setw(2) << data_->tm_time_.tm_mday
<< ' '
<< setw(2) << data_->tm_time_.tm_hour << ':'
<< setw(2) << data_->tm_time_.tm_min << ':'
<< setw(2) << data_->tm_time_.tm_sec << "."
<< setw(6) << usecs
<< ' '
<< setfill(' ') << setw(5)
<< static_cast<unsigned int>(GetTID()) << setfill('0')
<< ' '
<< data_->basename_ << ':' << data_->line_ << "] ";
}
data_->num_prefix_chars_ = data_->stream_.pcount();
if (!FLAGS_log_backtrace_at.empty()) {
char fileline[128];
snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
#ifdef HAVE_STACKTRACE
if (!strcmp(FLAGS_log_backtrace_at.c_str(), fileline)) {
string stacktrace;
DumpStackTraceToString(&stacktrace);
stream() << " (stacktrace:\n" << stacktrace << ") ";
}
#endif
}
}
(4)data_->send_method_保存了日志输出的方法,data_->stream_保存了日志消息,所以在LogMessage析构时调用Flush()方法,将日志输出,同时释放内存:
LogMessage::~LogMessage() {
Flush(); //输出日志
if(allocated_)
{
delete allocated_;
allocated_ = NULL;
}
}
void LogMessage::Flush() {
...//略
{
MutexLock l(&log_mutex);
(this->*(data_->send_method_))(); //调用SendToLog
++num_messages_[static_cast<int>(data_->severity_)];
}
LogDestination::WaitForSinks(data_);
...//略
data_->has_been_flushed_ = true;
}
void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
static bool already_warned_before_initgoogle = false;
log_mutex.AssertHeld();
...//略
if (!FLAGS_logtostderr) {
for (int i = 0; i < NUM_SEVERITIES; ++i) {
if ( LogDestination::log_destinations_[i] )
LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
}
}
log_mutex.Unlock();
LogDestination::WaitForSinks(data_);
const char* message = "*** Check failure stack trace: ***\n";
if (write(STDERR_FILENO, message, strlen(message)) < 0) {
// Ignore errors.
}
Fail();
}
}
至此,一个写日志的流程完成。