error.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. #pragma once
  2. #include <library/cpp/yt/error/error_code.h>
  3. #include <library/cpp/yt/threading/public.h>
  4. #include <library/cpp/yt/error/mergeable_dictionary.h>
  5. #include <library/cpp/yt/yson_string/convert.h>
  6. #include <library/cpp/yt/yson_string/string.h>
  7. #include <library/cpp/yt/misc/property.h>
  8. #include <util/system/compiler.h>
  9. #include <util/system/getpid.h>
  10. #include <util/generic/size_literals.h>
  11. #include <type_traits>
  12. namespace NYT {
  13. ////////////////////////////////////////////////////////////////////////////////
  14. //! An opaque wrapper around |int| value capable of conversions from |int|s and
  15. //! arbitrary enum types.
  16. class TErrorCode
  17. {
  18. public:
  19. using TUnderlying = int;
  20. constexpr TErrorCode();
  21. explicit constexpr TErrorCode(int value);
  22. template <class E>
  23. requires std::is_enum_v<E>
  24. constexpr TErrorCode(E value);
  25. constexpr operator int() const;
  26. template <class E>
  27. requires std::is_enum_v<E>
  28. constexpr operator E() const;
  29. template <class E>
  30. requires std::is_enum_v<E>
  31. constexpr bool operator == (E rhs) const;
  32. constexpr bool operator == (TErrorCode rhs) const;
  33. private:
  34. int Value_;
  35. };
  36. ////////////////////////////////////////////////////////////////////////////////
  37. void FormatValue(TStringBuilderBase* builder, TErrorCode code, TStringBuf spec);
  38. ////////////////////////////////////////////////////////////////////////////////
  39. // Forward declaration.
  40. class TErrorException;
  41. template <class TValue>
  42. concept CErrorNestable = requires (TError& error, TValue&& operand)
  43. {
  44. { error <<= std::forward<TValue>(operand) } -> std::same_as<TError&>;
  45. };
  46. template <>
  47. class [[nodiscard]] TErrorOr<void>
  48. {
  49. public:
  50. TErrorOr();
  51. ~TErrorOr();
  52. TErrorOr(const TError& other);
  53. TErrorOr(TError&& other) noexcept;
  54. TErrorOr(const TErrorException& errorEx) noexcept;
  55. TErrorOr(const std::exception& ex);
  56. struct TDisableFormat
  57. { };
  58. static constexpr TDisableFormat DisableFormat = {};
  59. TErrorOr(std::string message, TDisableFormat);
  60. TErrorOr(TErrorCode code, std::string message, TDisableFormat);
  61. template <class... TArgs>
  62. explicit TErrorOr(
  63. TFormatString<TArgs...> format,
  64. TArgs&&... arg);
  65. template <class... TArgs>
  66. TErrorOr(
  67. TErrorCode code,
  68. TFormatString<TArgs...> format,
  69. TArgs&&... args);
  70. TError& operator = (const TError& other);
  71. TError& operator = (TError&& other) noexcept;
  72. static TError FromSystem();
  73. static TError FromSystem(int error);
  74. static TError FromSystem(const TSystemError& error);
  75. TErrorCode GetCode() const;
  76. TError& SetCode(TErrorCode code);
  77. TErrorCode GetNonTrivialCode() const;
  78. THashSet<TErrorCode> GetDistinctNonTrivialErrorCodes() const;
  79. const std::string& GetMessage() const;
  80. TError& SetMessage(std::string message);
  81. bool HasOriginAttributes() const;
  82. TProcessId GetPid() const;
  83. TStringBuf GetThreadName() const;
  84. NThreading::TThreadId GetTid() const;
  85. bool HasDatetime() const;
  86. TInstant GetDatetime() const;
  87. bool HasAttributes() const noexcept;
  88. const TErrorAttributes& Attributes() const;
  89. TErrorAttributes* MutableAttributes();
  90. const std::vector<TError>& InnerErrors() const;
  91. std::vector<TError>* MutableInnerErrors();
  92. // Used for deserialization only.
  93. TOriginAttributes* MutableOriginAttributes() const noexcept;
  94. void UpdateOriginAttributes();
  95. TError Truncate(
  96. int maxInnerErrorCount = 2,
  97. i64 stringLimit = 16_KB,
  98. const THashSet<TStringBuf>& attributeWhitelist = {}) const &;
  99. TError Truncate(
  100. int maxInnerErrorCount = 2,
  101. i64 stringLimit = 16_KB,
  102. const THashSet<TStringBuf>& attributeWhitelist = {}) &&;
  103. bool IsOK() const;
  104. template <class U>
  105. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  106. void ThrowOnError(U&& u) const &;
  107. template <class... TArgs>
  108. void ThrowOnError(TFormatString<TArgs...> format, TArgs&&... args) const &;
  109. template <class... TArgs>
  110. void ThrowOnError(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) const &;
  111. inline void ThrowOnError() const &;
  112. template <class U>
  113. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  114. void ThrowOnError(U&& u) &&;
  115. template <class... TArgs>
  116. void ThrowOnError(TFormatString<TArgs...> format, TArgs&&... args) &&;
  117. template <class... TArgs>
  118. void ThrowOnError(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) &&;
  119. inline void ThrowOnError() &&;
  120. template <CInvocable<bool(const TError&)> TFilter>
  121. std::optional<TError> FindMatching(const TFilter& filter) const;
  122. template <CInvocable<bool(TErrorCode)> TFilter>
  123. std::optional<TError> FindMatching(const TFilter& filter) const;
  124. std::optional<TError> FindMatching(TErrorCode code) const;
  125. std::optional<TError> FindMatching(const THashSet<TErrorCode>& codes) const;
  126. template <class U>
  127. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  128. TError Wrap(U&& u) const &;
  129. template <class... TArgs>
  130. TError Wrap(TFormatString<TArgs...> format, TArgs&&... args) const &;
  131. template <class... TArgs>
  132. TError Wrap(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) const &;
  133. TError Wrap() const &;
  134. template <class U>
  135. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  136. TError Wrap(U&& u) &&;
  137. template <class... TArgs>
  138. TError Wrap(TFormatString<TArgs...> format, TArgs&&... args) &&;
  139. template <class... TArgs>
  140. TError Wrap(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) &&;
  141. TError Wrap() &&;
  142. //! Perform recursive aggregation of error codes and messages over the error tree.
  143. //! Result of this aggregation is suitable for error clustering in groups of
  144. //! "similar" errors. Refer to yt/yt/library/error_skeleton/skeleton_ut.cpp for examples.
  145. //!
  146. //! This method builds skeleton from scratch by doing complete error tree traversal,
  147. //! so calling it in computationally hot code is discouraged.
  148. //!
  149. //! In order to prevent core -> re2 dependency, implementation belongs to a separate library
  150. //! yt/yt/library/error_skeleton. Calling this method without PEERDIR'ing implementation
  151. //! results in an exception.
  152. std::string GetSkeleton() const;
  153. TError& operator <<= (const TErrorAttribute& attribute) &;
  154. TError& operator <<= (const std::vector<TErrorAttribute>& attributes) &;
  155. TError& operator <<= (const TError& innerError) &;
  156. TError& operator <<= (TError&& innerError) &;
  157. TError& operator <<= (const std::vector<TError>& innerErrors) &;
  158. TError& operator <<= (std::vector<TError>&& innerErrors) &;
  159. TError& operator <<= (TAnyMergeableDictionaryRef attributes) &;
  160. template <CErrorNestable TValue>
  161. TError&& operator << (TValue&& operand) &&;
  162. template <CErrorNestable TValue>
  163. TError operator << (TValue&& operand) const &;
  164. template <CErrorNestable TValue>
  165. TError&& operator << (const std::optional<TValue>& rhs) &&;
  166. template <CErrorNestable TValue>
  167. TError operator << (const std::optional<TValue>& rhs) const &;
  168. private:
  169. class TImpl;
  170. std::unique_ptr<TImpl> Impl_;
  171. explicit TErrorOr(std::unique_ptr<TImpl> impl);
  172. void MakeMutable();
  173. friend class TErrorAttributes;
  174. };
  175. ////////////////////////////////////////////////////////////////////////////////
  176. bool operator == (const TError& lhs, const TError& rhs);
  177. ////////////////////////////////////////////////////////////////////////////////
  178. void FormatValue(TStringBuilderBase* builder, const TError& error, TStringBuf spec);
  179. ////////////////////////////////////////////////////////////////////////////////
  180. using TErrorVisitor = std::function<void(const TError&, int depth)>;
  181. //! Traverses the error tree in DFS order.
  182. void TraverseError(
  183. const TError& error,
  184. const TErrorVisitor& visitor,
  185. int depth = 0);
  186. ////////////////////////////////////////////////////////////////////////////////
  187. template <class T>
  188. struct TErrorTraits
  189. {
  190. using TWrapped = TErrorOr<T>;
  191. using TUnwrapped = T;
  192. };
  193. template <class T>
  194. struct TErrorTraits<TErrorOr<T>>
  195. {
  196. using TUnderlying = T;
  197. using TWrapped = TErrorOr<T>;
  198. using TUnwrapped = T;
  199. };
  200. ////////////////////////////////////////////////////////////////////////////////
  201. class TErrorException
  202. : public std::exception
  203. {
  204. public:
  205. DEFINE_BYREF_RW_PROPERTY(TError, Error);
  206. public:
  207. TErrorException() = default;
  208. TErrorException(const TErrorException& other) = default;
  209. TErrorException(TErrorException&& other) = default;
  210. const char* what() const noexcept override;
  211. private:
  212. mutable std::string CachedWhat_;
  213. };
  214. // Make these templates to avoid type erasure during throw.
  215. template <class TException>
  216. requires std::derived_from<std::remove_cvref_t<TException>, TErrorException>
  217. TException&& operator <<= (TException&& ex, const TError& error);
  218. template <class TException>
  219. requires std::derived_from<std::remove_cvref_t<TException>, TErrorException>
  220. TException&& operator <<= (TException&& ex, TError&& error);
  221. ////////////////////////////////////////////////////////////////////////////////
  222. namespace NDetail {
  223. struct TErrorAdaptor
  224. {
  225. template <class TArg>
  226. requires std::constructible_from<TError, TArg>
  227. TError operator << (TArg&& rhs) const;
  228. template <class TArg>
  229. requires
  230. std::constructible_from<TError, TArg> &&
  231. std::derived_from<std::remove_cvref_t<TArg>, TError>
  232. TArg&& operator << (TArg&& rhs) const;
  233. };
  234. // Make these to correctly forward TError to Wrap call.
  235. template <class TErrorLike, class U>
  236. requires
  237. std::derived_from<std::remove_cvref_t<TErrorLike>, TError> &&
  238. (!CStringLiteral<std::remove_cvref_t<U>>)
  239. void ThrowErrorExceptionIfFailed(TErrorLike&& error, U&& u);
  240. template <class TErrorLike, class... TArgs>
  241. requires std::derived_from<std::remove_cvref_t<TErrorLike>, TError>
  242. void ThrowErrorExceptionIfFailed(TErrorLike&& error, TFormatString<TArgs...> format, TArgs&&... args);
  243. template <class TErrorLike, class... TArgs>
  244. requires std::derived_from<std::remove_cvref_t<TErrorLike>, TError>
  245. void ThrowErrorExceptionIfFailed(TErrorLike&& error, TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args);
  246. template <class TErrorLike>
  247. requires std::derived_from<std::remove_cvref_t<TErrorLike>, TError>
  248. void ThrowErrorExceptionIfFailed(TErrorLike&& error);
  249. } // namespace NDetail
  250. ////////////////////////////////////////////////////////////////////////////////
  251. #define THROW_ERROR \
  252. throw ::NYT::TErrorException() <<= ::NYT::NDetail::TErrorAdaptor() <<
  253. #define THROW_ERROR_EXCEPTION(head, ...) \
  254. THROW_ERROR ::NYT::TError(head __VA_OPT__(,) __VA_ARGS__)
  255. // NB: When given an error and a string as arguments, this macro automatically wraps
  256. // new error around the initial one.
  257. #define THROW_ERROR_EXCEPTION_IF_FAILED(error, ...) \
  258. ::NYT::NDetail::ThrowErrorExceptionIfFailed((error) __VA_OPT__(,) __VA_ARGS__); \
  259. #define THROW_ERROR_EXCEPTION_UNLESS(condition, head, ...) \
  260. if ((condition)) {\
  261. } else { \
  262. THROW_ERROR ::NYT::TError(head __VA_OPT__(,) __VA_ARGS__); \
  263. }
  264. #define THROW_ERROR_EXCEPTION_IF(condition, head, ...) \
  265. THROW_ERROR_EXCEPTION_UNLESS(!(condition), head, __VA_ARGS__)
  266. ////////////////////////////////////////////////////////////////////////////////
  267. template <class T>
  268. class [[nodiscard]] TErrorOr
  269. : public TError
  270. {
  271. public:
  272. TErrorOr();
  273. TErrorOr(const T& value);
  274. TErrorOr(T&& value) noexcept;
  275. TErrorOr(const TErrorOr<T>& other);
  276. TErrorOr(TErrorOr<T>&& other) noexcept;
  277. TErrorOr(const TError& other);
  278. TErrorOr(TError&& other) noexcept;
  279. TErrorOr(const TErrorException& errorEx) noexcept;
  280. TErrorOr(const std::exception& ex);
  281. template <class U>
  282. TErrorOr(const TErrorOr<U>& other);
  283. template <class U>
  284. TErrorOr(TErrorOr<U>&& other) noexcept;
  285. TErrorOr<T>& operator = (const TErrorOr<T>& other)
  286. requires std::is_copy_assignable_v<T>;
  287. TErrorOr<T>& operator = (TErrorOr<T>&& other) noexcept
  288. requires std::is_nothrow_move_assignable_v<T>;
  289. const T& Value() const & Y_LIFETIME_BOUND;
  290. T& Value() & Y_LIFETIME_BOUND;
  291. T&& Value() && Y_LIFETIME_BOUND;
  292. template <class U>
  293. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  294. const T& ValueOrThrow(U&& u) const & Y_LIFETIME_BOUND;
  295. template <class... TArgs>
  296. const T& ValueOrThrow(TFormatString<TArgs...> format, TArgs&&... args) const & Y_LIFETIME_BOUND;
  297. template <class... TArgs>
  298. const T& ValueOrThrow(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) const & Y_LIFETIME_BOUND;
  299. const T& ValueOrThrow() const & Y_LIFETIME_BOUND;
  300. template <class U>
  301. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  302. T& ValueOrThrow(U&& u) & Y_LIFETIME_BOUND;
  303. template <class... TArgs>
  304. T& ValueOrThrow(TFormatString<TArgs...> format, TArgs&&... args) & Y_LIFETIME_BOUND;
  305. template <class... TArgs>
  306. T& ValueOrThrow(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) & Y_LIFETIME_BOUND;
  307. T& ValueOrThrow() & Y_LIFETIME_BOUND;
  308. template <class U>
  309. requires (!CStringLiteral<std::remove_cvref_t<U>>)
  310. T&& ValueOrThrow(U&& u) && Y_LIFETIME_BOUND;
  311. template <class... TArgs>
  312. T&& ValueOrThrow(TFormatString<TArgs...> format, TArgs&&... args) && Y_LIFETIME_BOUND;
  313. template <class... TArgs>
  314. T&& ValueOrThrow(TErrorCode code, TFormatString<TArgs...> format, TArgs&&... args) && Y_LIFETIME_BOUND;
  315. T&& ValueOrThrow() && Y_LIFETIME_BOUND;
  316. const T& ValueOrDefault(const T& defaultValue Y_LIFETIME_BOUND) const & Y_LIFETIME_BOUND;
  317. T& ValueOrDefault(T& defaultValue Y_LIFETIME_BOUND) & Y_LIFETIME_BOUND;
  318. constexpr T ValueOrDefault(T&& defaultValue) const &;
  319. constexpr T ValueOrDefault(T&& defaultValue) &&;
  320. private:
  321. std::optional<T> Value_;
  322. };
  323. ////////////////////////////////////////////////////////////////////////////////
  324. template <class T>
  325. void FormatValue(TStringBuilderBase* builder, const TErrorOr<T>& error, TStringBuf spec);
  326. ////////////////////////////////////////////////////////////////////////////////
  327. template <class F, class... As>
  328. auto RunNoExcept(F&& functor, As&&... args) noexcept -> decltype(functor(std::forward<As>(args)...))
  329. {
  330. return functor(std::forward<As>(args)...);
  331. }
  332. ////////////////////////////////////////////////////////////////////////////////
  333. } // namespace NYT
  334. #define STRIPPED_ERROR_INL_H_
  335. #include "error-inl.h"
  336. #undef STRIPPED_ERROR_INL_H_