glog源码

log流程

宏定义:

#define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
 498 #if GOOGLE_STRIP_LOG == 0
 499 #define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::LogMessage( \
 500       __FILE__, __LINE__)
 501 #define LOG_TO_STRING_INFO(message) @ac_google_namespace@::LogMessage( \
 502       __FILE__, __LINE__, @ac_google_namespace@::GLOG_INFO, message)
 503 #else
 504 #define COMPACT_GOOGLE_LOG_INFO @ac_google_namespace@::NullStream()
 505 #define LOG_TO_STRING_INFO(message) @ac_google_namespace@::NullStream()
 506 #endif

构造对象LogMessage

1574 LogMessage::LogMessage(const char* file, int line)
1575     : allocated_(NULL) {
1576   Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
1577 }

然后获取stream()

1742 ostream& LogMessage::stream() {
1743   return data_->stream_;
1744 }
1745 

data类型LogMessageData,stream_类型LogStream

class GLOG_EXPORT LogStream : public std::ostream {
}

最终会通过操作符 << 向std::ostream中写入数据 

LogMessageData初始化

在LogMessage构造下Init函数中完成

如果支持线程数据,则在thread_msg_data处调用placement new构造LogMessageData

thread_msg_data定义如下,即线程存储:

1546 #if defined(HAVE_ALIGNED_STORAGE) && __cplusplus >= 201103L
1547 static GLOG_THREAD_LOCAL_STORAGE
1548     std::aligned_storage<sizeof(LogMessage::LogMessageData),
1549                          alignof(LogMessage::LogMessageData)>::type thread_msg_data;
1550 #else
1551 static GLOG_THREAD_LOCAL_STORAGE
1552     char thread_msg_data[sizeof(void*) + sizeof(LogMessage::LogMessageData)];
1553 #endif  // HAVE_ALIGNED_STORAGE
1554 #endif  // defined(GLOG_THREAD_LOCAL_STORAGE)

LogMessageData构造:

1556 LogMessage::LogMessageData::LogMessageData()
1557   : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
1558 }

这里message_text_是 字符数组 

LogStream构造 :

1484     LogStream(char *buf, int len, int64 ctr)
1485         : std::ostream(NULL),
1486           streambuf_(buf, len),
1487           ctr_(ctr),
1488           self_(this) {
1489       rdbuf(&streambuf_);
1490     }

LogMessage构造下Init函数中会设置回调函数:

data_->send_method_ = send_method

即LogMessage::SendToLog

磁盘刷新时机

1723 LogMessage::~LogMessage() {
1724   Flush();
1725 #ifdef GLOG_THREAD_LOCAL_STORAGE
1726   if (data_ == static_cast<void*>(&thread_msg_data)) {
1727     data_->~LogMessageData();
1728     thread_data_available = true;
1729   }
1730   else {
1731     delete allocated_;
1732   }
1733 #else // !defined(GLOG_THREAD_LOCAL_STORAGE)
1734   delete allocated_;
1735 #endif // defined(GLOG_THREAD_LOCAL_STORAGE)
1736 }

LogMessage::Flush()实现

1748 void LogMessage::Flush() {
1775   {
1776     MutexLock l(&log_mutex);
1777     (this->*(data_->send_method_))();
1778     ++num_messages_[static_cast<int>(data_->severity_)];
1779   }
}

写文件实现

SendToLog实现

void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
1858     LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
1859                                      data_->message_text_,
1860                                      data_->num_chars_to_log_);
1861 
1862     LogDestination::MaybeLogToStderr(data_->severity_, data_->message_text_,
1863                                      data_->num_chars_to_log_,
1864                                      data_->num_prefix_chars_);
1865     LogDestination::MaybeLogToEmail(data_->severity_, data_->message_text_,
1866                                     data_->num_chars_to_log_);
1867     LogDestination::LogToSinks(data_->severity_,
1868                                data_->fullname_, data_->basename_,
1869                                data_->line_, logmsgtime_,
1870                                data_->message_text_ + data_->num_prefix_chars_,
1871                                (data_->num_chars_to_log_
1872                                 - data_->num_prefix_chars_ - 1) );
}

具体实现在LogToAllLogfiles 

 870 inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
 871                                              time_t timestamp,
 872                                              const char* message,
 873                                              size_t len) {
 874   if (FLAGS_logtostdout) {  // global flag: never log to file
 875     ColoredWriteToStdout(severity, message, len);
 876   } else if (FLAGS_logtostderr) {  // global flag: never log to file
 877     ColoredWriteToStderr(severity, message, len);
 878   } else {
 879     for (int i = severity; i >= 0; --i) {
 880       LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
 881     }
 882   }
 883 }

然后

 861 inline void LogDestination::MaybeLogToLogfile(LogSeverity severity,
 862                                               time_t timestamp,
 863                           const char* message,
 864                           size_t len) {
 865   const bool should_flush = severity > FLAGS_logbuflevel;
 866   LogDestination* destination = log_destination(severity);
 867   destination->logger_->Write(should_flush, timestamp, message, len);
 868 }

最终调用LogFileObject::Write:

  • 如果file_length_过大,关闭file_
  • 获取时间,调用CreateLogfile创建文件,使用文件锁fcntl(fd, F_SETLK, &w_lock)防止多个客户端写文件,创建软连接
  • 生成文件头信息,写入文件,fwrite(file_header_string.data(), 1, header_len, file_),更新字段

        1274     file_length_ += header_len;

        1275     bytes_since_flush_ += header_len;

  • 写入消息,调用fwrite(message, 1, message_len, file_);更新字段

        1274     file_length_ += header_len;

        1275     bytes_since_flush_ += header_len;

  • 刷新磁盘时机
1304   if ( force_flush ||
1305        (bytes_since_flush_ >= 1000000) ||
1306        (CycleClock_Now() >= next_flush_time_) ) {
1307     FlushUnlocked();

即满足下面其一:

1. force_flush =severity > FLAGS_logbuflevel(默认0)

2.fwrite写入数据大约超过980k

3.FLAGS_logbufsecs默认30秒,即超过30秒更新

1035   const int64 next = (FLAGS_logbufsecs * static_cast<int64>(1000000));  // in usec
1037   next_flush_time_ = CycleClock_Now() + UsecToCycles(next);

C标准缓冲刷新

1024 void LogFileObject::Flush() {
1025   MutexLock l(&lock_);
1026   FlushUnlocked();
1027 }
1028 
1029 void LogFileObject::FlushUnlocked(){
1030   if (file_ != NULL) {
1031     fflush(file_);
1032     bytes_since_flush_ = 0;
1033   }
1034   // Figure out when we are due for another flush.
1035   const int64 next = (FLAGS_logbufsecs
1036                       * static_cast<int64>(1000000));  // in usec
1037   next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
1038 }

配置项

logging.cpp中

 116 GLOG_DEFINE_bool(timestamp_in_logfile_name,
 117                  BoolFromEnv("GOOGLE_TIMESTAMP_IN_LOGFILE_NAME", true),
 118                  "put a timestamp at the end of the log file name");
 119 GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
 120                  "log messages go to stderr instead of logfiles");
 121 GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
 122                  "log messages go to stderr in addition to logfiles");
 123 GLOG_DEFINE_bool(colorlogtostderr, false,
 124                  "color messages logged to stderr (if supported by terminal)");
 125 GLOG_DEFINE_bool(colorlogtostdout, false,
 126                  "color messages logged to stdout (if supported by terminal)");
 127 GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
 128                  "log messages go to stdout instead of logfiles");
 129 #ifdef GLOG_OS_LINUX
 130 GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
 131                  "Logs can grow very quickly and they are rarely read before they "
 132                  "need to be evicted from memory. Instead, drop them from memory "
 133                  "as soon as they are flushed to disk.");
 134 #endif


 141 DEFINE_int32(stderrthreshold,
 142              GOOGLE_NAMESPACE::GLOG_ERROR,
 143              "log messages at or above this level are copied to stderr in "
 144              "addition to logfiles.  This flag obsoletes --alsologtostderr.");
 145 
 146 GLOG_DEFINE_string(alsologtoemail, "",
 147                    "log messages go to these email addresses "
 148                    "in addition to logfiles");
 149 GLOG_DEFINE_bool(log_prefix, true,
 150                  "Prepend the log prefix to the start of each log line");
 151 GLOG_DEFINE_bool(log_year_in_prefix, true,
 152                  "Include the year in the log prefix");
 153 GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
 154                   "actually get logged anywhere");
 155 GLOG_DEFINE_int32(logbuflevel, 0,
 156                   "Buffer log messages logged at this level or lower"
 157                   " (-1 means don't buffer; 0 means buffer INFO only;"
 158                   " ...)");
 159 GLOG_DEFINE_int32(logbufsecs, 30,
 160                   "Buffer log messages for at most this many seconds");
 161 
 162 GLOG_DEFINE_int32(logcleansecs, 60 * 5, // every 5 minutes
 163                   "Clean overdue logs every this many seconds");
 164 
 165 GLOG_DEFINE_int32(logemaillevel, 999,
 166                   "Email log messages logged at this level or higher"
 167                   " (0 means email all; 3 means email FATAL only;"
 168                   " ...)");
 169 GLOG_DEFINE_string(logmailer, "",
 170                    "Mailer used to send logging email");

 186 GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
 187 
 188 GLOG_DEFINE_string(log_dir, DefaultLogDir(),
 189                    "If specified, logfiles are written into this directory instead "
 190                    "of the default logging directory.");
 191 GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
 192                    "files in this directory");
 193 
 194 GLOG_DEFINE_uint32(max_log_size, 1800,
 195                    "approx. maximum log file size (in MB). A value of 0 will "
 196                    "be silently overridden to 1.");
 197 
 198 GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
 199                  "Stop attempting to log to disk if the disk is full.");
 200 
 201 GLOG_DEFINE_string(log_backtrace_at, "",
 202                    "Emit a backtrace when logging at file:linenum.");
 203 
 204 GLOG_DEFINE_bool(log_utc_time, false,
 205     "Use UTC time for logging.");

minloglevel,小于该值不会fwrite

logbuflevel,大于该值强制刷新

logbufsecs(单位秒),超过该时间刷新

max_log_size(单位M),文件大小

drop_log_memory,当为true且 file_length_ >= (3U << 20U)即大于3M,会通过计算决定是否调用

1322         posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length,
1323                       POSIX_FADV_DONTNEED);

posix_fadvise是一个用于控制 page cache 预读或清理策略的接口。应用可以使用这个接口来告诉内核,接下来将以何种模式访问文件数据,从而允许内核执行适当的优化。但是,这个接口对内核提交的是建议,不一定会被采纳。

POSIX_FADV_DONTNEED :指定的数据将不会被访问,丢弃 page cache 中的数据,内核先将脏页异步刷盘,并且只会尽力而为,清除掉自己能清除的缓存,而不会等待刷脏完成后再清除文件的全部缓存。

总结

1.基本上可以做到同步刷新(但没调用fsync相关)

2.多线程下有锁,性能会差

3.每次写日志的构造和析构,性能影响未知

4.设计较好,扩展多,方便使用,适用于通用场景,不适用高性能场景

5.如果再深究,就需要看fwrite源码了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MyObject-C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值