/*! * Copyright (c) 2015 by Contributors * \file logging.h * \brief defines logging macros of dmlc * allows use of GLOG, fall back to internal * implementation when disabled */ #ifndef MSHADOW_LOGGING_H_ #define MSHADOW_LOGGING_H_ #ifndef DMLC_LOGGING_H_ #define DMLC_LOGGING_H_ #include #include #include #include #include #include "./base.h" namespace dmlc { /*! \brief taken from DMLC directly */ /*! * \brief exception class that will be thrown by * default logger if DMLC_LOG_FATAL_THROW == 1 */ struct Error : public std::runtime_error { /*! * \brief constructor * \param s the error message */ explicit Error(const std::string &s) : std::runtime_error(s) {} }; } // namespace dmlc #if defined(_MSC_VER) && _MSC_VER < 1900 #define noexcept(a) #endif #if DMLC_USE_GLOG #include namespace dmlc { /*! \brief taken from DMLC directly */ inline void InitLogging(const char* argv0) { google::InitGoogleLogging(argv0); } } // namespace dmlc #else // use a light version of glog #include #include #include #include #if defined(_MSC_VER) #pragma warning(disable : 4722) #endif namespace dmlc { inline void InitLogging(const char* argv0) { // DO NOTHING } // Always-on checking #define CHECK(x) \ if (!(x)) \ dmlc::LogMessageFatal(__FILE__, __LINE__).stream() << "Check " \ "failed: " #x << ' ' #define CHECK_LT(x, y) CHECK((x) < (y)) #define CHECK_GT(x, y) CHECK((x) > (y)) #define CHECK_LE(x, y) CHECK((x) <= (y)) #define CHECK_GE(x, y) CHECK((x) >= (y)) #define CHECK_EQ(x, y) CHECK((x) == (y)) #define CHECK_NE(x, y) CHECK((x) != (y)) #define CHECK_NOTNULL(x) \ ((x) == NULL ? dmlc::LogMessageFatal(__FILE__, __LINE__).stream() << "Check notnull: " #x << ' ', (x) : (x)) // NOLINT(*) // Debug-only checking. #ifdef NDEBUG #define DCHECK(x) \ while (false) CHECK(x) #define DCHECK_LT(x, y) \ while (false) CHECK((x) < (y)) #define DCHECK_GT(x, y) \ while (false) CHECK((x) > (y)) #define DCHECK_LE(x, y) \ while (false) CHECK((x) <= (y)) #define DCHECK_GE(x, y) \ while (false) CHECK((x) >= (y)) #define DCHECK_EQ(x, y) \ while (false) CHECK((x) == (y)) #define DCHECK_NE(x, y) \ while (false) CHECK((x) != (y)) #else #define DCHECK(x) CHECK(x) #define DCHECK_LT(x, y) CHECK((x) < (y)) #define DCHECK_GT(x, y) CHECK((x) > (y)) #define DCHECK_LE(x, y) CHECK((x) <= (y)) #define DCHECK_GE(x, y) CHECK((x) >= (y)) #define DCHECK_EQ(x, y) CHECK((x) == (y)) #define DCHECK_NE(x, y) CHECK((x) != (y)) #endif // NDEBUG #define LOG_INFO dmlc::LogMessage(__FILE__, __LINE__) #define LOG_ERROR LOG_INFO #define LOG_WARNING LOG_INFO #define LOG_FATAL dmlc::LogMessageFatal(__FILE__, __LINE__) #define LOG_QFATAL LOG_FATAL // Poor man version of VLOG #define VLOG(x) LOG_INFO.stream() #define LOG(severity) LOG_##severity.stream() #define LG LOG_INFO.stream() #define LOG_IF(severity, condition) \ !(condition) ? (void)0 : dmlc::LogMessageVoidify() & LOG(severity) #ifdef NDEBUG #define LOG_DFATAL LOG_ERROR #define DFATAL ERROR #define DLOG(severity) true ? (void)0 : dmlc::LogMessageVoidify() & LOG(severity) #define DLOG_IF(severity, condition) \ (true || !(condition)) ? (void)0 : dmlc::LogMessageVoidify() & LOG(severity) #else #define LOG_DFATAL LOG_FATAL #define DFATAL FATAL #define DLOG(severity) LOG(severity) #define DLOG_IF(severity, condition) LOG_IF(severity, condition) #endif // Poor man version of LOG_EVERY_N #define LOG_EVERY_N(severity, n) LOG(severity) class DateLogger { public: DateLogger() { #if defined(_MSC_VER) _tzset(); #endif } const char* HumanDate() { #if defined(_MSC_VER) _strtime_s(buffer_, sizeof(buffer_)); #else time_t time_value = time(NULL); struct tm now; localtime_r(&time_value, &now); snprintf(buffer_, sizeof(buffer_), "%02d:%02d:%02d", now.tm_hour, now.tm_min, now.tm_sec); #endif return buffer_; } private: char buffer_[9]; }; class LogMessage { public: LogMessage(const char* file, int line) : #ifdef __ANDROID__ log_stream_(std::cout) #else log_stream_(std::cerr) #endif { log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":" << line << ": "; } ~LogMessage() { log_stream_ << "\n"; } std::ostream& stream() { return log_stream_; } protected: std::ostream& log_stream_; private: DateLogger pretty_date_; LogMessage(const LogMessage&); void operator=(const LogMessage&); }; #if DMLC_LOG_FATAL_THROW == 0 class LogMessageFatal : public LogMessage { public: LogMessageFatal(const char* file, int line) : LogMessage(file, line) {} ~LogMessageFatal() { log_stream_ << "\n"; abort(); } private: LogMessageFatal(const LogMessageFatal&); void operator=(const LogMessageFatal&); }; #else class LogMessageFatal { public: LogMessageFatal(const char* file, int line) { log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":" << line << ": "; } std::ostringstream &stream() { return log_stream_; } ~LogMessageFatal() DMLC_THROW_EXCEPTION { // throwing out of destructor is evil // hopefully we can do it here throw Error(log_stream_.str()); } private: std::ostringstream log_stream_; DateLogger pretty_date_; LogMessageFatal(const LogMessageFatal&); void operator=(const LogMessageFatal&); }; #endif // This class is used to explicitly ignore values in the conditional // logging macros. This avoids compiler warnings like "value computed // is not used" and "statement has no effect". class LogMessageVoidify { public: LogMessageVoidify() {} // This has to be an operator with a precedence lower than << but // higher than "?:". See its usage. void operator&(std::ostream&) {} }; } // namespace dmlc #endif #endif // DMLC_LOGGING_H_ #endif // MSHADOW_LOGGING_H_