IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> glog源码 -> 正文阅读

[C++知识库]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源码了

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:05:26  更:2022-03-30 18:07:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:14:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码