1#ifndef C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
2#define C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
3
4#include <chrono>
5#include <climits>
6#include <ctime>
7#include <fstream>
8#include <iomanip>
9#include <map>
10#include <set>
11#include <sstream>
12#include <string>
13#include <vector>
14
15#include <c10/util/Flags.h>
16
17const char CAFFE2_SEVERITY_PREFIX[] = "FEWIV";
18
19namespace c10 {
20
21// Log severity level constants.
22const int GLOG_FATAL = 3;
23const int GLOG_ERROR = 2;
24const int GLOG_WARNING = 1;
25const int GLOG_INFO = 0;
26
27class C10_API MessageLogger {
28 public:
29 MessageLogger(const char* file, int line, int severity);
30 ~MessageLogger();
31 // Return the stream associated with the logger object.
32 std::stringstream& stream() {
33 return stream_;
34 }
35
36 private:
37 // When there is a fatal log, we simply abort.
38 void DealWithFatal() {
39 abort();
40 }
41
42 const char* tag_;
43 std::stringstream stream_;
44 int severity_;
45};
46
47// This class is used to explicitly ignore values in the conditional
48// logging macros. This avoids compiler warnings like "value computed
49// is not used" and "statement has no effect".
50class C10_API LoggerVoidify {
51 public:
52 LoggerVoidify() = default;
53 // This has to be an operator with a precedence lower than << but
54 // higher than ?:
55 void operator&(const std::ostream& s) {}
56};
57
58// Log a message and terminate.
59template <class T>
60void LogMessageFatal(const char* file, int line, const T& message) {
61 MessageLogger(file, line, GLOG_FATAL).stream() << message;
62}
63
64// Helpers for TORCH_CHECK_NOTNULL(). Two are necessary to support both raw
65// pointers and smart pointers.
66template <typename T>
67T& CheckNotNullCommon(const char* file, int line, const char* names, T& t) {
68 if (t == nullptr) {
69 LogMessageFatal(file, line, std::string(names));
70 }
71 return t;
72}
73
74template <typename T>
75T* CheckNotNull(const char* file, int line, const char* names, T* t) {
76 return CheckNotNullCommon(file, line, names, t);
77}
78
79template <typename T>
80T& CheckNotNull(const char* file, int line, const char* names, T& t) {
81 return CheckNotNullCommon(file, line, names, t);
82}
83} // namespace c10
84
85// ---------------------- Logging Macro definitions --------------------------
86
87static_assert(
88 CAFFE2_LOG_THRESHOLD <= ::c10::GLOG_FATAL,
89 "CAFFE2_LOG_THRESHOLD should at most be GLOG_FATAL.");
90// If n is under the compile time caffe log threshold, The _CAFFE_LOG(n)
91// should not generate anything in optimized code.
92#define LOG(n) \
93 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
94 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
95#define VLOG(n) \
96 if (-n >= CAFFE2_LOG_THRESHOLD) \
97 ::c10::MessageLogger(__FILE__, __LINE__, -n).stream()
98
99#define LOG_IF(n, condition) \
100 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD && (condition)) \
101 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
102#define VLOG_IF(n, condition) \
103 if (-n >= CAFFE2_LOG_THRESHOLD && (condition)) \
104 ::c10::MessageLogger(__FILE__, __LINE__, -n).stream()
105
106#define VLOG_IS_ON(verboselevel) (CAFFE2_LOG_THRESHOLD <= -(verboselevel))
107
108// Log with source location information override (to be used in generic
109// warning/error handlers implemented as functions, not macros)
110#define LOG_AT_FILE_LINE(n, file, line) \
111 if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
112 ::c10::MessageLogger(file, line, ::c10::GLOG_##n).stream()
113
114// Log only if condition is met. Otherwise evaluates to void.
115#define FATAL_IF(condition) \
116 condition ? (void)0 \
117 : ::c10::LoggerVoidify() & \
118 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_FATAL).stream()
119
120// Check for a given boolean condition.
121#define CHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
122
123#ifndef NDEBUG
124// Debug only version of CHECK
125#define DCHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
126#define DLOG(severity) LOG(severity)
127#else // NDEBUG
128// Optimized version - generates no code.
129#define DCHECK(condition) \
130 while (false) \
131 CHECK(condition)
132
133#define DLOG(n) \
134 true ? (void)0 \
135 : ::c10::LoggerVoidify() & \
136 ::c10::MessageLogger(__FILE__, __LINE__, ::c10::GLOG_##n).stream()
137#endif // NDEBUG
138
139#define TORCH_CHECK_OP(val1, val2, op) \
140 FATAL_IF(((val1)op(val2))) << "Check failed: " #val1 " " #op " " #val2 " (" \
141 << (val1) << " vs. " << (val2) << ") "
142
143// TORCH_CHECK_OP macro definitions
144#define TORCH_CHECK_EQ(val1, val2) TORCH_CHECK_OP(val1, val2, ==)
145#define TORCH_CHECK_NE(val1, val2) TORCH_CHECK_OP(val1, val2, !=)
146#define TORCH_CHECK_LE(val1, val2) TORCH_CHECK_OP(val1, val2, <=)
147#define TORCH_CHECK_LT(val1, val2) TORCH_CHECK_OP(val1, val2, <)
148#define TORCH_CHECK_GE(val1, val2) TORCH_CHECK_OP(val1, val2, >=)
149#define TORCH_CHECK_GT(val1, val2) TORCH_CHECK_OP(val1, val2, >)
150
151#ifndef NDEBUG
152// Debug only versions of TORCH_CHECK_OP macros.
153#define TORCH_DCHECK_EQ(val1, val2) TORCH_CHECK_OP(val1, val2, ==)
154#define TORCH_DCHECK_NE(val1, val2) TORCH_CHECK_OP(val1, val2, !=)
155#define TORCH_DCHECK_LE(val1, val2) TORCH_CHECK_OP(val1, val2, <=)
156#define TORCH_DCHECK_LT(val1, val2) TORCH_CHECK_OP(val1, val2, <)
157#define TORCH_DCHECK_GE(val1, val2) TORCH_CHECK_OP(val1, val2, >=)
158#define TORCH_DCHECK_GT(val1, val2) TORCH_CHECK_OP(val1, val2, >)
159#else // !NDEBUG
160// These versions generate no code in optimized mode.
161#define TORCH_DCHECK_EQ(val1, val2) \
162 while (false) \
163 TORCH_CHECK_OP(val1, val2, ==)
164#define TORCH_DCHECK_NE(val1, val2) \
165 while (false) \
166 TORCH_CHECK_OP(val1, val2, !=)
167#define TORCH_DCHECK_LE(val1, val2) \
168 while (false) \
169 TORCH_CHECK_OP(val1, val2, <=)
170#define TORCH_DCHECK_LT(val1, val2) \
171 while (false) \
172 TORCH_CHECK_OP(val1, val2, <)
173#define TORCH_DCHECK_GE(val1, val2) \
174 while (false) \
175 TORCH_CHECK_OP(val1, val2, >=)
176#define TORCH_DCHECK_GT(val1, val2) \
177 while (false) \
178 TORCH_CHECK_OP(val1, val2, >)
179#endif // NDEBUG
180
181// Check that a pointer is not null.
182#define TORCH_CHECK_NOTNULL(val) \
183 ::c10::CheckNotNull( \
184 __FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
185
186#ifndef NDEBUG
187// Debug only version of TORCH_CHECK_NOTNULL
188#define TORCH_DCHECK_NOTNULL(val) \
189 ::c10::CheckNotNull( \
190 __FILE__, __LINE__, "Check failed: '" #val "' Must be non NULL", (val))
191#else // !NDEBUG
192// Optimized version - generates no code.
193#define TORCH_DCHECK_NOTNULL(val) \
194 while (false) \
195 TORCH_CHECK_NOTNULL(val)
196#endif // NDEBUG
197
198// ---------------------- Support for std objects --------------------------
199// These are adapted from glog to support a limited set of logging capability
200// for STL objects.
201
202namespace std {
203// Forward declare these two, and define them after all the container streams
204// operators so that we can recurse from pair -> container -> container -> pair
205// properly.
206template <class First, class Second>
207std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
208} // namespace std
209
210namespace c10 {
211template <class Iter>
212void PrintSequence(std::ostream& ss, Iter begin, Iter end);
213} // namespace c10
214
215namespace std {
216#define INSTANTIATE_FOR_CONTAINER(container) \
217 template <class... Types> \
218 std::ostream& operator<<( \
219 std::ostream& out, const container<Types...>& seq) { \
220 c10::PrintSequence(out, seq.begin(), seq.end()); \
221 return out; \
222 }
223
224INSTANTIATE_FOR_CONTAINER(std::vector)
225INSTANTIATE_FOR_CONTAINER(std::map)
226INSTANTIATE_FOR_CONTAINER(std::set)
227#undef INSTANTIATE_FOR_CONTAINER
228
229template <class First, class Second>
230inline std::ostream& operator<<(
231 std::ostream& out,
232 const std::pair<First, Second>& p) {
233 out << '(' << p.first << ", " << p.second << ')';
234 return out;
235}
236
237inline std::ostream& operator<<(std::ostream& out, const std::nullptr_t&) {
238 out << "(null)";
239 return out;
240}
241} // namespace std
242
243namespace c10 {
244template <class Iter>
245inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
246 // Output at most 100 elements -- appropriate if used for logging.
247 for (int i = 0; begin != end && i < 100; ++i, ++begin) {
248 if (i > 0)
249 out << ' ';
250 out << *begin;
251 }
252 if (begin != end) {
253 out << " ...";
254 }
255}
256} // namespace c10
257
258#endif // C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
259