269 lines
6.7 KiB
C++
269 lines
6.7 KiB
C++
/*!
|
|
* 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 DMLC_LOGGING_H_
|
|
#define DMLC_LOGGING_H_
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <stdexcept>
|
|
#include "./base.h"
|
|
|
|
namespace dmlc {
|
|
/*!
|
|
* \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_CXX11
|
|
#define DMLC_THROW_EXCEPTION noexcept(false)
|
|
#else
|
|
#define DMLC_THROW_EXCEPTION
|
|
#endif
|
|
|
|
#if DMLC_USE_GLOG
|
|
#include <glog/logging.h>
|
|
|
|
namespace dmlc {
|
|
inline void InitLogging(const char* argv0) {
|
|
google::InitGoogleLogging(argv0);
|
|
}
|
|
} // namespace dmlc
|
|
|
|
#else
|
|
// use a light version of glog
|
|
#include <assert.h>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <ctime>
|
|
|
|
#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
|
|
|
|
#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
|
|
|
|
// 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 *pnow;
|
|
#if !defined(_WIN32)
|
|
struct tm now;
|
|
pnow = localtime_r(&time_value, &now);
|
|
#else
|
|
pnow = localtime(&time_value); // NOLINT(*)
|
|
#endif
|
|
snprintf(buffer_, sizeof(buffer_), "%02d:%02d:%02d",
|
|
pnow->tm_hour, pnow->tm_min, pnow->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&);
|
|
};
|
|
|
|
// customized logger that can allow user to define where to log the message.
|
|
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_; }
|
|
/*!
|
|
* \brief customized logging of the message.
|
|
* This function won't be implemented by libdmlc
|
|
* \param msg The message to be logged.
|
|
*/
|
|
static void Log(const std::string& msg);
|
|
|
|
private:
|
|
std::ostringstream log_stream_;
|
|
};
|
|
|
|
#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
|
|
// also log the message before throw
|
|
#if DMLC_LOG_BEFORE_THROW
|
|
LOG(ERROR) << log_stream_.str();
|
|
#endif
|
|
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_
|