Logging.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. #ifndef C10_UTIL_LOGGING_H_
  2. #define C10_UTIL_LOGGING_H_
  3. #include <climits>
  4. #include <exception>
  5. #include <functional>
  6. #include <limits>
  7. #include <sstream>
  8. #include <c10/macros/Macros.h>
  9. #include <c10/util/Exception.h>
  10. #include <c10/util/Flags.h>
  11. #include <c10/util/StringUtil.h>
  12. // CAFFE2_LOG_THRESHOLD is a compile time flag that would allow us to turn off
  13. // logging at compile time so no logging message below that level is produced
  14. // at all. The value should be between INT_MIN and CAFFE_FATAL.
  15. #ifndef CAFFE2_LOG_THRESHOLD
  16. // If we have not defined the compile time log threshold, we keep all the
  17. // log cases.
  18. #define CAFFE2_LOG_THRESHOLD INT_MIN
  19. #endif // CAFFE2_LOG_THRESHOLD
  20. // Below are different implementations for glog and non-glog cases.
  21. #ifdef C10_USE_GLOG
  22. #include <c10/util/logging_is_google_glog.h>
  23. #else // !C10_USE_GLOG
  24. #include <c10/util/logging_is_not_google_glog.h>
  25. #endif // C10_USE_GLOG
  26. C10_DECLARE_int(caffe2_log_level);
  27. C10_DECLARE_bool(caffe2_use_fatal_for_enforce);
  28. // Some versions of GLOG support less-spammy version of LOG_EVERY_MS. If it's
  29. // not available - just short-circuit to the always working one one.
  30. // We define the C10_ name to avoid confusing other files
  31. #ifdef LOG_EVERY_MS
  32. #define C10_LOG_EVERY_MS(severity, ms) LOG_EVERY_MS(severity, ms)
  33. #else
  34. #define C10_LOG_EVERY_MS(severity, ms) LOG(severity)
  35. #endif
  36. // Same for LOG_FIRST_N
  37. #ifdef LOG_FIRST_N
  38. #define C10_LOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n)
  39. #else
  40. #define C10_LOG_FIRST_N(severity, n) LOG(severity)
  41. #endif
  42. // Same for LOG_EVERY_N
  43. #ifdef LOG_EVERY_N
  44. #define C10_LOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
  45. #else
  46. #define C10_LOG_EVERY_N(severity, n) LOG(severity)
  47. #endif
  48. namespace c10 {
  49. using std::string;
  50. // Functions that we use for initialization.
  51. C10_API bool InitCaffeLogging(int* argc, char** argv);
  52. C10_API void UpdateLoggingLevelsFromFlags();
  53. [[noreturn]] C10_API void ThrowEnforceNotMet(
  54. const char* file,
  55. const int line,
  56. const char* condition,
  57. const std::string& msg,
  58. const void* caller = nullptr);
  59. [[noreturn]] C10_API void ThrowEnforceNotMet(
  60. const char* file,
  61. const int line,
  62. const char* condition,
  63. const char* msg,
  64. const void* caller = nullptr);
  65. [[noreturn]] C10_API inline void ThrowEnforceNotMet(
  66. const char* file,
  67. const int line,
  68. const char* condition,
  69. detail::CompileTimeEmptyString /*msg*/,
  70. const void* caller = nullptr) {
  71. ThrowEnforceNotMet(file, line, condition, "", caller);
  72. }
  73. [[noreturn]] C10_API void ThrowEnforceFiniteNotMet(
  74. const char* file,
  75. const int line,
  76. const char* condition,
  77. const std::string& msg,
  78. const void* caller = nullptr);
  79. [[noreturn]] C10_API void ThrowEnforceFiniteNotMet(
  80. const char* file,
  81. const int line,
  82. const char* condition,
  83. const char* msg,
  84. const void* caller = nullptr);
  85. [[noreturn]] C10_API inline void ThrowEnforceFiniteNotMet(
  86. const char* file,
  87. const int line,
  88. const char* condition,
  89. detail::CompileTimeEmptyString /*msg*/,
  90. const void* caller = nullptr) {
  91. ThrowEnforceFiniteNotMet(file, line, condition, "", caller);
  92. }
  93. constexpr bool IsUsingGoogleLogging() {
  94. #ifdef C10_USE_GLOG
  95. return true;
  96. #else
  97. return false;
  98. #endif
  99. }
  100. /**
  101. * A utility to allow one to show log info to stderr after the program starts.
  102. *
  103. * This is similar to calling GLOG's --logtostderr, or setting caffe2_log_level
  104. * to smaller than INFO. You are recommended to only use this in a few sparse
  105. * cases, such as when you want to write a tutorial or something. Normally, use
  106. * the commandline flags to set the log level.
  107. */
  108. C10_API void ShowLogInfoToStderr();
  109. C10_API void SetStackTraceFetcher(std::function<string(void)> fetcher);
  110. using EnforceNotMet = ::c10::Error;
  111. #define CAFFE_ENFORCE(condition, ...) \
  112. do { \
  113. if (C10_UNLIKELY(!(condition))) { \
  114. ::c10::ThrowEnforceNotMet( \
  115. __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
  116. } \
  117. } while (false)
  118. #define CAFFE_ENFORCE_FINITE(condition, ...) \
  119. do { \
  120. if (C10_UNLIKELY(!(condition))) { \
  121. ::c10::ThrowEnforceFiniteNotMet( \
  122. __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
  123. } \
  124. } while (false)
  125. #define CAFFE_ENFORCE_WITH_CALLER(condition, ...) \
  126. do { \
  127. if (C10_UNLIKELY(!(condition))) { \
  128. ::c10::ThrowEnforceNotMet( \
  129. __FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__), this); \
  130. } \
  131. } while (false)
  132. #define CAFFE_THROW(...) \
  133. ::c10::ThrowEnforceNotMet(__FILE__, __LINE__, "", ::c10::str(__VA_ARGS__))
  134. /**
  135. * Rich logging messages
  136. *
  137. * CAFFE_ENFORCE_THAT can be used with one of the "checker functions" that
  138. * capture input argument values and add it to the exception message. E.g.
  139. * `CAFFE_ENFORCE_THAT(Equals(foo(x), bar(y)), "Optional additional message")`
  140. * would evaluate both foo and bar only once and if the results are not equal -
  141. * include them in the exception message.
  142. *
  143. * Some of the basic checker functions like Equals or Greater are already
  144. * defined below. Other header might define customized checkers by adding
  145. * functions to caffe2::enforce_detail namespace. For example:
  146. *
  147. * namespace caffe2 { namespace enforce_detail {
  148. * inline EnforceFailMessage IsVector(const vector<int64_t>& shape) {
  149. * if (shape.size() == 1) { return EnforceOK(); }
  150. * return c10::str("Shape ", shape, " is not a vector");
  151. * }
  152. * }}
  153. *
  154. * With further usages like `CAFFE_ENFORCE_THAT(IsVector(Input(0).dims()))`
  155. *
  156. * Convenient wrappers for binary operations like CAFFE_ENFORCE_EQ are provided
  157. * too. Please use them instead of TORCH_CHECK_EQ and friends for failures in
  158. * user-provided input.
  159. */
  160. namespace enforce_detail {
  161. template <typename T1, typename T2>
  162. std::string enforceFailMsgImpl(const T1& x, const T2& y) {
  163. return c10::str(x, " vs ", y);
  164. }
  165. template <typename T1, typename T2, typename... Args>
  166. std::string enforceFailMsgImpl(const T1& x, const T2& y, const Args&... args) {
  167. return c10::str(x, " vs ", y, ". ", args...);
  168. }
  169. template <typename Pred, typename T1, typename T2, typename... Args>
  170. void enforceThatImpl(
  171. Pred p,
  172. const T1& lhs,
  173. const T2& rhs,
  174. const char* file,
  175. int line,
  176. const char* expr,
  177. const void* caller,
  178. const Args&... args) {
  179. if (C10_UNLIKELY(!(p(lhs, rhs)))) {
  180. ::c10::ThrowEnforceNotMet(
  181. file,
  182. line,
  183. expr,
  184. ::c10::enforce_detail::enforceFailMsgImpl(lhs, rhs, args...),
  185. caller);
  186. }
  187. }
  188. #define CAFFE_ENFORCE_THAT_IMPL(op, lhs, rhs, expr, ...) \
  189. ::c10::enforce_detail::enforceThatImpl( \
  190. op, lhs, rhs, __FILE__, __LINE__, expr, nullptr, ##__VA_ARGS__)
  191. #define CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(op, lhs, rhs, expr, ...) \
  192. ::c10::enforce_detail::enforceThatImpl( \
  193. op, (lhs), (rhs), __FILE__, __LINE__, expr, this, ##__VA_ARGS__)
  194. } // namespace enforce_detail
  195. #define CAFFE_ENFORCE_THAT(cmp, op, lhs, rhs, ...) \
  196. CAFFE_ENFORCE_THAT_IMPL(cmp, lhs, rhs, #lhs " " #op " " #rhs, ##__VA_ARGS__)
  197. #define CAFFE_ENFORCE_BINARY_OP(cmp, op, x, y, ...) \
  198. CAFFE_ENFORCE_THAT_IMPL(cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__)
  199. #define CAFFE_ENFORCE_EQ(x, y, ...) \
  200. CAFFE_ENFORCE_BINARY_OP(std::equal_to<void>(), ==, x, y, ##__VA_ARGS__)
  201. #define CAFFE_ENFORCE_NE(x, y, ...) \
  202. CAFFE_ENFORCE_BINARY_OP(std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__)
  203. #define CAFFE_ENFORCE_LE(x, y, ...) \
  204. CAFFE_ENFORCE_BINARY_OP(std::less_equal<void>(), <=, x, y, ##__VA_ARGS__)
  205. #define CAFFE_ENFORCE_LT(x, y, ...) \
  206. CAFFE_ENFORCE_BINARY_OP(std::less<void>(), <, x, y, ##__VA_ARGS__)
  207. #define CAFFE_ENFORCE_GE(x, y, ...) \
  208. CAFFE_ENFORCE_BINARY_OP(std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__)
  209. #define CAFFE_ENFORCE_GT(x, y, ...) \
  210. CAFFE_ENFORCE_BINARY_OP(std::greater<void>(), >, x, y, ##__VA_ARGS__)
  211. #define CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(cmp, op, x, y, ...) \
  212. CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
  213. cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__)
  214. #define CAFFE_ENFORCE_EQ_WITH_CALLER(x, y, ...) \
  215. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
  216. std::equal_to<void>(), ==, x, y, ##__VA_ARGS__)
  217. #define CAFFE_ENFORCE_NE_WITH_CALLER(x, y, ...) \
  218. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
  219. std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__)
  220. #define CAFFE_ENFORCE_LE_WITH_CALLER(x, y, ...) \
  221. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
  222. std::less_equal<void>(), <=, x, y, ##__VA_ARGS__)
  223. #define CAFFE_ENFORCE_LT_WITH_CALLER(x, y, ...) \
  224. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(std::less<void>(), <, x, y, ##__VA_ARGS__)
  225. #define CAFFE_ENFORCE_GE_WITH_CALLER(x, y, ...) \
  226. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
  227. std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__)
  228. #define CAFFE_ENFORCE_GT_WITH_CALLER(x, y, ...) \
  229. CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
  230. std::greater<void>(), >, x, y, ##__VA_ARGS__)
  231. /**
  232. * Very lightweight logging for the first time API usage. It's beneficial for
  233. * tracking of individual functionality usage in larger applications.
  234. *
  235. * In order to ensure light-weightedness of logging, we utilize static variable
  236. * trick - LogAPIUsage will be invoked only once and further invocations will
  237. * just do an atomic check.
  238. *
  239. * Example:
  240. * // Logs caller info with an arbitrary text event, if there is a usage.
  241. * C10_LOG_API_USAGE_ONCE("my_api");
  242. */
  243. #define C10_LOG_API_USAGE_ONCE(...) \
  244. C10_UNUSED static bool C10_ANONYMOUS_VARIABLE(logFlag) = \
  245. ::c10::detail::LogAPIUsageFakeReturn(__VA_ARGS__);
  246. // API usage logging capabilities
  247. C10_API void SetAPIUsageLogger(std::function<void(const std::string&)> logger);
  248. C10_API void LogAPIUsage(const std::string& context);
  249. // PyTorch ddp usage logging capabilities
  250. // DDPLoggingData holds data that can be logged in applications
  251. // for analysis and debugging. Data structure is defined in
  252. // c10 directory so that it can be easily imported by both c10
  253. // and torch files.
  254. struct DDPLoggingData {
  255. // logging fields that are string types.
  256. std::map<std::string, std::string> strs_map;
  257. // logging fields that are int64_t types.
  258. std::map<std::string, int64_t> ints_map;
  259. };
  260. C10_API void SetPyTorchDDPUsageLogger(
  261. std::function<void(const DDPLoggingData&)> logger);
  262. C10_API void LogPyTorchDDPUsage(const DDPLoggingData& ddpData);
  263. namespace detail {
  264. // Return value is needed to do the static variable initialization trick
  265. C10_API bool LogAPIUsageFakeReturn(const std::string& context);
  266. } // namespace detail
  267. // Initializes the c10 logger.
  268. C10_API void initLogging();
  269. } // namespace c10
  270. #endif // C10_UTIL_LOGGING_H_