error.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396
  1. #include "error.h"
  2. #include "serialize.h"
  3. #include <yt/yt/core/concurrency/scheduler.h>
  4. #include <yt/yt_proto/yt/core/misc/proto/error.pb.h>
  5. #include <yt/yt/core/actions/callback.h>
  6. #include <yt/yt/core/misc/protobuf_helpers.h>
  7. #include <yt/yt/core/misc/string_helpers.h>
  8. #include <yt/yt/core/misc/proc.h>
  9. #include <yt/yt/core/net/local_address.h>
  10. #include <yt/yt/core/tracing/trace_context.h>
  11. #include <yt/yt/core/yson/tokenizer.h>
  12. #include <yt/yt/core/ytree/attributes.h>
  13. #include <yt/yt/core/ytree/convert.h>
  14. #include <yt/yt/core/ytree/fluent.h>
  15. #include <yt/yt/core/net/address.h>
  16. #include <library/cpp/yt/exception/exception.h>
  17. #include <library/cpp/yt/misc/thread_name.h>
  18. #include <library/cpp/yt/misc/tls.h>
  19. #include <util/string/subst.h>
  20. #include <util/system/error.h>
  21. #include <util/system/thread.h>
  22. namespace NYT {
  23. using namespace NYTree;
  24. using namespace NYson;
  25. using NYT::FromProto;
  26. using NYT::ToProto;
  27. ////////////////////////////////////////////////////////////////////////////////
  28. constexpr TStringBuf OriginalErrorDepthAttribute = "original_error_depth";
  29. constexpr TStringBuf ErrorMessageTruncatedSuffix = "...<message truncated>";
  30. ////////////////////////////////////////////////////////////////////////////////
  31. void TErrorCode::Save(TStreamSaveContext& context) const
  32. {
  33. NYT::Save(context, Value_);
  34. }
  35. void TErrorCode::Load(TStreamLoadContext& context)
  36. {
  37. NYT::Load(context, Value_);
  38. }
  39. void FormatValue(TStringBuilderBase* builder, TErrorCode code, TStringBuf spec)
  40. {
  41. FormatValue(builder, static_cast<int>(code), spec);
  42. }
  43. TString ToString(TErrorCode code)
  44. {
  45. return ToStringViaBuilder(code);
  46. }
  47. ////////////////////////////////////////////////////////////////////////////////
  48. YT_THREAD_LOCAL(bool) ErrorSanitizerEnabled = false;
  49. YT_THREAD_LOCAL(TInstant) ErrorSanitizerDatetimeOverride = {};
  50. YT_THREAD_LOCAL(TSharedRef) ErrorSanitizerLocalHostNameOverride = {};
  51. TErrorSanitizerGuard::TErrorSanitizerGuard(TInstant datetimeOverride, TSharedRef localHostNameOverride)
  52. : SavedEnabled_(ErrorSanitizerEnabled)
  53. , SavedDatetimeOverride_(GetTlsRef(ErrorSanitizerDatetimeOverride))
  54. , SavedLocalHostNameOverride_(GetTlsRef(ErrorSanitizerLocalHostNameOverride))
  55. {
  56. ErrorSanitizerEnabled = true;
  57. GetTlsRef(ErrorSanitizerDatetimeOverride) = datetimeOverride;
  58. GetTlsRef(ErrorSanitizerLocalHostNameOverride) = std::move(localHostNameOverride);
  59. }
  60. TErrorSanitizerGuard::~TErrorSanitizerGuard()
  61. {
  62. YT_ASSERT(ErrorSanitizerEnabled);
  63. ErrorSanitizerEnabled = SavedEnabled_;
  64. GetTlsRef(ErrorSanitizerDatetimeOverride) = SavedDatetimeOverride_;
  65. GetTlsRef(ErrorSanitizerLocalHostNameOverride) = std::move(SavedLocalHostNameOverride_);
  66. }
  67. ////////////////////////////////////////////////////////////////////////////////
  68. class TError::TImpl
  69. {
  70. public:
  71. TImpl()
  72. : Code_(NYT::EErrorCode::OK)
  73. { }
  74. TImpl(const TError::TImpl& other)
  75. : Code_(other.Code_)
  76. , Message_(other.Message_)
  77. , Host_(other.Host_)
  78. , HostHolder_(other.HostHolder_)
  79. , Datetime_(other.Datetime_)
  80. , Pid_(other.Pid_)
  81. , Tid_(other.Tid_)
  82. , ThreadName_(other.ThreadName_)
  83. , Fid_(other.Fid_)
  84. , TraceId_(other.TraceId_)
  85. , SpanId_(other.SpanId_)
  86. , Attributes_(other.Attributes_ ? other.Attributes_->Clone() : nullptr)
  87. , InnerErrors_(other.InnerErrors_)
  88. { }
  89. explicit TImpl(TString message)
  90. : Code_(NYT::EErrorCode::Generic)
  91. , Message_(std::move(message))
  92. {
  93. CaptureOriginAttributes();
  94. }
  95. TImpl(TErrorCode code, TString message)
  96. : Code_(code)
  97. , Message_(std::move(message))
  98. {
  99. if (!IsOK()) {
  100. CaptureOriginAttributes();
  101. }
  102. }
  103. TErrorCode GetCode() const
  104. {
  105. return Code_;
  106. }
  107. void SetCode(TErrorCode code)
  108. {
  109. Code_ = code;
  110. }
  111. const TString& GetMessage() const
  112. {
  113. return Message_;
  114. }
  115. void SetMessage(TString message)
  116. {
  117. Message_ = std::move(message);
  118. }
  119. TString* MutableMessage()
  120. {
  121. return &Message_;
  122. }
  123. bool HasHost() const
  124. {
  125. return Host_.operator bool();
  126. }
  127. TStringBuf GetHost() const
  128. {
  129. return Host_;
  130. }
  131. bool HasOriginAttributes() const
  132. {
  133. return ThreadName_.Length > 0;
  134. }
  135. bool HasDatetime() const
  136. {
  137. return Datetime_ != TInstant();
  138. }
  139. TInstant GetDatetime() const
  140. {
  141. return Datetime_;
  142. }
  143. void SetDatetime(TInstant datetime)
  144. {
  145. Datetime_ = datetime;
  146. }
  147. TProcessId GetPid() const
  148. {
  149. return Pid_;
  150. }
  151. NThreading::TThreadId GetTid() const
  152. {
  153. return Tid_;
  154. }
  155. TStringBuf GetThreadName() const
  156. {
  157. return ThreadName_.ToStringBuf();
  158. }
  159. NConcurrency::TFiberId GetFid() const
  160. {
  161. return Fid_;
  162. }
  163. bool HasTracingAttributes() const
  164. {
  165. return TraceId_ != NTracing::InvalidTraceId;
  166. }
  167. NTracing::TTraceId GetTraceId() const
  168. {
  169. return TraceId_;
  170. }
  171. NTracing::TSpanId GetSpanId() const
  172. {
  173. return SpanId_;
  174. }
  175. const IAttributeDictionary& Attributes() const
  176. {
  177. if (!Attributes_) {
  178. return EmptyAttributes();
  179. }
  180. return *Attributes_;
  181. }
  182. IAttributeDictionary* MutableAttributes()
  183. {
  184. if (!Attributes_) {
  185. Attributes_ = CreateEphemeralAttributes();
  186. }
  187. return Attributes_.Get();
  188. }
  189. bool HasAttributes() const
  190. {
  191. return Attributes_.operator bool();
  192. }
  193. void SetAttributes(NYTree::IAttributeDictionaryPtr attributes)
  194. {
  195. Attributes_ = std::move(attributes);
  196. ExtractSystemAttributes();
  197. }
  198. const std::vector<TError>& InnerErrors() const
  199. {
  200. return InnerErrors_;
  201. }
  202. std::vector<TError>* MutableInnerErrors()
  203. {
  204. return &InnerErrors_;
  205. }
  206. bool IsOK() const
  207. {
  208. return Code_ == NYT::EErrorCode::OK;
  209. }
  210. void CopyBuiltinAttributesFrom(const TError::TImpl& other)
  211. {
  212. Host_ = other.Host_;
  213. HostHolder_ = other.HostHolder_;
  214. Datetime_ = other.Datetime_;
  215. Pid_ = other.Pid_;
  216. Tid_ = other.Tid_;
  217. ThreadName_ = other.ThreadName_;
  218. Fid_ = other.Fid_;
  219. TraceId_ = other.TraceId_;
  220. SpanId_ = other.SpanId_;
  221. }
  222. private:
  223. TErrorCode Code_;
  224. TString Message_;
  225. // Most errors are local; for these Host_ refers to a static buffer and HostHolder_ is not used.
  226. // This saves one allocation on TError construction.
  227. TStringBuf Host_;
  228. // HostHolder_ optionally stores data of Host_, and this pointer connection survives move of containing object.
  229. TSharedRef HostHolder_;
  230. TInstant Datetime_;
  231. TProcessId Pid_ = 0;
  232. NThreading::TThreadId Tid_ = NThreading::InvalidThreadId;
  233. TThreadName ThreadName_;
  234. NConcurrency::TFiberId Fid_ = NConcurrency::InvalidFiberId;
  235. NTracing::TTraceId TraceId_ = NTracing::InvalidTraceId;
  236. NTracing::TSpanId SpanId_ = NTracing::InvalidSpanId;
  237. NYTree::IAttributeDictionaryPtr Attributes_;
  238. std::vector<TError> InnerErrors_;
  239. void CaptureOriginAttributes()
  240. {
  241. if (ErrorSanitizerEnabled) {
  242. Datetime_ = GetTlsRef(ErrorSanitizerDatetimeOverride);
  243. HostHolder_ = GetTlsRef(ErrorSanitizerLocalHostNameOverride);
  244. Host_ = HostHolder_.empty() ? TStringBuf() : TStringBuf(HostHolder_.Begin(), HostHolder_.End());
  245. return;
  246. }
  247. Host_ = NNet::ReadLocalHostName();
  248. Datetime_ = TInstant::Now();
  249. Pid_ = GetPID();
  250. Tid_ = TThread::CurrentThreadId();
  251. ThreadName_ = GetCurrentThreadName();
  252. Fid_ = NConcurrency::GetCurrentFiberId();
  253. if (const auto* traceContext = NTracing::TryGetCurrentTraceContext()) {
  254. TraceId_ = traceContext->GetTraceId();
  255. SpanId_ = traceContext->GetSpanId();
  256. }
  257. }
  258. void ExtractSystemAttributes()
  259. {
  260. if (!Attributes_) {
  261. return;
  262. }
  263. static const TString HostKey("host");
  264. HostHolder_ = TSharedRef::FromString(Attributes_->GetAndRemove<TString>(HostKey, TString()));
  265. Host_ = HostHolder_.empty() ? TStringBuf() : TStringBuf(HostHolder_.Begin(), HostHolder_.End());
  266. static const TString DatetimeKey("datetime");
  267. Datetime_ = Attributes_->GetAndRemove<TInstant>(DatetimeKey, TInstant());
  268. static const TString PidKey("pid");
  269. Pid_ = Attributes_->GetAndRemove<TProcessId>(PidKey, 0);
  270. static const TString TidKey("tid");
  271. Tid_ = Attributes_->GetAndRemove<NThreading::TThreadId>(TidKey, NThreading::InvalidThreadId);
  272. static const TString ThreadNameKey("thread");
  273. ThreadName_ = Attributes_->GetAndRemove<TString>(ThreadNameKey, TString());
  274. static const TString FidKey("fid");
  275. Fid_ = Attributes_->GetAndRemove<NConcurrency::TFiberId>(FidKey, NConcurrency::InvalidFiberId);
  276. static const TString TraceIdKey("trace_id");
  277. TraceId_ = Attributes_->GetAndRemove<NTracing::TTraceId>(TraceIdKey, NTracing::InvalidTraceId);
  278. static const TString SpanIdKey("span_id");
  279. SpanId_ = Attributes_->GetAndRemove<NTracing::TSpanId>(SpanIdKey, NTracing::InvalidSpanId);
  280. }
  281. };
  282. ////////////////////////////////////////////////////////////////////////////////
  283. namespace {
  284. bool IsWhitelisted(const TError& error, const THashSet<TStringBuf>& attributeWhitelist)
  285. {
  286. for (const auto& key : error.Attributes().ListKeys()) {
  287. if (attributeWhitelist.contains(key)) {
  288. return true;
  289. }
  290. }
  291. for (const auto& innerError : error.InnerErrors()) {
  292. if (IsWhitelisted(innerError, attributeWhitelist)) {
  293. return true;
  294. }
  295. }
  296. return false;
  297. }
  298. //! Returns vector which consists of objects from errors such that:
  299. //! if N is the number of objects in errors s.t. IsWhitelisted is true
  300. //! then first N objects of returned vector are the ones for which IsWhitelisted is true
  301. //! followed by std::max(0, maxInnerErrorCount - N - 1) remaining objects
  302. //! finally followed by errors.back().
  303. std::vector<TError>& ApplyWhitelist(std::vector<TError>& errors, const THashSet<TStringBuf>& attributeWhitelist, int maxInnerErrorCount)
  304. {
  305. if (std::ssize(errors) < std::max(2, maxInnerErrorCount)) {
  306. return errors;
  307. }
  308. auto firstNotWhitelisted = std::partition(
  309. errors.begin(),
  310. std::prev(errors.end()),
  311. [&attributeWhitelist] (const TError& error) {
  312. return IsWhitelisted(error, attributeWhitelist);
  313. });
  314. int lastErrorOffset = std::max<int>(firstNotWhitelisted - errors.begin(), maxInnerErrorCount - 1);
  315. *(errors.begin() + lastErrorOffset) = std::move(errors.back());
  316. errors.resize(lastErrorOffset + 1);
  317. return errors;
  318. }
  319. } // namespace
  320. ////////////////////////////////////////////////////////////////////////////////
  321. TError::TErrorOr() = default;
  322. TError::~TErrorOr() = default;
  323. TError::TErrorOr(const TError& other)
  324. {
  325. if (!other.IsOK()) {
  326. Impl_ = std::make_unique<TImpl>(*other.Impl_);
  327. }
  328. }
  329. TError::TErrorOr(TError&& other) noexcept
  330. : Impl_(std::move(other.Impl_))
  331. { }
  332. TError::TErrorOr(const std::exception& ex)
  333. {
  334. if (auto simpleException = dynamic_cast<const TSimpleException*>(&ex)) {
  335. *this = TError(NYT::EErrorCode::Generic, simpleException->GetMessage());
  336. // NB: clang-14 is incapable of capturing structured binding variables
  337. // so we force materialize them via this function call.
  338. auto addAttribute = [this] (const auto& key, const auto& value) {
  339. std::visit([&] (const auto& actual) {
  340. *this <<= TErrorAttribute(key, actual);
  341. }, value);
  342. };
  343. for (const auto& [key, value] : simpleException->GetAttributes()) {
  344. addAttribute(key, value);
  345. }
  346. try {
  347. if (simpleException->GetInnerException()) {
  348. std::rethrow_exception(simpleException->GetInnerException());
  349. }
  350. } catch (const std::exception& innerEx) {
  351. *this <<= TError(innerEx);
  352. }
  353. } else if (const auto* errorEx = dynamic_cast<const TErrorException*>(&ex)) {
  354. *this = errorEx->Error();
  355. } else {
  356. *this = TError(NYT::EErrorCode::Generic, ex.what());
  357. }
  358. YT_VERIFY(!IsOK());
  359. }
  360. TError::TErrorOr(TString message)
  361. : Impl_(std::make_unique<TImpl>(std::move(message)))
  362. { }
  363. TError::TErrorOr(TErrorCode code, TString message)
  364. : Impl_(std::make_unique<TImpl>(code, std::move(message)))
  365. { }
  366. TError& TError::operator = (const TError& other)
  367. {
  368. if (other.IsOK()) {
  369. Impl_.reset();
  370. } else {
  371. Impl_ = std::make_unique<TImpl>(*other.Impl_);
  372. }
  373. return *this;
  374. }
  375. TError& TError::operator = (TError&& other) noexcept
  376. {
  377. Impl_ = std::move(other.Impl_);
  378. return *this;
  379. }
  380. TError TError::FromSystem()
  381. {
  382. return FromSystem(LastSystemError());
  383. }
  384. TError TError::FromSystem(int error)
  385. {
  386. return TError(TErrorCode(LinuxErrorCodeBase + error), LastSystemErrorText(error)) <<
  387. TErrorAttribute("errno", error);
  388. }
  389. TError TError::FromSystem(const TSystemError& error)
  390. {
  391. return FromSystem(error.Status());
  392. }
  393. TErrorCode TError::GetCode() const
  394. {
  395. if (!Impl_) {
  396. return NYT::EErrorCode::OK;
  397. }
  398. return Impl_->GetCode();
  399. }
  400. TError& TError::SetCode(TErrorCode code)
  401. {
  402. MakeMutable();
  403. Impl_->SetCode(code);
  404. return *this;
  405. }
  406. TErrorCode TError::GetNonTrivialCode() const
  407. {
  408. if (!Impl_) {
  409. return NYT::EErrorCode::OK;
  410. }
  411. if (GetCode() != NYT::EErrorCode::Generic) {
  412. return GetCode();
  413. }
  414. for (const auto& innerError : InnerErrors()) {
  415. auto innerCode = innerError.GetNonTrivialCode();
  416. if (innerCode != NYT::EErrorCode::Generic) {
  417. return innerCode;
  418. }
  419. }
  420. return GetCode();
  421. }
  422. THashSet<TErrorCode> TError::GetDistinctNonTrivialErrorCodes() const
  423. {
  424. THashSet<TErrorCode> result;
  425. TraverseError(*this, [&result] (const TError& error, int /*depth*/) {
  426. if (auto errorCode = error.GetCode(); errorCode != NYT::EErrorCode::OK) {
  427. result.insert(errorCode);
  428. }
  429. });
  430. return result;
  431. }
  432. const TString& TError::GetMessage() const
  433. {
  434. if (!Impl_) {
  435. static const TString Result;
  436. return Result;
  437. }
  438. return Impl_->GetMessage();
  439. }
  440. TError& TError::SetMessage(TString message)
  441. {
  442. MakeMutable();
  443. Impl_->SetMessage(std::move(message));
  444. return *this;
  445. }
  446. bool TError::HasHost() const
  447. {
  448. if (!Impl_) {
  449. return false;
  450. }
  451. return Impl_->HasHost();
  452. }
  453. TStringBuf TError::GetHost() const
  454. {
  455. if (!Impl_) {
  456. return {};
  457. }
  458. return Impl_->GetHost();
  459. }
  460. bool TError::HasOriginAttributes() const
  461. {
  462. if (!Impl_) {
  463. return false;
  464. }
  465. return Impl_->HasOriginAttributes();
  466. }
  467. bool TError::HasDatetime() const
  468. {
  469. if (!Impl_) {
  470. return false;
  471. }
  472. return Impl_->HasDatetime();
  473. }
  474. TInstant TError::GetDatetime() const
  475. {
  476. if (!Impl_) {
  477. return {};
  478. }
  479. return Impl_->GetDatetime();
  480. }
  481. TProcessId TError::GetPid() const
  482. {
  483. if (!Impl_) {
  484. return 0;
  485. }
  486. return Impl_->GetPid();
  487. }
  488. NThreading::TThreadId TError::GetTid() const
  489. {
  490. if (!Impl_) {
  491. return NThreading::InvalidThreadId;
  492. }
  493. return Impl_->GetTid();
  494. }
  495. TStringBuf TError::GetThreadName() const
  496. {
  497. if (!Impl_) {
  498. static TString empty;
  499. return empty;
  500. }
  501. return Impl_->GetThreadName();
  502. }
  503. NConcurrency::TFiberId TError::GetFid() const
  504. {
  505. if (!Impl_) {
  506. return NConcurrency::InvalidFiberId;
  507. }
  508. return Impl_->GetFid();
  509. }
  510. bool TError::HasTracingAttributes() const
  511. {
  512. if (!Impl_) {
  513. return false;
  514. }
  515. return Impl_->HasTracingAttributes();
  516. }
  517. NTracing::TTraceId TError::GetTraceId() const
  518. {
  519. if (!Impl_) {
  520. return NTracing::InvalidTraceId;
  521. }
  522. return Impl_->GetTraceId();
  523. }
  524. NTracing::TSpanId TError::GetSpanId() const
  525. {
  526. if (!Impl_) {
  527. return NTracing::InvalidSpanId;
  528. }
  529. return Impl_->GetSpanId();
  530. }
  531. const IAttributeDictionary& TError::Attributes() const
  532. {
  533. if (!Impl_) {
  534. return EmptyAttributes();
  535. }
  536. return Impl_->Attributes();
  537. }
  538. IAttributeDictionary* TError::MutableAttributes()
  539. {
  540. MakeMutable();
  541. return Impl_->MutableAttributes();
  542. }
  543. const std::vector<TError>& TError::InnerErrors() const
  544. {
  545. if (!Impl_) {
  546. static const std::vector<TError> Result;
  547. return Result;
  548. }
  549. return Impl_->InnerErrors();
  550. }
  551. std::vector<TError>* TError::MutableInnerErrors()
  552. {
  553. MakeMutable();
  554. return Impl_->MutableInnerErrors();
  555. }
  556. const TString InnerErrorsTruncatedKey("inner_errors_truncated");
  557. TError TError::Truncate(
  558. int maxInnerErrorCount,
  559. i64 stringLimit,
  560. const THashSet<TStringBuf>& attributeWhitelist) const &
  561. {
  562. if (!Impl_) {
  563. return TError();
  564. }
  565. auto truncateInnerError = [=, &attributeWhitelist] (const TError& innerError) {
  566. return innerError.Truncate(maxInnerErrorCount, stringLimit, attributeWhitelist);
  567. };
  568. auto truncateAttributes = [stringLimit, &attributeWhitelist] (const IAttributeDictionary& attributes) {
  569. auto truncatedAttributes = CreateEphemeralAttributes();
  570. for (const auto& key : attributes.ListKeys()) {
  571. const auto& value = attributes.FindYson(key);
  572. if (std::ssize(value.AsStringBuf()) > stringLimit && !attributeWhitelist.contains(key)) {
  573. truncatedAttributes->SetYson(
  574. key,
  575. BuildYsonStringFluently()
  576. .Value("...<attribute truncated>..."));
  577. } else {
  578. truncatedAttributes->SetYson(
  579. key,
  580. value);
  581. }
  582. }
  583. return truncatedAttributes;
  584. };
  585. auto result = std::make_unique<TImpl>();
  586. result->SetCode(GetCode());
  587. result->SetMessage(TruncateString(GetMessage(), stringLimit, ErrorMessageTruncatedSuffix));
  588. if (Impl_->HasAttributes()) {
  589. result->SetAttributes(truncateAttributes(Impl_->Attributes()));
  590. }
  591. result->CopyBuiltinAttributesFrom(*Impl_);
  592. const auto& innerErrors = InnerErrors();
  593. auto& copiedInnerErrors = *result->MutableInnerErrors();
  594. if (std::ssize(innerErrors) <= maxInnerErrorCount) {
  595. for (const auto& innerError : innerErrors) {
  596. copiedInnerErrors.push_back(truncateInnerError(innerError));
  597. }
  598. } else {
  599. result->MutableAttributes()->Set(InnerErrorsTruncatedKey, true);
  600. // NB(arkady-e1ppa): We want to always keep the last inner error,
  601. // so we make room for it and do not check if it is whitelisted.
  602. for (int idx = 0; idx < std::ssize(innerErrors) - 1; ++idx) {
  603. const auto& innerError = innerErrors[idx];
  604. if (
  605. IsWhitelisted(innerError, attributeWhitelist) ||
  606. std::ssize(copiedInnerErrors) < maxInnerErrorCount - 1)
  607. {
  608. copiedInnerErrors.push_back(truncateInnerError(innerError));
  609. }
  610. }
  611. copiedInnerErrors.push_back(truncateInnerError(innerErrors.back()));
  612. }
  613. return TError(std::move(result));
  614. }
  615. TError TError::Truncate(
  616. int maxInnerErrorCount,
  617. i64 stringLimit,
  618. const THashSet<TStringBuf>& attributeWhitelist) &&
  619. {
  620. if (!Impl_) {
  621. return TError();
  622. }
  623. auto truncateInnerError = [=, &attributeWhitelist] (TError& innerError) {
  624. innerError = std::move(innerError).Truncate(maxInnerErrorCount, stringLimit, attributeWhitelist);
  625. };
  626. auto truncateAttributes = [stringLimit, &attributeWhitelist] (IAttributeDictionary* attributes) {
  627. for (const auto& key : attributes->ListKeys()) {
  628. if (std::ssize(attributes->FindYson(key).AsStringBuf()) > stringLimit && !attributeWhitelist.contains(key)) {
  629. attributes->SetYson(
  630. key,
  631. BuildYsonStringFluently()
  632. .Value("...<attribute truncated>..."));
  633. }
  634. }
  635. };
  636. TruncateStringInplace(Impl_->MutableMessage(), stringLimit, ErrorMessageTruncatedSuffix);
  637. if (Impl_->HasAttributes()) {
  638. truncateAttributes(Impl_->MutableAttributes());
  639. }
  640. if (std::ssize(InnerErrors()) <= maxInnerErrorCount) {
  641. for (auto& innerError : *MutableInnerErrors()) {
  642. truncateInnerError(innerError);
  643. }
  644. } else {
  645. auto& innerErrors = ApplyWhitelist(*MutableInnerErrors(), attributeWhitelist, maxInnerErrorCount);
  646. MutableAttributes()->Set(InnerErrorsTruncatedKey, true);
  647. for (auto& innerError : innerErrors) {
  648. truncateInnerError(innerError);
  649. }
  650. }
  651. return std::move(*this);
  652. }
  653. bool TError::IsOK() const
  654. {
  655. if (!Impl_) {
  656. return true;
  657. }
  658. return Impl_->IsOK();
  659. }
  660. void TError::ThrowOnError() const
  661. {
  662. if (!IsOK()) {
  663. THROW_ERROR *this;
  664. }
  665. }
  666. TError TError::Wrap() const &
  667. {
  668. return *this;
  669. }
  670. TError TError::Wrap() &&
  671. {
  672. return std::move(*this);
  673. }
  674. Y_WEAK TString GetErrorSkeleton(const TError& /*error*/)
  675. {
  676. // Proper implementation resides in yt/yt/library/error_skeleton/skeleton.cpp.
  677. THROW_ERROR_EXCEPTION("Error skeleton implementation library is not linked; consider PEERDIR'ing yt/yt/library/error_skeleton");
  678. }
  679. TString TError::GetSkeleton() const
  680. {
  681. return GetErrorSkeleton(*this);
  682. }
  683. void TError::Save(TStreamSaveContext& context) const
  684. {
  685. using NYT::Save;
  686. if (!Impl_) {
  687. // Fast path.
  688. Save(context, TErrorCode(NYT::EErrorCode::OK)); // code
  689. Save(context, TStringBuf()); // message
  690. Save(context, IAttributeDictionaryPtr()); // attributes
  691. Save(context, std::vector<TError>()); // inner errors
  692. return;
  693. }
  694. Save(context, GetCode());
  695. Save(context, GetMessage());
  696. // Cf. TAttributeDictionaryValueSerializer.
  697. auto attributePairs = Attributes().ListPairs();
  698. size_t attributeCount = attributePairs.size();
  699. if (HasOriginAttributes()) {
  700. attributeCount += 5;
  701. }
  702. if (HasDatetime()) {
  703. attributeCount += 1;
  704. }
  705. if (HasTracingAttributes()) {
  706. attributeCount += 2;
  707. }
  708. if (attributeCount > 0) {
  709. // Cf. TAttributeDictionaryRefSerializer.
  710. Save(context, true);
  711. TSizeSerializer::Save(context, attributeCount);
  712. auto saveAttribute = [&] (const TString& key, const auto& value) {
  713. Save(context, key);
  714. Save(context, ConvertToYsonString(value));
  715. };
  716. if (HasOriginAttributes()) {
  717. static const TString HostKey("host");
  718. saveAttribute(HostKey, GetHost());
  719. static const TString PidKey("pid");
  720. saveAttribute(PidKey, GetPid());
  721. static const TString TidKey("tid");
  722. saveAttribute(TidKey, GetTid());
  723. static const TString ThreadNameKey("thread");
  724. saveAttribute(ThreadNameKey, GetThreadName());
  725. static const TString FidKey("fid");
  726. saveAttribute(FidKey, GetFid());
  727. }
  728. if (HasDatetime()) {
  729. static const TString DatetimeKey("datetime");
  730. saveAttribute(DatetimeKey, GetDatetime());
  731. }
  732. if (HasTracingAttributes()) {
  733. static const TString TraceIdKey("trace_id");
  734. saveAttribute(TraceIdKey, GetTraceId());
  735. static const TString SpanIdKey("span_id");
  736. saveAttribute(SpanIdKey, GetSpanId());
  737. }
  738. std::sort(attributePairs.begin(), attributePairs.end(), [] (const auto& lhs, const auto& rhs) {
  739. return lhs.first < rhs.first;
  740. });
  741. for (const auto& [key, value] : attributePairs) {
  742. Save(context, key);
  743. Save(context, value);
  744. }
  745. } else {
  746. Save(context, false);
  747. }
  748. Save(context, InnerErrors());
  749. }
  750. void TError::Load(TStreamLoadContext& context)
  751. {
  752. Impl_.reset();
  753. using NYT::Load;
  754. auto code = Load<TErrorCode>(context);
  755. auto message = Load<TString>(context);
  756. IAttributeDictionaryPtr attributes;
  757. if (Load<bool>(context)) {
  758. attributes = CreateEphemeralAttributes();
  759. TAttributeDictionarySerializer::LoadNonNull(context, attributes);
  760. }
  761. auto innerErrors = Load<std::vector<TError>>(context);
  762. if (code == NYT::EErrorCode::OK) {
  763. // Fast path.
  764. // Note that there were no allocations above.
  765. return;
  766. }
  767. auto impl = std::make_unique<TImpl>();
  768. impl->SetCode(code);
  769. impl->SetMessage(std::move(message));
  770. impl->SetAttributes(std::move(attributes));
  771. *impl->MutableInnerErrors() = std::move(innerErrors);
  772. Impl_ = std::move(impl);
  773. }
  774. std::optional<TError> TError::FindMatching(TErrorCode code) const
  775. {
  776. return FindMatching([&] (TErrorCode errorCode) {
  777. return code == errorCode;
  778. });
  779. }
  780. std::optional<TError> TError::FindMatching(const THashSet<TErrorCode>& codes) const
  781. {
  782. return FindMatching([&] (TErrorCode code) {
  783. return codes.contains(code);
  784. });
  785. }
  786. std::optional<TError> TError::FindMatching(std::function<bool(TErrorCode)> filter) const
  787. {
  788. if (!Impl_) {
  789. return {};
  790. }
  791. if (filter(GetCode())) {
  792. return *this;
  793. }
  794. for (const auto& innerError : InnerErrors()) {
  795. if (auto innerResult = innerError.FindMatching(filter)) {
  796. return innerResult;
  797. }
  798. }
  799. return {};
  800. }
  801. TError::TErrorOr(std::unique_ptr<TImpl> impl)
  802. : Impl_(std::move(impl))
  803. { }
  804. void TError::MakeMutable()
  805. {
  806. if (!Impl_) {
  807. Impl_ = std::make_unique<TImpl>();
  808. }
  809. }
  810. ////////////////////////////////////////////////////////////////////////////////
  811. namespace {
  812. void AppendIndent(TStringBuilderBase* builer, int indent)
  813. {
  814. builer->AppendChar(' ', indent);
  815. }
  816. void AppendAttribute(TStringBuilderBase* builder, const TString& key, const TString& value, int indent)
  817. {
  818. AppendIndent(builder, indent + 4);
  819. if (!value.Contains('\n')) {
  820. builder->AppendFormat("%-15s %s", key, value);
  821. } else {
  822. builder->AppendString(key);
  823. TString indentedValue = "\n" + value;
  824. SubstGlobal(indentedValue, "\n", "\n" + TString{static_cast<size_t>(indent + 8), ' '});
  825. // Now first line in indentedValue is empty and every other line is indented by 8 spaces.
  826. builder->AppendString(indentedValue);
  827. }
  828. builder->AppendChar('\n');
  829. }
  830. void AppendError(TStringBuilderBase* builder, const TError& error, int indent)
  831. {
  832. if (error.IsOK()) {
  833. builder->AppendString("OK");
  834. return;
  835. }
  836. AppendIndent(builder, indent);
  837. builder->AppendString(error.GetMessage());
  838. builder->AppendChar('\n');
  839. if (error.GetCode() != NYT::EErrorCode::Generic) {
  840. AppendAttribute(builder, "code", ToString(static_cast<int>(error.GetCode())), indent);
  841. }
  842. // Pretty-print origin.
  843. if (error.HasOriginAttributes()) {
  844. AppendAttribute(
  845. builder,
  846. "origin",
  847. Format("%v (pid %v, thread %v, fid %x)",
  848. error.GetHost(),
  849. error.GetPid(),
  850. (!error.GetThreadName().empty() ? error.GetThreadName() : ToString(error.GetTid())),
  851. error.GetFid()),
  852. indent);
  853. } else if (ErrorSanitizerEnabled && error.HasHost()) {
  854. AppendAttribute(
  855. builder,
  856. "host",
  857. ToString(error.GetHost()),
  858. indent);
  859. }
  860. if (error.HasDatetime()) {
  861. AppendAttribute(
  862. builder,
  863. "datetime",
  864. Format("%v", error.GetDatetime()),
  865. indent);
  866. }
  867. for (const auto& [key, value] : error.Attributes().ListPairs()) {
  868. TTokenizer tokenizer(value.AsStringBuf());
  869. YT_VERIFY(tokenizer.ParseNext());
  870. switch (tokenizer.GetCurrentType()) {
  871. case ETokenType::String:
  872. AppendAttribute(builder, key, TString(tokenizer.CurrentToken().GetStringValue()), indent);
  873. break;
  874. case ETokenType::Int64:
  875. AppendAttribute(builder, key, ToString(tokenizer.CurrentToken().GetInt64Value()), indent);
  876. break;
  877. case ETokenType::Uint64:
  878. AppendAttribute(builder, key, ToString(tokenizer.CurrentToken().GetUint64Value()), indent);
  879. break;
  880. case ETokenType::Double:
  881. AppendAttribute(builder, key, ToString(tokenizer.CurrentToken().GetDoubleValue()), indent);
  882. break;
  883. case ETokenType::Boolean:
  884. AppendAttribute(builder, key, TString(FormatBool(tokenizer.CurrentToken().GetBooleanValue())), indent);
  885. break;
  886. default:
  887. AppendAttribute(builder, key, ConvertToYsonString(value, EYsonFormat::Text).ToString(), indent);
  888. break;
  889. }
  890. }
  891. for (const auto& innerError : error.InnerErrors()) {
  892. builder->AppendChar('\n');
  893. AppendError(builder, innerError, indent + 2);
  894. }
  895. }
  896. } // namespace
  897. bool operator == (const TError& lhs, const TError& rhs)
  898. {
  899. if (!lhs.Impl_ && !rhs.Impl_) {
  900. return true;
  901. }
  902. return
  903. lhs.GetCode() == rhs.GetCode() &&
  904. lhs.GetMessage() == rhs.GetMessage() &&
  905. lhs.GetHost() == rhs.GetHost() &&
  906. lhs.GetDatetime() == rhs.GetDatetime() &&
  907. lhs.GetPid() == rhs.GetPid() &&
  908. lhs.GetTid() == rhs.GetTid() &&
  909. lhs.GetFid() == rhs.GetFid() &&
  910. lhs.GetTraceId() == rhs.GetTraceId() &&
  911. lhs.GetSpanId() == rhs.GetSpanId() &&
  912. lhs.Attributes() == rhs.Attributes() &&
  913. lhs.InnerErrors() == rhs.InnerErrors();
  914. }
  915. void FormatValue(TStringBuilderBase* builder, const TError& error, TStringBuf /*spec*/)
  916. {
  917. AppendError(builder, error, 0);
  918. }
  919. TString ToString(const TError& error)
  920. {
  921. TStringBuilder builder;
  922. AppendError(&builder, error, 0);
  923. return builder.Flush();
  924. }
  925. void ToProto(NYT::NProto::TError* protoError, const TError& error)
  926. {
  927. if (!error.Impl_) {
  928. protoError->set_code(static_cast<int>(NYT::EErrorCode::OK));
  929. protoError->clear_message();
  930. return;
  931. }
  932. protoError->set_code(error.GetCode());
  933. protoError->set_message(error.GetMessage());
  934. protoError->clear_attributes();
  935. if (error.Impl_->HasAttributes()) {
  936. ToProto(protoError->mutable_attributes(), error.Attributes());
  937. }
  938. auto addAttribute = [&] (const TString& key, const auto& value) {
  939. auto* protoItem = protoError->mutable_attributes()->add_attributes();
  940. protoItem->set_key(key);
  941. protoItem->set_value(ConvertToYsonString(value).ToString());
  942. };
  943. if (error.HasOriginAttributes()) {
  944. static const TString HostKey("host");
  945. addAttribute(HostKey, error.GetHost());
  946. static const TString PidKey("pid");
  947. addAttribute(PidKey, error.GetPid());
  948. static const TString TidKey("tid");
  949. addAttribute(TidKey, error.GetTid());
  950. static const TString ThreadName("thread");
  951. addAttribute(ThreadName, error.GetThreadName());
  952. static const TString FidKey("fid");
  953. addAttribute(FidKey, error.GetFid());
  954. } else if (ErrorSanitizerEnabled && error.HasHost()) {
  955. static const TString HostKey("host");
  956. addAttribute(HostKey, error.GetHost());
  957. }
  958. if (error.HasDatetime()) {
  959. static const TString DatetimeKey("datetime");
  960. addAttribute(DatetimeKey, error.GetDatetime());
  961. }
  962. if (error.HasTracingAttributes()) {
  963. static const TString TraceIdKey("trace_id");
  964. addAttribute(TraceIdKey, error.GetTraceId());
  965. static const TString SpanIdKey("span_id");
  966. addAttribute(SpanIdKey, error.GetSpanId());
  967. }
  968. protoError->clear_inner_errors();
  969. for (const auto& innerError : error.InnerErrors()) {
  970. ToProto(protoError->add_inner_errors(), innerError);
  971. }
  972. }
  973. void FromProto(TError* error, const NYT::NProto::TError& protoError)
  974. {
  975. *error = {};
  976. if (protoError.code() == static_cast<int>(NYT::EErrorCode::OK)) {
  977. return;
  978. }
  979. error->SetCode(TErrorCode(protoError.code()));
  980. error->SetMessage(FromProto<TString>(protoError.message()));
  981. if (protoError.has_attributes()) {
  982. error->Impl_->SetAttributes(FromProto(protoError.attributes()));
  983. } else {
  984. error->Impl_->SetAttributes(nullptr);
  985. }
  986. *error->MutableInnerErrors() = FromProto<std::vector<TError>>(protoError.inner_errors());
  987. }
  988. void TraverseError(const TError& error, const TErrorVisitor& visitor, int depth)
  989. {
  990. visitor(error, depth);
  991. for (const auto& inner : error.InnerErrors()) {
  992. TraverseError(inner, visitor, depth + 1);
  993. }
  994. }
  995. namespace {
  996. // Errors whose depth exceeds |ErrorSerializationDepthLimit| are serialized
  997. // as children of their ancestor on depth |ErrorSerializationDepthLimit - 1|.
  998. void SerializeInnerErrors(TFluentMap fluent, const TError& error, int depth)
  999. {
  1000. if (depth >= ErrorSerializationDepthLimit) {
  1001. // Ignore deep inner errors.
  1002. return;
  1003. }
  1004. auto visit = [&] (auto fluent, const TError& error, int depth) {
  1005. fluent
  1006. .Item().Do([&] (auto fluent) {
  1007. Serialize(error, fluent.GetConsumer(), /*valueProduce*/ nullptr, depth);
  1008. });
  1009. };
  1010. fluent
  1011. .Item("inner_errors").DoListFor(error.InnerErrors(), [&] (auto fluent, const TError& innerError) {
  1012. if (depth < ErrorSerializationDepthLimit - 1) {
  1013. visit(fluent, innerError, depth + 1);
  1014. } else {
  1015. YT_VERIFY(depth == ErrorSerializationDepthLimit - 1);
  1016. TraverseError(
  1017. innerError,
  1018. [&] (const TError& e, int depth) {
  1019. visit(fluent, e, depth);
  1020. },
  1021. depth + 1);
  1022. }
  1023. });
  1024. }
  1025. } // namespace
  1026. void Serialize(
  1027. const TError& error,
  1028. IYsonConsumer* consumer,
  1029. const std::function<void(IYsonConsumer*)>* valueProducer,
  1030. int depth)
  1031. {
  1032. BuildYsonFluently(consumer)
  1033. .BeginMap()
  1034. .Item("code").Value(error.GetCode())
  1035. .Item("message").Value(error.GetMessage())
  1036. .Item("attributes").DoMap([&] (auto fluent) {
  1037. if (error.HasOriginAttributes()) {
  1038. fluent
  1039. .Item("host").Value(error.GetHost())
  1040. .Item("pid").Value(error.GetPid())
  1041. .Item("tid").Value(error.GetTid())
  1042. .Item("thread").Value(error.GetThreadName())
  1043. .Item("fid").Value(error.GetFid());
  1044. } else if (ErrorSanitizerEnabled && error.HasHost()) {
  1045. fluent
  1046. .Item("host").Value(error.GetHost());
  1047. }
  1048. if (error.HasDatetime()) {
  1049. fluent
  1050. .Item("datetime").Value(error.GetDatetime());
  1051. }
  1052. if (error.HasTracingAttributes()) {
  1053. fluent
  1054. .Item("trace_id").Value(error.GetTraceId())
  1055. .Item("span_id").Value(error.GetSpanId());
  1056. }
  1057. if (depth > ErrorSerializationDepthLimit && !error.Attributes().Contains(OriginalErrorDepthAttribute)) {
  1058. fluent
  1059. .Item(OriginalErrorDepthAttribute).Value(depth);
  1060. }
  1061. for (const auto& [key, value] : error.Attributes().ListPairs()) {
  1062. fluent
  1063. .Item(key).Value(value);
  1064. }
  1065. })
  1066. .DoIf(!error.InnerErrors().empty(), [&] (auto fluent) {
  1067. SerializeInnerErrors(fluent, error, depth);
  1068. })
  1069. .DoIf(valueProducer != nullptr, [&] (auto fluent) {
  1070. auto* consumer = fluent.GetConsumer();
  1071. // NB: we are forced to deal with a bare consumer here because
  1072. // we can't use void(TFluentMap) in a function signature as it
  1073. // will lead to the inclusion of fluent.h in error.h and a cyclic
  1074. // inclusion error.h -> fluent.h -> callback.h -> error.h
  1075. consumer->OnKeyedItem(TStringBuf("value"));
  1076. (*valueProducer)(consumer);
  1077. })
  1078. .EndMap();
  1079. }
  1080. void Deserialize(TError& error, const NYTree::INodePtr& node)
  1081. {
  1082. error = {};
  1083. auto mapNode = node->AsMap();
  1084. static const TString CodeKey("code");
  1085. auto code = TErrorCode(mapNode->GetChildValueOrThrow<i64>(CodeKey));
  1086. if (code == NYT::EErrorCode::OK) {
  1087. return;
  1088. }
  1089. auto result = std::make_unique<TError::TImpl>();
  1090. result->SetCode(code);
  1091. static const TString MessageKey("message");
  1092. result->SetMessage(mapNode->GetChildValueOrThrow<TString>(MessageKey));
  1093. static const TString AttributesKey("attributes");
  1094. result->SetAttributes(IAttributeDictionary::FromMap(mapNode->GetChildOrThrow(AttributesKey)->AsMap()));
  1095. static const TString InnerErrorsKey("inner_errors");
  1096. if (auto innerErrorsNode = mapNode->FindChild(InnerErrorsKey)) {
  1097. for (const auto& innerErrorNode : innerErrorsNode->AsList()->GetChildren()) {
  1098. result->MutableInnerErrors()->push_back(ConvertTo<TError>(innerErrorNode));
  1099. }
  1100. }
  1101. error = TError(std::move(result));
  1102. }
  1103. void Deserialize(TError& error, NYson::TYsonPullParserCursor* cursor)
  1104. {
  1105. Deserialize(error, ExtractTo<INodePtr>(cursor));
  1106. }
  1107. ////////////////////////////////////////////////////////////////////////////////
  1108. TError& TError::operator <<= (const TErrorAttribute& attribute) &
  1109. {
  1110. MutableAttributes()->SetYson(attribute.Key, attribute.Value);
  1111. return *this;
  1112. }
  1113. TError& TError::operator <<= (const std::vector<TErrorAttribute>& attributes) &
  1114. {
  1115. for (const auto& attribute : attributes) {
  1116. MutableAttributes()->SetYson(attribute.Key, attribute.Value);
  1117. }
  1118. return *this;
  1119. }
  1120. TError& TError::operator <<= (const TError& innerError) &
  1121. {
  1122. MutableInnerErrors()->push_back(innerError);
  1123. return *this;
  1124. }
  1125. TError& TError::operator <<= (TError&& innerError) &
  1126. {
  1127. MutableInnerErrors()->push_back(std::move(innerError));
  1128. return *this;
  1129. }
  1130. TError& TError::operator <<= (const std::vector<TError>& innerErrors) &
  1131. {
  1132. MutableInnerErrors()->insert(
  1133. MutableInnerErrors()->end(),
  1134. innerErrors.begin(),
  1135. innerErrors.end());
  1136. return *this;
  1137. }
  1138. TError& TError::operator <<= (std::vector<TError>&& innerErrors) &
  1139. {
  1140. MutableInnerErrors()->insert(
  1141. MutableInnerErrors()->end(),
  1142. std::make_move_iterator(innerErrors.begin()),
  1143. std::make_move_iterator(innerErrors.end()));
  1144. return *this;
  1145. }
  1146. TError& TError::operator <<= (const NYTree::IAttributeDictionary& attributes) &
  1147. {
  1148. MutableAttributes()->MergeFrom(attributes);
  1149. return *this;
  1150. }
  1151. ////////////////////////////////////////////////////////////////////////////////
  1152. const char* TErrorException::what() const noexcept
  1153. {
  1154. if (CachedWhat_.empty()) {
  1155. CachedWhat_ = ToString(Error_);
  1156. }
  1157. return CachedWhat_.data();
  1158. }
  1159. ////////////////////////////////////////////////////////////////////////////////
  1160. } // namespace NYT