#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一样的写法比较方便。