error.h 14 KB

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