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 {
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;
pid_t GetTID() {
return GetCurrentThreadId();
}
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) {
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;
}
const char* const_basename(const char* filepath) {
const char* base = strrchr(filepath, '/');
// Look for either path separator in Windows
if (!base)
base = strrchr(filepath, '\\');
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;
}
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_;
};
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一样的写法比较方便。