From 298f1d5569bf2cbc670ce2bb7d0fe0526f30c8e3 Mon Sep 17 00:00:00 2001 From: Vijaymahantesh Sattigeri Date: Thu, 18 Nov 2021 17:58:36 +0530 Subject: [PATCH] Added an API to get GMT offset from LogMessageTime * Added API to get GMT offset * Made LogMessageTime as a memeber of LogMessage * Refactored LogSink::send() method --- AUTHORS | 1 + CONTRIBUTORS | 1 + src/glog/logging.h.in | 77 ++++++++++---------- src/logging.cc | 100 ++++++++++++++------------ src/logging_custom_prefix_unittest.cc | 40 +++++------ src/logging_unittest.cc | 26 ++----- src/mock-log.h | 2 +- 7 files changed, 122 insertions(+), 125 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5a472ad32..2f9ce7436 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,5 +24,6 @@ Roman Perepelitsa Sergiu Deitsch tbennun Teddy Reed +Vijaymahantesh Sattigeri Zhongming Qu Zhuoran Shen diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 1086f1a80..9299b5d28 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -47,5 +47,6 @@ Sergiu Deitsch Shinichiro Hamaji tbennun Teddy Reed +Vijaymahantesh Sattigeri Zhongming Qu Zhuoran Shen diff --git a/src/glog/logging.h.in b/src/glog/logging.h.in index c6762cf96..10bbf6a4b 100644 --- a/src/glog/logging.h.in +++ b/src/glog/logging.h.in @@ -135,30 +135,40 @@ typedef unsigned __int64 uint64; @ac_google_end_namespace@ -#ifdef GLOG_CUSTOM_PREFIX_SUPPORT struct LogMessageTime { - explicit LogMessageTime (const struct::tm& time_struct_, - const time_t& timestamp_, const int32_t& usecs_): - time_struct(time_struct_), ts(timestamp_), usecs(usecs_) {} - - const time_t& timestamp() const { return ts; } - const int& sec() const { return time_struct.tm_sec; } - const int32_t& usec() const { return usecs; } - const int& (min)() const { return time_struct.tm_min; } - const int& hour() const { return time_struct.tm_hour; } - const int& day() const { return time_struct.tm_mday; } - const int& month() const { return time_struct.tm_mon; } - const int& year() const { return time_struct.tm_year; } - const int& dayOfWeek() const { return time_struct.tm_wday; } - const int& dayInYear() const { return time_struct.tm_yday; } - const int& dst() const { return time_struct.tm_isdst; } + LogMessageTime(): time_struct_(), timestamp_(0), usecs_(0), gmtoffset_(0) {} + + void setTimeInfo(struct::tm time_struct, time_t timestamp, int32_t usecs){ + time_struct_ = time_struct; + timestamp_ = timestamp; + usecs_ = usecs; + + CalcGmtOffset(); + } + + const time_t& timestamp() const { return timestamp_; } + const int& sec() const { return time_struct_.tm_sec; } + const int32_t& usec() const { return usecs_; } + const int& (min)() const { return time_struct_.tm_min; } + const int& hour() const { return time_struct_.tm_hour; } + const int& day() const { return time_struct_.tm_mday; } + const int& month() const { return time_struct_.tm_mon; } + const int& year() const { return time_struct_.tm_year; } + const int& dayOfWeek() const { return time_struct_.tm_wday; } + const int& dayInYear() const { return time_struct_.tm_yday; } + const int& dst() const { return time_struct_.tm_isdst; } + const long int& gmtoff() const { return gmtoffset_; } private: - const struct::tm& time_struct; - const time_t& ts; - const int32_t& usecs; + struct::tm time_struct_; // Time of creation of LogMessage + time_t timestamp_; // Time of creation of LogMessage in seconds + int32_t usecs_; // Time of creation of LogMessage - microseconds part + long int gmtoffset_; + + void CalcGmtOffset(); }; +#ifdef GLOG_CUSTOM_PREFIX_SUPPORT struct LogMessageInfo { explicit LogMessageInfo(const char* const severity_, const char* const filename_, @@ -1552,6 +1562,10 @@ public: // Must be called without the log_mutex held. (L < log_mutex) static int64 num_messages(int severity); + const LogMessageTime& getLogMessageTime() const { + return logmsgtime_; + } + struct LogMessageData; private: @@ -1577,6 +1591,7 @@ private: // LogMessage uses less stack space. LogMessageData* allocated_; LogMessageData* data_; + LogMessageTime logmsgtime_; friend class LogDestination; @@ -1721,17 +1736,7 @@ class GOOGLE_GLOG_DLL_DECL LogSink { // during this call. 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, int32 /*usecs*/) { - send(severity, full_filename, base_filename, line, - tm_time, message, message_len); - } - // This send() signature is obsolete. - // New implementations should define this in terms of - // the above send() method. - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct ::tm* tm_time, + const LogMessageTime &logmsgtime, const char* message, size_t message_len) = 0; // Redefine this to implement waiting for @@ -1752,16 +1757,8 @@ class GOOGLE_GLOG_DLL_DECL LogSink { // Returns the normal text output of the log message. // Can be useful to implement send(). static std::string ToString(LogSeverity severity, const char* file, int line, - const struct ::tm* tm_time, - const char* message, size_t message_len, - int32 usecs); - - // Obsolete - static std::string ToString(LogSeverity severity, const char* file, int line, - const struct ::tm* tm_time, - const char* message, size_t message_len) { - return ToString(severity, file, line, tm_time, message, message_len, 0); - } + const LogMessageTime &logmsgtime, + const char* message, size_t message_len); }; // Add or remove a LogSink as a consumer of logging data. Thread-safe. diff --git a/src/logging.cc b/src/logging.cc index 8db32cb6a..57f982a40 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -363,9 +363,6 @@ struct LogMessage::LogMessageData { std::vector* 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 - int32 usecs_; // Time of creation of LogMessage - microseconds part 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 @@ -571,10 +568,9 @@ class LogDestination { const char *full_filename, const char *base_filename, int line, - const struct ::tm* tm_time, + const LogMessageTime &logmsgtime, const char* message, - size_t message_len, - int32 usecs); + size_t message_len); // Wait for all registered sinks via WaitTillSent // including the optional one in "data". @@ -854,15 +850,14 @@ inline void LogDestination::LogToSinks(LogSeverity severity, const char *full_filename, const char *base_filename, int line, - const struct ::tm* tm_time, + const LogMessageTime &logmsgtime, const char* message, - size_t message_len, - int32 usecs) { + size_t message_len) { ReaderMutexLock l(&sink_mutex_); if (sinks_) { for (size_t i = sinks_->size(); i-- > 0; ) { (*sinks_)[i]->send(severity, full_filename, base_filename, - line, tm_time, message, message_len, usecs); + line, logmsgtime, message, message_len); } } } @@ -1608,12 +1603,15 @@ void LogMessage::Init(const char* file, data_->sink_ = NULL; data_->outvec_ = NULL; WallTime now = WallTime_Now(); - data_->timestamp_ = static_cast(now); + time_t timestamp_now = static_cast(now); + std::tm time_struct; if(FLAGS_log_utc_time) - gmtime_r(&data_->timestamp_, &data_->tm_time_); + gmtime_r(×tamp_now, &time_struct); else - localtime_r(&data_->timestamp_, &data_->tm_time_); - data_->usecs_ = static_cast((now - data_->timestamp_) * 1000000); + localtime_r(×tamp_now, &time_struct); + + logmsgtime_.setTimeInfo(time_struct, timestamp_now, + static_cast((now - timestamp_now) * 1000000)); data_->num_chars_to_log_ = 0; data_->num_chars_to_syslog_ = 0; @@ -1633,14 +1631,14 @@ void LogMessage::Init(const char* file, if (custom_prefix_callback == NULL) { #endif stream() << LogSeverityNames[severity][0] - << setw(4) << 1900+data_->tm_time_.tm_year - << setw(2) << 1+data_->tm_time_.tm_mon - << setw(2) << data_->tm_time_.tm_mday + << setw(4) << 1900 + logmsgtime_.year() + << setw(2) << 1 + logmsgtime_.month() + << setw(2) << logmsgtime_.day() << ' ' - << setw(2) << data_->tm_time_.tm_hour << ':' - << setw(2) << data_->tm_time_.tm_min << ':' - << setw(2) << data_->tm_time_.tm_sec << "." - << setw(6) << data_->usecs_ + << setw(2) << logmsgtime_.hour() << ':' + << setw(2) << logmsgtime_.min() << ':' + << setw(2) << logmsgtime_.sec() << "." + << setw(6) << logmsgtime_.usec() << ' ' << setfill(' ') << setw(5) << static_cast(GetTID()) << setfill('0') @@ -1652,9 +1650,7 @@ void LogMessage::Init(const char* file, stream(), LogMessageInfo(LogSeverityNames[severity], data_->basename_, data_->line_, GetTID(), - LogMessageTime(data_->tm_time_, - data_->timestamp_, - data_->usecs_)), + logmsgtime_), custom_prefix_callback_data ); stream() << " "; @@ -1800,15 +1796,14 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) { // this could be protected by a flag if necessary. LogDestination::LogToSinks(data_->severity_, data_->fullname_, data_->basename_, - data_->line_, &data_->tm_time_, + data_->line_, logmsgtime_, data_->message_text_ + data_->num_prefix_chars_, (data_->num_chars_to_log_ - - data_->num_prefix_chars_ - 1), - data_->usecs_); + data_->num_prefix_chars_ - 1) ); } else { // log this message to all log files of severity <= severity_ - LogDestination::LogToAllLogfiles(data_->severity_, data_->timestamp_, + LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(), data_->message_text_, data_->num_chars_to_log_); @@ -1819,11 +1814,10 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) { data_->num_chars_to_log_); LogDestination::LogToSinks(data_->severity_, data_->fullname_, data_->basename_, - data_->line_, &data_->tm_time_, + data_->line_, logmsgtime_, data_->message_text_ + data_->num_prefix_chars_, (data_->num_chars_to_log_ - - data_->num_prefix_chars_ - 1), - data_->usecs_); + - data_->num_prefix_chars_ - 1) ); // NOTE: -1 removes trailing \n } @@ -1842,7 +1836,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) { sizeof(fatal_message)-1); memcpy(fatal_message, data_->message_text_, copy); fatal_message[copy] = '\0'; - fatal_time = data_->timestamp_; + fatal_time = logmsgtime_.timestamp(); } if (!FLAGS_logtostderr) { @@ -1904,11 +1898,10 @@ void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) { RAW_DCHECK(data_->num_chars_to_log_ > 0 && data_->message_text_[data_->num_chars_to_log_-1] == '\n', ""); data_->sink_->send(data_->severity_, data_->fullname_, data_->basename_, - data_->line_, &data_->tm_time_, + data_->line_, logmsgtime_, data_->message_text_ + data_->num_prefix_chars_, (data_->num_chars_to_log_ - - data_->num_prefix_chars_ - 1), - data_->usecs_); + data_->num_prefix_chars_ - 1) ); } } @@ -2034,20 +2027,20 @@ void LogSink::WaitTillSent() { } string LogSink::ToString(LogSeverity severity, const char* file, int line, - const struct ::tm* tm_time, - const char* message, size_t message_len, int32 usecs) { + const LogMessageTime &logmsgtime, + const char* message, size_t message_len) { ostringstream stream(string(message, message_len)); stream.fill('0'); stream << LogSeverityNames[severity][0] - << setw(4) << 1900+tm_time->tm_year - << setw(2) << 1+tm_time->tm_mon - << setw(2) << tm_time->tm_mday + << setw(4) << 1900 + logmsgtime.year() + << setw(2) << 1 + logmsgtime.month() + << setw(2) << logmsgtime.day() << ' ' - << setw(2) << tm_time->tm_hour << ':' - << setw(2) << tm_time->tm_min << ':' - << setw(2) << tm_time->tm_sec << '.' - << setw(6) << usecs + << setw(2) << logmsgtime.hour() << ':' + << setw(2) << logmsgtime.min() << ':' + << setw(2) << logmsgtime.sec() << '.' + << setw(6) << logmsgtime.usec() << ' ' << setfill(' ') << setw(5) << GetTID() << setfill('0') << ' ' @@ -2566,3 +2559,22 @@ void DisableLogCleaner() { } _END_GOOGLE_NAMESPACE_ + +void LogMessageTime::CalcGmtOffset() { + std::tm gmt_struct; + int isDst = 0; + if ( FLAGS_log_utc_time ) { + localtime_r(×tamp_, &gmt_struct); + isDst = gmt_struct.tm_isdst; + gmt_struct = time_struct_; + } else { + isDst = time_struct_.tm_isdst; + gmtime_r(×tamp_, &gmt_struct); + } + + time_t gmt_sec = mktime(&gmt_struct); + const long hour_secs = 3600; + // If the Daylight Saving Time(isDst) is active subtract an hour from the current timestamp. + gmtoffset_ = static_cast(timestamp_ - gmt_sec + (isDst ? hour_secs : 0) ) ; +} + diff --git a/src/logging_custom_prefix_unittest.cc b/src/logging_custom_prefix_unittest.cc index a35fcd34a..ac25f04b0 100644 --- a/src/logging_custom_prefix_unittest.cc +++ b/src/logging_custom_prefix_unittest.cc @@ -526,17 +526,10 @@ class TestLogSinkImpl : public LogSink { vector errors; 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, int usecs) { - errors.push_back( - ToString(severity, base_filename, line, tm_time, message, message_len, usecs)); - } - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, + const LogMessageTime &logmsgtime, const char* message, size_t message_len) { - send(severity, full_filename, base_filename, line, - tm_time, message, message_len, 0); + errors.push_back( + ToString(severity, base_filename, line, logmsgtime, message, message_len)); } }; @@ -1154,24 +1147,17 @@ class TestWaitingLogSink : public 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, int usecs) { + const LogMessageTime &logmsgtime, + const char* message, size_t message_len) { // Push it to Writer thread if we are the original logging thread. // Note: Something like ThreadLocalLogSink is a better choice // to do thread-specific LogSink logic for real. if (pthread_equal(tid_, pthread_self())) { writer_.Buffer(ToString(severity, base_filename, line, - tm_time, message, message_len, usecs)); + logmsgtime, message, message_len)); } } - 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) { - send(severity, full_filename, base_filename, line, tm_time, message, message_len, 0); - } - virtual void WaitTillSent() { // Wait for Writer thread if we are the original logging thread. if (pthread_equal(tid_, pthread_self())) writer_.Wait(); @@ -1379,3 +1365,17 @@ TEST(UserDefinedClass, logging) { // We must be able to compile this. CHECK_EQ(u, u); } + +TEST(LogMsgTime, gmtoff) { + /* + * Unit test for GMT offset API + * TODO: To properly test this API, we need a platform independent way to set time-zone. + * */ + google::LogMessage log_obj(__FILE__, __LINE__); + + long int nGmtOff = log_obj.getLogMessageTime().gmtoff(); + // GMT offset ranges from UTC-12:00 to UTC+14:00 + const long utc_min_offset = -43200; + const long utc_max_offset = 50400; + EXPECT_TRUE( (nGmtOff >= utc_min_offset) && (nGmtOff <= utc_max_offset) ); +} diff --git a/src/logging_unittest.cc b/src/logging_unittest.cc index 0221814d7..08ca4229d 100644 --- a/src/logging_unittest.cc +++ b/src/logging_unittest.cc @@ -521,17 +521,10 @@ class TestLogSinkImpl : public LogSink { vector errors; 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, int usecs) { - errors.push_back( - ToString(severity, base_filename, line, tm_time, message, message_len, usecs)); - } - virtual void send(LogSeverity severity, const char* full_filename, - const char* base_filename, int line, - const struct tm* tm_time, + const LogMessageTime &logmsgtime, const char* message, size_t message_len) { - send(severity, full_filename, base_filename, line, - tm_time, message, message_len, 0); + errors.push_back( + ToString(severity, base_filename, line, logmsgtime, message, message_len)); } }; @@ -1242,24 +1235,17 @@ class TestWaitingLogSink : public 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, int usecs) { + const LogMessageTime &logmsgtime, + const char* message, size_t message_len) { // Push it to Writer thread if we are the original logging thread. // Note: Something like ThreadLocalLogSink is a better choice // to do thread-specific LogSink logic for real. if (pthread_equal(tid_, pthread_self())) { writer_.Buffer(ToString(severity, base_filename, line, - tm_time, message, message_len, usecs)); + logmsgtime, message, message_len)); } } - 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) { - send(severity, full_filename, base_filename, line, tm_time, message, message_len, 0); - } - virtual void WaitTillSent() { // Wait for Writer thread if we are the original logging thread. if (pthread_equal(tid_, pthread_self())) writer_.Wait(); diff --git a/src/mock-log.h b/src/mock-log.h index f172e0cd4..bdfb3c5f1 100644 --- a/src/mock-log.h +++ b/src/mock-log.h @@ -116,7 +116,7 @@ class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink { virtual void send(GOOGLE_NAMESPACE::LogSeverity severity, const char* full_filename, const char* /*base_filename*/, int /*line*/, - const tm* /*tm_time*/, + const LogMessageTime & /*logmsgtime*/, const char* message, size_t message_len) { // We are only interested in the log severity, full file name, and // log message.