Logging.h 14 KB

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