Treelite
logging.h
Go to the documentation of this file.
1 
7 #ifndef TREELITE_LOGGING_H_
8 #define TREELITE_LOGGING_H_
9 
10 #include <treelite/thread_local.h>
11 #include <treelite/error.h>
12 #include <iostream>
13 #include <string>
14 #include <sstream>
15 #include <memory>
16 #include <cstdio>
17 #include <ctime>
18 
19 namespace treelite {
20 
21 template <typename X, typename Y>
22 std::unique_ptr<std::string> LogCheckFormat(const X& x, const Y& y) {
23  std::ostringstream os;
24  os << " (" << x << " vs. " << y << ") ";
25  /* CHECK_XX(x, y) requires x and y can be serialized to string. Use CHECK(x OP y) otherwise. */
26  return std::make_unique<std::string>(os.str());
27 }
28 
29 #if defined(__GNUC__) || defined(__clang__)
30 #define TREELITE_ALWAYS_INLINE inline __attribute__((__always_inline__))
31 #elif defined(_MSC_VER)
32 #define TREELITE_ALWAYS_INLINE __forceinline
33 #else
34 #define TREELITE_ALWAYS_INLINE inline
35 #endif
36 
37 #define DEFINE_CHECK_FUNC(name, op) \
38  template <typename X, typename Y> \
39  TREELITE_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name(const X& x, const Y& y) { \
40  if (x op y) return nullptr; \
41  return LogCheckFormat(x, y); \
42  } \
43  TREELITE_ALWAYS_INLINE std::unique_ptr<std::string> LogCheck##name(int x, int y) { \
44  return LogCheck##name<int, int>(x, y); \
45  }
46 
47 #pragma GCC diagnostic push
48 #pragma GCC diagnostic ignored "-Wsign-compare"
49 DEFINE_CHECK_FUNC(_LT, <)
50 DEFINE_CHECK_FUNC(_GT, >)
51 DEFINE_CHECK_FUNC(_LE, <=)
52 DEFINE_CHECK_FUNC(_GE, >=)
53 DEFINE_CHECK_FUNC(_EQ, ==)
54 DEFINE_CHECK_FUNC(_NE, !=)
55 #pragma GCC diagnostic pop
56 
57 
58 #define TREELITE_CHECK_BINARY_OP(name, op, x, y) \
59  if (auto __treelite__log__err = ::treelite::LogCheck##name(x, y)) \
60  ::treelite::LogMessageFatal(__FILE__, __LINE__).stream() \
61  << "Check failed: " << #x " " #op " " #y << *__treelite__log__err << ": "
62 #define TREELITE_CHECK(x) \
63  if (!(x)) \
64  ::treelite::LogMessageFatal(__FILE__, __LINE__).stream() \
65  << "Check failed: " #x << ": "
66 #define TREELITE_CHECK_LT(x, y) TREELITE_CHECK_BINARY_OP(_LT, <, x, y)
67 #define TREELITE_CHECK_GT(x, y) TREELITE_CHECK_BINARY_OP(_GT, >, x, y)
68 #define TREELITE_CHECK_LE(x, y) TREELITE_CHECK_BINARY_OP(_LE, <=, x, y)
69 #define TREELITE_CHECK_GE(x, y) TREELITE_CHECK_BINARY_OP(_GE, >=, x, y)
70 #define TREELITE_CHECK_EQ(x, y) TREELITE_CHECK_BINARY_OP(_EQ, ==, x, y)
71 #define TREELITE_CHECK_NE(x, y) TREELITE_CHECK_BINARY_OP(_NE, !=, x, y)
72 
73 #define TREELITE_LOG_INFO ::treelite::LogMessage(__FILE__, __LINE__)
74 #define TREELITE_LOG_ERROR TREELITE_LOG_INFO
75 #define TREELITE_LOG_FATAL ::treelite::LogMessageFatal(__FILE__, __LINE__)
76 #define TREELITE_LOG(severity) TREELITE_LOG_##severity.stream()
77 
78 class DateLogger {
79  public:
80  DateLogger() {
81 #if defined(_MSC_VER)
82  _tzset();
83 #endif // defined(_MSC_VER)
84  }
85  const char* HumanDate() {
86 #if defined(_MSC_VER)
87  _strtime_s(buffer_, sizeof(buffer_));
88 #else // defined(_MSC_VER)
89  time_t time_value = std::time(nullptr);
90  struct tm* pnow;
91 #if !defined(_WIN32)
92  struct tm now;
93  pnow = localtime_r(&time_value, &now);
94 #else // !defined(_WIN32)
95  pnow = std::localtime(&time_value); // NOLINT(*)
96 #endif // !defined(_WIN32)
97  std::snprintf(buffer_, sizeof(buffer_), "%02d:%02d:%02d",
98  pnow->tm_hour, pnow->tm_min, pnow->tm_sec);
99 #endif // defined(_MSC_VER)
100  return buffer_;
101  }
102 
103  private:
104  char buffer_[9];
105 };
106 
108  public:
109  LogMessageFatal(const char* file, int line) {
110  log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":" << line << ": ";
111  }
112  LogMessageFatal(const LogMessageFatal&) = delete;
113  void operator=(const LogMessageFatal&) = delete;
114 
115  std::ostringstream& stream() {
116  return log_stream_;
117  }
118  ~LogMessageFatal() noexcept(false) {
119  throw Error(log_stream_.str());
120  }
121 
122  private:
123  std::ostringstream log_stream_;
124  DateLogger pretty_date_;
125 };
126 
127 class LogMessage {
128  public:
129  LogMessage(const char* file, int line) {
130  log_stream_ << "[" << DateLogger().HumanDate() << "] " << file << ":"
131  << line << ": ";
132  }
133  ~LogMessage() {
134  Log(log_stream_.str());
135  }
136  std::ostream& stream() { return log_stream_; }
137  static void Log(const std::string& msg);
138 
139  private:
140  std::ostringstream log_stream_;
141 };
142 
144  public:
145  using Callback = void (*)(const char*);
147  : log_callback_([] (const char* msg) { std::cerr << msg << std::endl; }) {}
148  inline void Register(Callback log_callback) {
149  this->log_callback_ = log_callback;
150  }
151  inline Callback Get() const {
152  return log_callback_;
153  }
154  private:
155  Callback log_callback_;
156 };
157 
159 
160 } // namespace treelite
161 
162 #endif // TREELITE_LOGGING_H_
Exception class that will be thrown by Treelite.
Definition: error.h:18
Exception class used throughout the Treelite codebase.
Helper class for thread-local storage.
A thread-local storage.
Definition: thread_local.h:17