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源码了
|