google开源库glog源码实现分析
2017-10-18 16:34
429 查看
#include <vector> # define GOOGLE_GLOG_DLL_DECL __declspec(dllexport) # define GOOGLE_GLOG_DLL_DECL_FOR_UNITTESTS __declspec(dllimport) namespace base_logging { // LogMessage::LogStream is a std::ostream backed by this streambuf. // This class ignores overflow and leaves two bytes at the end of the // buffer to allow for a '\n' and '\0'. class GOOGLE_GLOG_DLL_DECL LogStreamBuf : public std::streambuf { public: // REQUIREMENTS: "len" must be >= 2 to account for the '\n' and '\n'. LogStreamBuf(char *buf, int len) { setp(buf, buf + len - 2); } // This effectively ignores overflow. virtual int_type overflow(int_type ch) { return ch; } // Legacy public ostrstream method. size_t pcount() const { return pptr() - pbase(); } char* pbase() const { return std::streambuf::pbase(); } }; } // namespace base_logging class GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream { #ifdef _MSC_VER # pragma warning(default: 4275) #endif public: LogStream(char *buf, int len, int ctr) : std::ostream(NULL), streambuf_(buf, len), ctr_(ctr), self_(this) { rdbuf(&streambuf_); } int ctr() const { return ctr_; } void set_ctr(int ctr) { ctr_ = ctr; } LogStream* self() const { return self_; } // Legacy std::streambuf methods. size_t pcount() const { return streambuf_.pcount(); } char* pbase() const { return streambuf_.pbase(); } char* str() const { return pbase(); } private: LogStream(const LogStream&); LogStream& operator=(const LogStream&); base_logging::LogStreamBuf streambuf_; int ctr_; // Counter hack (for the LOG_EVERY_X() macro) LogStream *self_; // Consistency check hack }; typedef int LogSeverity; //static Mutex log_mutex; // Number of messages sent at each severity. Under log_mutex. //int64 LogMessage::num_messages_[NUM_SEVERITIES] = { 0, 0, 0, 0 }; // Globally disable log writing (if disk is full) static bool stop_writing = false; const char*const LogSeverityNames[NUM_SEVERITIES] = { "INFO", "WARNING", "ERROR", "FATAL" }; // Has the user called SetExitOnDFatal(true)? static bool exit_on_dfatal = true; const char* GetLogSeverityName(LogSeverity severity) { return LogSeverityNames[severity]; } typedef int pid_t; #include <processthreadsapi.h> pid_t GetTID() { return GetCurrentThreadId(); } #include <iomanip> class GOOGLE_GLOG_DLL_DECL LogSink { public: virtual ~LogSink() {} virtual void send(LogSeverity severity, const char* full_filename, const char* base_filename, int line, const struct ::tm* tm_time, const char* message, size_t message_len) = 0; virtual void WaitTillSent() {} static std::string ToString(LogSeverity severity, const char* file, int line, const struct ::tm* tm_time, const char* message, size_t message_len) { ostringstream stream(string(message, message_len)); stream.fill('0'); // FIXME(jrvb): Updating this to use the correct value for usecs // requires changing the signature for both this method and // LogSink::send(). This change needs to be done in a separate CL // so subclasses of LogSink can be updated at the same time. int usecs = 0; stream << "[" << LogSeverityNames[severity][0] << setw(2) << 1 + tm_time->tm_mon << setw(2) << tm_time->tm_mday << ' ' << setw(2) << tm_time->tm_hour << ':' << setw(2) << tm_time->tm_min << ':' << setw(2) << tm_time->tm_sec << '.' << setw(6) << usecs << ' ' << setfill(' ') << setw(5) << GetTID() << setfill('0') << ' ' << file << ':' << line << "] "; stream << string(message, message_len); return stream.str(); } }; const int kMaxLogMessageLen = 30000; struct LogMessageData { LogMessageData() : stream_(message_text_, /*LogMessage::*/kMaxLogMessageLen, 0) {} int preserved_errno_; // preserved errno // Buffer space; contains complete message text. char message_text_[kMaxLogMessageLen + 1]; LogStream stream_; char severity_; // What level is this LogMessage logged at? int line_; // line number where logging call is. //void (LogMessage::*send_method_)(); // Call this in destructor to send union { // At most one of these is used: union to keep the size low. LogSink* sink_; // NULL or sink to send message to std::vector<std::string>* outvec_; // NULL or vector to push message onto std::string* message_; // NULL or string to write message into }; time_t timestamp_; // Time of creation of LogMessage struct ::tm tm_time_; // Time of creation of LogMessage size_t num_prefix_chars_; // # of chars of prefix in this message size_t num_chars_to_log_; // # of chars of msg to send to log size_t num_chars_to_syslog_; // # of chars of msg to send to syslog const char* basename_; // basename of file that called LOG const char* fullname_; // fullname of file that called LOG bool has_been_flushed_; // false => data has not been flushed bool first_fatal_; // true => this was first fatal msg private: LogMessageData(const LogMessageData&); void operator=(const LogMessageData&) {} }; class LogMessage { public: // icc 8 requires this typedef to avoid an internal compiler error. typedef void (LogMessage::*SendMethod)(); /*LogMessage(const char* file, int line, LogSeverity severity, int ctr, SendMethod send_method);*/ LogMessage(const char* file, int line); LogMessage(const char* file, int line, LogSeverity severity); LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, bool also_send_to_log); LogMessage(const char* file, int line, LogSeverity severity, std::vector<std::string>* outvec); LogMessage(const char* file, int line, LogSeverity severity, std::string* message); ~LogMessage(); void Flush(); static const size_t kMaxLogMessageLen = 30000; void SendToLog() {} // Actually dispatch to the logs void SendToSyslogAndLog() {} // Actually dispatch to syslog and the logs static void Fail() {} std::ostream& stream(); int preserved_errno() const; //static int64 num_messages(int severity); private: // Fully internal SendMethod cases: void SendToSinkAndLog() {} // Send to sink if provided and dispatch to the logs void SendToSink() {} // Send to sink if provided, do nothing otherwise. void WriteToStringAndLog() {} void SaveOrSendToLog() {} // Save to stringvec if provided, else to logs void Init(const char* file, int line, LogSeverity severity, void (LogMessage::*send_method)()); //static int64 num_messages_[NUM_SEVERITIES]; // under log_mutex LogMessageData* allocated_; LogMessageData* data_; friend class LogDestination; LogMessage(const LogMessage&); void operator=(const LogMessage&) {} }; /* LogMessageData::LogMessageData() : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) { } LogMessage::LogMessage(const char* file, int line, LogSeverity severity, int ctr, void (LogMessage::*send_method)()) : allocated_(NULL) { Init(file, line, severity, send_method); data_->stream_.set_ctr(ctr); } LogMessage::LogMessage(const char* file, int line, const CheckOpString& result) : allocated_(NULL) { Init(file, line, GLOG_FATAL, &LogMessage::SendToLog); stream() << "Check failed: " << (*result.str_) << " "; }*/ LogMessage::LogMessage(const char* file, int line) : allocated_(NULL) { Init(file, line, GLOG_INFO, &LogMessage::SendToLog); } LogMessage::LogMessage(const char* file, int line, LogSeverity severity) : allocated_(NULL) { Init(file, line, severity, &LogMessage::SendToLog); } LogMessage::LogMessage(const char* file, int line, LogSeverity severity, LogSink* sink, bool also_send_to_log) : allocated_(NULL) { Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog : &LogMessage::SendToSink); data_->sink_ = sink; // override Init()'s setting to NULL } LogMessage::LogMessage(const char* file, int line, LogSeverity severity, vector<string> *outvec) : allocated_(NULL) { Init(file, line, severity, &LogMessage::SaveOrSendToLog); data_->outvec_ = outvec; // override Init()'s setting to NULL } LogMessage::LogMessage(const char* file, int line, LogSeverity severity, string *message) : allocated_(NULL) { Init(file, line, severity, &LogMessage::WriteToStringAndLog); data_->message_ = message; // override Init()'s setting to NULL } static int gettimeofday(struct timeval *tv, void* tz) { #define EPOCHFILETIME (116444736000000000ULL) FILETIME ft; LARGE_INTEGER li; uint64_t tt; GetSystemTimeAsFileTime(&ft); li.LowPart = ft.dwLowDateTime; li.HighPart = ft.dwHighDateTime; tt = (li.QuadPart - EPOCHFILETIME) / 10; tv->tv_sec = tt / 1000000; tv->tv_usec = tt % 1000000; return 0; } int64_t CycleClock_Now() { // TODO(hamaji): temporary impementation - it might be too slow. struct timeval tv; gettimeofday(&tv, NULL); return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec; } int64_t UsecToCycles(int64_t usec) { return usec; } time_t WallTime_Now() { // Now, cycle clock is retuning microseconds since the epoch. return CycleClock_Now() * 0.000001; } inline struct tm* localtime_r(const time_t* timep, struct tm* result) { localtime_s(result, timep); return result; } static struct ::tm last_tm_time_for_raw_log; static int last_usecs_for_raw_log; void RawLog__SetLastTime(const struct ::tm& t, int usecs) { memcpy(&last_tm_time_for_raw_log, &t, sizeof(last_tm_time_for_raw_log)); last_usecs_for_raw_log = usecs; } #define OS_WINDOWS const char* const_basename(const char* filepath) { const char* base = strrchr(filepath, '/'); #ifdef OS_WINDOWS // Look for either path separator in Windows if (!base) base = strrchr(filepath, '\\'); #endif return base ? (base + 1) : filepath; } void LogMessage::Init(const char* file, int line, LogSeverity severity, void (LogMessage::*send_method)()) { allocated_ = NULL; if (severity != GLOG_FATAL || !exit_on_dfatal) { allocated_ = new LogMessageData(); data_ = allocated_; 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; time_t 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); RawLog__SetLastTime(data_->tm_time_, usecs); 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 (1/*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(); } LogMessage::~LogMessage() { Flush(); delete allocated_; } int LogMessage::preserved_errno() const { return data_->preserved_errno_; } ostream& LogMessage::stream() { return data_->stream_; } void LogMessage::Flush() { if (data_->has_been_flushed_ || data_->severity_ < 0/*FLAGS_minloglevel*/) return; data_->num_chars_to_log_ = data_->stream_.pcount(); data_->num_chars_to_syslog_ = data_->num_chars_to_log_ - data_->num_prefix_chars_; bool append_newline = (data_->message_text_[data_->num_chars_to_log_ - 1] != '\n'); char original_final_char = '\0'; if (append_newline) { //original_final_char = data_->message_text_[data_->num_chars_to_log_]; data_->message_text_[data_->num_chars_to_log_++] = '\n'; } /*{ MutexLock l(&log_mutex); (this->*(data_->send_method_))(); ++num_messages_[static_cast<int>(data_->severity_)]; } LogDestination::WaitForSinks(data_);*/ if (append_newline) { data_->message_text_[data_->num_chars_to_log_ - 1] = original_final_char; } cout << data_->message_text_ << endl; data_->has_been_flushed_ = true; } #define LOG(severity) COMPACT_GOOGLE_LOG_ ## severity.stream() #define COMPACT_GOOGLE_LOG_INFO LogMessage( \ __FILE__, __LINE__) class emptyclass { public: emptyclass() {} emptyclass(const char *file, int line) { strcpy(file_, file); line_ = line; } ~emptyclass() { cout << "[" << const_basename(file_) << ":" << line_ << "] " << oststream_.str() << endl; } ostringstream oststream_; char file_[256]; int line_; }; #define TLOG(severity) TLOG_##severity.oststream_ #define TLOG_INFO emptyclass( \ __FILE__, __LINE__) int main(int argc, char *argv[]) { emptyclass();//构造函数将返回一个临时对象,该语句执行完后析构 TLOG(INFO) << "this is a test message:" << 10; int type = 6; LOG(INFO) << "hello world:" << type; getchar(); return 0; }
大致的原理就是通过构造一个临时对象,析构的时候讲ostream中的内容flush到日志文件,emptyclass是类似实现的一个类,主要是觉得glog类似cout一样的写法比较方便。
相关文章推荐
- google glog源码分析
- google PLDA + 实现原理及源码分析
- setDefaultKeyMode(DEFAULT_KEYS_SHORTCUT) 功能的验证 及其 源码实现分析
- 【转】android仿iPhone滚轮控件实现及源码分析(一)
- Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
- 源码分析----ReentrantLock实现和AbstractQueuedSynchronizer
- 蔡军生先生第二人生的源码分析(6)类CallSite的实现
- 蔡军生先生第二人生的源码分析(十七)人物Mesh数据显示的实现
- 第二人生的源码分析(11)地面显示的实现
- Glusterfs之rpc模块源码分析(中)之Glusterfs的rpc模块实现(1)
- Spring Security源码分析四:Spring Social实现微信社交登录
- Spring Security 源码分析(四):Spring Social实现微信社交登录
- Java集合之HashMap源码实现分析
- Android Prelink实现的源码分析
- skynet源码分析【skynet定时器服务的实现】
- 【MyBatis源码分析】插件实现原理
- 第二人生的源码分析(十八)人物纹理显示的实现
- tomcat-jdbc Pool 源码实现简单分析
- Golang日志库源码分析:Glog