| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #pragma once |
| |
|
| | #ifndef DMLC_LOGGING_H_ |
| | #define DMLC_LOGGING_H_ |
| | #include <cstdio> |
| | #include <cstdlib> |
| | #include <memory> |
| | #include <stdexcept> |
| | #include <string> |
| | #include <vector> |
| |
|
| | #if DMLC_LOG_STACK_TRACE |
| | #include <cxxabi.h> |
| |
|
| | #include <sstream> |
| | #include DMLC_EXECINFO_H |
| | #endif |
| |
|
| | |
| | #ifndef DMLC_USE_GLOG |
| | #define DMLC_USE_GLOG 0 |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | #ifndef DMLC_LOG_FATAL_THROW |
| | #define DMLC_LOG_FATAL_THROW 1 |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | #ifndef DMLC_LOG_BEFORE_THROW |
| | #define DMLC_LOG_BEFORE_THROW 0 |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| | #ifndef DMLC_LOG_CUSTOMIZE |
| | #define DMLC_LOG_CUSTOMIZE 0 |
| | #endif |
| |
|
| | |
| | |
| | |
| | #ifndef DMLC_LOG_DEBUG |
| | #ifdef NDEBUG |
| | #define DMLC_LOG_DEBUG 0 |
| | #else |
| | #define DMLC_LOG_DEBUG 1 |
| | #endif |
| | #endif |
| |
|
| | |
| | |
| | |
| | #ifndef DMLC_LOG_NODATE |
| | #define DMLC_LOG_NODATE 0 |
| | #endif |
| |
|
| | |
| | #define DMLC_STR_CONCAT_(__x, __y) __x##__y |
| | #define DMLC_STR_CONCAT(__x, __y) DMLC_STR_CONCAT_(__x, __y) |
| |
|
| | #define DMLC_THROW_EXCEPTION noexcept(false) |
| | #define DMLC_NO_EXCEPTION noexcept(true) |
| |
|
| | #if defined(__GNUC__) || defined(__clang__) |
| | #define DMLC_ALWAYS_INLINE inline __attribute__((__always_inline__)) |
| | #elif defined(_MSC_VER) |
| | #define DMLC_ALWAYS_INLINE __forceinline |
| | #else |
| | #define DMLC_ALWAYS_INLINE inline |
| | #endif |
| |
|
| | #if defined(_MSC_VER) |
| | #define DMLC_NO_INLINE __declspec(noinline) |
| | #else |
| | #define DMLC_NO_INLINE __attribute__((noinline)) |
| | #endif |
| |
|
| | namespace dmlc { |
| | |
| | |
| | |
| | |
| | struct Error : public std::runtime_error { |
| | |
| | |
| | |
| | |
| | explicit Error(const std::string& s) : std::runtime_error(s) {} |
| | }; |
| |
|
| | #if DMLC_LOG_STACK_TRACE |
| | |
| | inline size_t LogStackTraceLevel() { |
| | size_t level; |
| | if (auto var = std::getenv("DMLC_LOG_STACK_TRACE_DEPTH")) { |
| | if (1 == sscanf(var, "%zu", &level)) { |
| | return level + 1; |
| | } |
| | } |
| | return DMLC_LOG_STACK_TRACE_SIZE; |
| | } |
| |
|
| | inline std::string Demangle(char const* msg_str) { |
| | using std::string; |
| | string msg(msg_str); |
| | size_t symbol_start = string::npos; |
| | size_t symbol_end = string::npos; |
| | if (((symbol_start = msg.find("_Z")) != string::npos) && |
| | (symbol_end = msg.find_first_of(" +", symbol_start))) { |
| | string left_of_symbol(msg, 0, symbol_start); |
| | string symbol(msg, symbol_start, symbol_end - symbol_start); |
| | string right_of_symbol(msg, symbol_end); |
| |
|
| | int status = 0; |
| | size_t length = string::npos; |
| | std::unique_ptr<char, void (*)(void* __ptr)> demangled_symbol = { |
| | abi::__cxa_demangle(symbol.c_str(), 0, &length, &status), &std::free}; |
| | if (demangled_symbol && status == 0 && length > 0) { |
| | string symbol_str(demangled_symbol.get()); |
| | std::ostringstream os; |
| | os << left_of_symbol << symbol_str << right_of_symbol; |
| | return os.str(); |
| | } |
| | } |
| | return string(msg_str); |
| | } |
| |
|
| | |
| | |
| | inline std::string StackTrace( |
| | size_t start_frame = 1, |
| | const size_t stack_size = DMLC_LOG_STACK_TRACE_SIZE) { |
| | using std::string; |
| | std::ostringstream stacktrace_os; |
| | std::vector<void*> stack(stack_size); |
| | int nframes = backtrace(stack.data(), static_cast<int>(stack_size)); |
| | if (start_frame < static_cast<size_t>(nframes)) { |
| | stacktrace_os << "Stack trace:\n"; |
| | } |
| | char** msgs = backtrace_symbols(stack.data(), nframes); |
| | if (msgs != nullptr) { |
| | for (int frameno = start_frame; frameno < nframes; ++frameno) { |
| | string msg = dmlc::Demangle(msgs[frameno]); |
| | stacktrace_os << " [bt] (" << frameno - start_frame << ") " << msg |
| | << "\n"; |
| | } |
| | } |
| | free(msgs); |
| | string stack_trace = stacktrace_os.str(); |
| | return stack_trace; |
| | } |
| |
|
| | #else |
| |
|
| | inline size_t LogStackTraceLevel() { |
| | return 0; |
| | } |
| |
|
| | inline std::string demangle(char const* msg_str) { |
| | return std::string(); |
| | } |
| |
|
| | inline std::string StackTrace( |
| | size_t start_frame = 1, |
| | const size_t stack_size = 0) { |
| | return std::string( |
| | "Stack trace not available when " |
| | "DMLC_LOG_STACK_TRACE is disabled at compile time."); |
| | } |
| |
|
| | #endif |
| | } |
| |
|
| | #if DMLC_USE_GLOG |
| | #include <glog/logging.h> |
| |
|
| | namespace dmlc { |
| | |
| | |
| | |
| | |
| | inline void InitLogging(const char* argv0) { |
| | google::InitGoogleLogging(argv0); |
| | } |
| | } |
| |
|
| | #elif defined DMLC_USE_LOGGING_LIBRARY |
| |
|
| | #include DMLC_USE_LOGGING_LIBRARY |
| | namespace dmlc { |
| | inline void InitLogging(const char*) { |
| | |
| | } |
| | } |
| |
|
| | #else |
| | |
| | #include <assert.h> |
| |
|
| | #include <ctime> |
| | #include <iostream> |
| | #include <sstream> |
| |
|
| | #if defined(_MSC_VER) |
| | #pragma warning(disable : 4722) |
| | #pragma warning(disable : 4068) |
| | #endif |
| |
|
| | namespace dmlc { |
| | inline void InitLogging(const char*) { |
| | |
| | } |
| |
|
| | |
| | inline bool DebugLoggingEnabled() { |
| | static int state = 0; |
| | if (state == 0) { |
| | if (auto var = std::getenv("DMLC_LOG_DEBUG")) { |
| | if (std::string(var) == "1") { |
| | state = 1; |
| | } else { |
| | state = -1; |
| | } |
| | } else { |
| | |
| | state = -1; |
| | } |
| | } |
| | return state == 1; |
| | } |
| |
|
| | #ifndef DMLC_GLOG_DEFINED |
| |
|
| | template <typename X, typename Y> |
| | std::unique_ptr<std::string> LogCheckFormat(const X& x, const Y& y) { |
| | std::ostringstream os; |
| | os << " (" << x << " vs. " << y |
| | << ") "; |
| | |
| | |
| | return std::unique_ptr<std::string>(new std::string(os.str())); |
| | } |
| |
|
| | |
| | #define DEFINE_CHECK_FUNC(name, op) \ |
| | template <typename X, typename Y> \ |
| | DMLC_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name( \ |
| | const X& x, const Y& y) { \ |
| | if (x op y) \ |
| | return nullptr; \ |
| | return LogCheckFormat(x, y); \ |
| | } \ |
| | DMLC_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name( \ |
| | int x, int y) { \ |
| | return LogCheck##name<int, int>(x, y); \ |
| | } |
| |
|
| | #pragma GCC diagnostic push |
| | #pragma GCC diagnostic ignored "-Wsign-compare" |
| | DEFINE_CHECK_FUNC(_LT, <) |
| | DEFINE_CHECK_FUNC(_GT, >) |
| | DEFINE_CHECK_FUNC(_LE, <=) |
| | DEFINE_CHECK_FUNC(_GE, >=) |
| | DEFINE_CHECK_FUNC(_EQ, ==) |
| | DEFINE_CHECK_FUNC(_NE, !=) |
| | #pragma GCC diagnostic pop |
| |
|
| | #define CHECK_BINARY_OP(name, op, x, y) \ |
| | if (auto __dmlc__log__err = dmlc::LogCheck##name(x, y)) \ |
| | dmlc::LogMessageFatal(__FILE__, __LINE__).stream() \ |
| | << "Check failed: " << #x " " #op " " #y << *__dmlc__log__err << ": " |
| |
|
| | |
| | #define CHECK(x) \ |
| | if (!(x)) \ |
| | dmlc::LogMessageFatal(__FILE__, __LINE__).stream() \ |
| | << "Check failed: " #x << ": " |
| | #define CHECK_LT(x, y) CHECK_BINARY_OP(_LT, <, x, y) |
| | #define CHECK_GT(x, y) CHECK_BINARY_OP(_GT, >, x, y) |
| | #define CHECK_LE(x, y) CHECK_BINARY_OP(_LE, <=, x, y) |
| | #define CHECK_GE(x, y) CHECK_BINARY_OP(_GE, >=, x, y) |
| | #define CHECK_EQ(x, y) CHECK_BINARY_OP(_EQ, ==, x, y) |
| | #define CHECK_NE(x, y) CHECK_BINARY_OP(_NE, !=, x, y) |
| | #define CHECK_NOTNULL(x) \ |
| | ((x) == NULL ? dmlc::LogMessageFatal(__FILE__, __LINE__).stream() \ |
| | << "Check notnull: " #x << ' ', \ |
| | (x) \ |
| | : (x)) |
| |
|
| | |
| | #if DMLC_LOG_DEBUG |
| | #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 |
| |
|
| | #if DMLC_LOG_CUSTOMIZE |
| | #define LOG_INFO dmlc::CustomLogMessage(__FILE__, __LINE__) |
| | #else |
| | #define LOG_INFO dmlc::LogMessage(__FILE__, __LINE__) |
| | #endif |
| | #define LOG_ERROR LOG_INFO |
| | #define LOG_WARNING LOG_INFO |
| | #define LOG_FATAL dmlc::LogMessageFatal(__FILE__, __LINE__) |
| | #define LOG_QFATAL LOG_FATAL |
| |
|
| | |
| | #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) |
| |
|
| | #if DMLC_LOG_DEBUG |
| |
|
| | #define LOG_DFATAL LOG_FATAL |
| | #define DFATAL FATAL |
| | #define DLOG(severity) LOG_IF(severity, ::dmlc::DebugLoggingEnabled()) |
| | #define DLOG_IF(severity, condition) \ |
| | LOG_IF(severity, ::dmlc::DebugLoggingEnabled() && (condition)) |
| |
|
| | #else |
| |
|
| | #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) |
| | #endif |
| |
|
| | |
| | #define LOG_EVERY_N(severity, n) LOG(severity) |
| |
|
| | #endif |
| |
|
| | class DateLogger { |
| | public: |
| | DateLogger() { |
| | #if defined(_MSC_VER) |
| | _tzset(); |
| | #endif |
| | } |
| | const char* HumanDate() { |
| | #if !defined(_LIBCPP_SGX_CONFIG) && DMLC_LOG_NODATE == 0 |
| | #if defined(_MSC_VER) |
| | _strtime_s(buffer_, sizeof(buffer_)); |
| | #else |
| | time_t time_value = time(NULL); |
| | struct tm* pnow; |
| | #if !defined(_WIN32) |
| | struct tm now; |
| | pnow = localtime_r(&time_value, &now); |
| | #else |
| | pnow = localtime(&time_value); |
| | #endif |
| | snprintf( |
| | buffer_, |
| | sizeof(buffer_), |
| | "%02d:%02d:%02d", |
| | pnow->tm_hour, |
| | pnow->tm_min, |
| | pnow->tm_sec); |
| | #endif |
| | return buffer_; |
| | #else |
| | return ""; |
| | #endif |
| | } |
| |
|
| | private: |
| | char buffer_[9]; |
| | }; |
| |
|
| | #ifndef _LIBCPP_SGX_NO_IOSTREAMS |
| | 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&); |
| | }; |
| |
|
| | |
| | class CustomLogMessage { |
| | public: |
| | CustomLogMessage(const char* file, int line) { |
| | log_stream_ << "[" << DateLogger().HumanDate() << "] " << file << ":" |
| | << line << ": "; |
| | } |
| | ~CustomLogMessage() { |
| | Log(log_stream_.str()); |
| | } |
| | std::ostream& stream() { |
| | return log_stream_; |
| | } |
| | |
| | |
| | |
| | |
| | |
| | static void Log(const std::string& msg); |
| |
|
| | private: |
| | std::ostringstream log_stream_; |
| | }; |
| | #else |
| | class DummyOStream { |
| | public: |
| | template <typename T> |
| | DummyOStream& operator<<(T _) { |
| | return *this; |
| | } |
| | inline std::string str() { |
| | return ""; |
| | } |
| | }; |
| | class LogMessage { |
| | public: |
| | LogMessage(const char* file, int line) : log_stream_() {} |
| | DummyOStream& stream() { |
| | return log_stream_; |
| | } |
| |
|
| | protected: |
| | DummyOStream log_stream_; |
| |
|
| | private: |
| | LogMessage(const LogMessage&); |
| | void operator=(const LogMessage&); |
| | }; |
| | #endif |
| |
|
| | #if defined(_LIBCPP_SGX_NO_IOSTREAMS) |
| | class LogMessageFatal : public LogMessage { |
| | public: |
| | LogMessageFatal(const char* file, int line) : LogMessage(file, line) {} |
| | ~LogMessageFatal() { |
| | abort(); |
| | } |
| |
|
| | private: |
| | LogMessageFatal(const LogMessageFatal&); |
| | void operator=(const LogMessageFatal&); |
| | }; |
| | #elif DMLC_LOG_FATAL_THROW == 0 |
| | class LogMessageFatal : public LogMessage { |
| | public: |
| | LogMessageFatal(const char* file, int line) : LogMessage(file, line) {} |
| | ~LogMessageFatal() { |
| | log_stream_ << "\n" << StackTrace(1, LogStackTraceLevel()) << "\n"; |
| | abort(); |
| | } |
| |
|
| | private: |
| | LogMessageFatal(const LogMessageFatal&); |
| | void operator=(const LogMessageFatal&); |
| | }; |
| | #else |
| | class LogMessageFatal { |
| | public: |
| | LogMessageFatal(const char* file, int line) { |
| | GetEntry().Init(file, line); |
| | } |
| | std::ostringstream& stream() { |
| | return GetEntry().log_stream; |
| | } |
| | DMLC_NO_INLINE ~LogMessageFatal() DMLC_THROW_EXCEPTION { |
| | #if DMLC_LOG_STACK_TRACE |
| | GetEntry().log_stream << "\n" |
| | << StackTrace(1, LogStackTraceLevel()) << "\n"; |
| | #endif |
| | throw GetEntry().Finalize(); |
| | } |
| |
|
| | private: |
| | struct Entry { |
| | std::ostringstream log_stream; |
| | DMLC_NO_INLINE void Init(const char* file, int line) { |
| | DateLogger date; |
| | log_stream.str(""); |
| | log_stream.clear(); |
| | log_stream << "[" << date.HumanDate() << "] " << file << ":" << line |
| | << ": "; |
| | } |
| | dmlc::Error Finalize() { |
| | #if DMLC_LOG_BEFORE_THROW |
| | LOG(ERROR) << log_stream.str(); |
| | #endif |
| | return dmlc::Error(log_stream.str()); |
| | } |
| | |
| | |
| | |
| | #if !(defined(__MINGW32__) || defined(__MINGW64__)) |
| | DMLC_NO_INLINE static Entry& ThreadLocal() { |
| | static thread_local Entry result; |
| | return result; |
| | } |
| | #endif |
| | }; |
| | LogMessageFatal(const LogMessageFatal&); |
| | void operator=(const LogMessageFatal&); |
| |
|
| | #if defined(__MINGW32__) || defined(__MINGW64__) |
| | DMLC_NO_INLINE Entry& GetEntry() { |
| | return entry_; |
| | } |
| |
|
| | Entry entry_; |
| | #else |
| | DMLC_NO_INLINE Entry& GetEntry() { |
| | return Entry::ThreadLocal(); |
| | } |
| | #endif |
| | }; |
| | #endif |
| |
|
| | |
| | |
| | |
| | class LogMessageVoidify { |
| | public: |
| | LogMessageVoidify() {} |
| | |
| | |
| | #if !defined(_LIBCPP_SGX_NO_IOSTREAMS) |
| | void operator&(std::ostream&) {} |
| | #endif |
| | }; |
| |
|
| | } |
| |
|
| | #endif |
| | #endif |
| |
|