google开源库glog源码实现分析

来源:互联网 发布:sql的case when 编辑:程序博客网 时间:2024/06/06 01:40
#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_loggingclass GOOGLE_GLOG_DLL_DECL LogStream : public std::ostream {#ifdef _MSC_VER# pragma warning(default: 4275)#endifpublic: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 sendunion {  // At most one of these is used: union to keep the size low.LogSink* sink_;             // NULL or sink to send message tostd::vector<std::string>* outvec_; // NULL or vector to push message ontostd::string* message_;             // NULL or string to write message into};time_t timestamp_;            // Time of creation of LogMessagestruct ::tm tm_time_;         // Time of creation of LogMessagesize_t num_prefix_chars_;     // # of chars of prefix in this messagesize_t num_chars_to_log_;     // # of chars of msg to send to logsize_t num_chars_to_syslog_;  // # of chars of msg to send to syslogconst char* basename_;        // basename of file that called LOGconst char* fullname_;        // fullname of file that called LOGbool has_been_flushed_;       // false => data has not been flushedbool first_fatal_;            // true => this was first fatal msgprivate: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 logsvoid SendToSyslogAndLog() {}  // Actually dispatch to syslog and the logsstatic 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 logsvoid SendToSink() {}  // Send to sink if provided, do nothing otherwise.void WriteToStringAndLog() {}void SaveOrSendToLog() {}  // Save to stringvec if provided, else to logsvoid Init(const char* file, int line, LogSeverity severity,void (LogMessage::*send_method)());//static int64 num_messages_[NUM_SEVERITIES];  // under log_mutexLogMessageData* 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_WINDOWSconst char* const_basename(const char* filepath) {const char* base = strrchr(filepath, '/');#ifdef OS_WINDOWS  // Look for either path separator in Windowsif (!base)base = strrchr(filepath, '\\');#endifreturn 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一样的写法比较方便。


原创粉丝点击