errors.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. #include "errors.h"
  2. #include <library/cpp/yson/node/node_io.h>
  3. #include <library/cpp/yson/node/node_visitor.h>
  4. #include <yt/cpp/mapreduce/interface/error_codes.h>
  5. #include <library/cpp/json/json_reader.h>
  6. #include <library/cpp/yson/writer.h>
  7. #include <util/string/builder.h>
  8. #include <util/stream/str.h>
  9. #include <util/generic/set.h>
  10. namespace NYT {
  11. using namespace NJson;
  12. ////////////////////////////////////////////////////////////////////////////////
  13. static void WriteErrorDescription(const TYtError& error, IOutputStream* out)
  14. {
  15. (*out) << error.GetMessage();
  16. const auto& innerErrorList = error.InnerErrors();
  17. if (!innerErrorList.empty()) {
  18. (*out) << ": ";
  19. WriteErrorDescription(innerErrorList[0], out);
  20. }
  21. }
  22. static void SerializeError(const TYtError& error, NYson::IYsonConsumer* consumer)
  23. {
  24. consumer->OnBeginMap();
  25. {
  26. consumer->OnKeyedItem("code");
  27. consumer->OnInt64Scalar(error.GetCode());
  28. consumer->OnKeyedItem("message");
  29. consumer->OnStringScalar(error.GetMessage());
  30. if (!error.GetAttributes().empty()) {
  31. consumer->OnKeyedItem("attributes");
  32. consumer->OnBeginMap();
  33. {
  34. for (const auto& item : error.GetAttributes()) {
  35. consumer->OnKeyedItem(item.first);
  36. TNodeVisitor(consumer).Visit(item.second);
  37. }
  38. }
  39. consumer->OnEndMap();
  40. }
  41. if (!error.InnerErrors().empty()) {
  42. consumer->OnKeyedItem("inner_errors");
  43. {
  44. consumer->OnBeginList();
  45. for (const auto& innerError : error.InnerErrors()) {
  46. SerializeError(innerError, consumer);
  47. }
  48. consumer->OnEndList();
  49. }
  50. }
  51. }
  52. consumer->OnEndMap();
  53. }
  54. static TString DumpJobInfoForException(const TOperationId& operationId, const TVector<TFailedJobInfo>& failedJobInfoList)
  55. {
  56. ::TStringBuilder output;
  57. // Exceptions have limit to contain 65508 bytes of text, so we also limit stderr text
  58. constexpr size_t MAX_SIZE = 65508 / 2;
  59. size_t written = 0;
  60. for (const auto& failedJobInfo : failedJobInfoList) {
  61. if (written >= MAX_SIZE) {
  62. break;
  63. }
  64. TStringStream nextChunk;
  65. nextChunk << '\n';
  66. nextChunk << "OperationId: " << GetGuidAsString(operationId) << " JobId: " << GetGuidAsString(failedJobInfo.JobId) << '\n';
  67. nextChunk << "Error: " << failedJobInfo.Error.FullDescription() << '\n';
  68. if (!failedJobInfo.Stderr.empty()) {
  69. nextChunk << "Stderr: " << Endl;
  70. size_t tmpWritten = written + nextChunk.Str().size();
  71. if (tmpWritten >= MAX_SIZE) {
  72. break;
  73. }
  74. if (tmpWritten + failedJobInfo.Stderr.size() > MAX_SIZE) {
  75. nextChunk << failedJobInfo.Stderr.substr(failedJobInfo.Stderr.size() - (MAX_SIZE - tmpWritten));
  76. } else {
  77. nextChunk << failedJobInfo.Stderr;
  78. }
  79. }
  80. written += nextChunk.Str().size();
  81. output << nextChunk.Str();
  82. }
  83. return output;
  84. }
  85. ////////////////////////////////////////////////////////////////////////////////
  86. TYtError::TYtError()
  87. : Code_(0)
  88. { }
  89. TYtError::TYtError(const TString& message)
  90. : Code_(NYT::NClusterErrorCodes::Generic)
  91. , Message_(message)
  92. { }
  93. TYtError::TYtError(int code, TString message, TVector<TYtError> innerError, TNode::TMapType attributes)
  94. : Code_(code)
  95. , Message_(message)
  96. , InnerErrors_(innerError)
  97. , Attributes_(attributes)
  98. { }
  99. TYtError::TYtError(const TJsonValue& value)
  100. {
  101. const TJsonValue::TMapType& map = value.GetMap();
  102. TJsonValue::TMapType::const_iterator it = map.find("message");
  103. if (it != map.end()) {
  104. Message_ = it->second.GetString();
  105. }
  106. it = map.find("code");
  107. if (it != map.end()) {
  108. Code_ = static_cast<int>(it->second.GetInteger());
  109. } else {
  110. Code_ = NYT::NClusterErrorCodes::Generic;
  111. }
  112. it = map.find("inner_errors");
  113. if (it != map.end()) {
  114. const TJsonValue::TArray& innerErrors = it->second.GetArray();
  115. for (const auto& innerError : innerErrors) {
  116. InnerErrors_.push_back(TYtError(innerError));
  117. }
  118. }
  119. it = map.find("attributes");
  120. if (it != map.end()) {
  121. auto attributes = NYT::NodeFromJsonValue(it->second);
  122. if (attributes.IsMap()) {
  123. Attributes_ = std::move(attributes.AsMap());
  124. }
  125. }
  126. }
  127. TYtError::TYtError(const TNode& node)
  128. {
  129. const auto& map = node.AsMap();
  130. auto it = map.find("message");
  131. if (it != map.end()) {
  132. Message_ = it->second.AsString();
  133. }
  134. it = map.find("code");
  135. if (it != map.end()) {
  136. Code_ = static_cast<int>(it->second.AsInt64());
  137. } else {
  138. Code_ = NYT::NClusterErrorCodes::Generic;
  139. }
  140. it = map.find("inner_errors");
  141. if (it != map.end()) {
  142. const auto& innerErrors = it->second.AsList();
  143. for (const auto& innerError : innerErrors) {
  144. InnerErrors_.push_back(TYtError(innerError));
  145. }
  146. }
  147. it = map.find("attributes");
  148. if (it != map.end()) {
  149. auto& attributes = it->second;
  150. if (attributes.IsMap()) {
  151. Attributes_ = std::move(attributes.AsMap());
  152. }
  153. }
  154. }
  155. int TYtError::GetCode() const
  156. {
  157. return Code_;
  158. }
  159. const TString& TYtError::GetMessage() const
  160. {
  161. return Message_;
  162. }
  163. const TVector<TYtError>& TYtError::InnerErrors() const
  164. {
  165. return InnerErrors_;
  166. }
  167. void TYtError::ParseFrom(const TString& jsonError)
  168. {
  169. TJsonValue value;
  170. TStringInput input(jsonError);
  171. ReadJsonTree(&input, &value);
  172. *this = TYtError(value);
  173. }
  174. TSet<int> TYtError::GetAllErrorCodes() const
  175. {
  176. TDeque<const TYtError*> queue = {this};
  177. TSet<int> result;
  178. while (!queue.empty()) {
  179. const auto* current = queue.front();
  180. queue.pop_front();
  181. result.insert(current->Code_);
  182. for (const auto& error : current->InnerErrors_) {
  183. queue.push_back(&error);
  184. }
  185. }
  186. return result;
  187. }
  188. bool TYtError::ContainsErrorCode(int code) const
  189. {
  190. if (Code_ == code) {
  191. return true;
  192. }
  193. for (const auto& error : InnerErrors_) {
  194. if (error.ContainsErrorCode(code)) {
  195. return true;
  196. }
  197. }
  198. return false;
  199. }
  200. bool TYtError::ContainsText(const TStringBuf& text) const
  201. {
  202. if (Message_.Contains(text)) {
  203. return true;
  204. }
  205. for (const auto& error : InnerErrors_) {
  206. if (error.ContainsText(text)) {
  207. return true;
  208. }
  209. }
  210. return false;
  211. }
  212. bool TYtError::HasAttributes() const
  213. {
  214. return !Attributes_.empty();
  215. }
  216. const TNode::TMapType& TYtError::GetAttributes() const
  217. {
  218. return Attributes_;
  219. }
  220. TString TYtError::GetYsonText() const
  221. {
  222. TStringStream out;
  223. ::NYson::TYsonWriter writer(&out, NYson::EYsonFormat::Text);
  224. SerializeError(*this, &writer);
  225. return std::move(out.Str());
  226. }
  227. TString TYtError::ShortDescription() const
  228. {
  229. TStringStream out;
  230. WriteErrorDescription(*this, &out);
  231. return std::move(out.Str());
  232. }
  233. TString TYtError::FullDescription() const
  234. {
  235. TStringStream s;
  236. WriteErrorDescription(*this, &s);
  237. s << "; full error: " << GetYsonText();
  238. return s.Str();
  239. }
  240. ////////////////////////////////////////////////////////////////////////////////
  241. TErrorResponse::TErrorResponse(TYtError error, const TString& requestId)
  242. : RequestId_(requestId)
  243. , Error_(std::move(error))
  244. {
  245. Setup();
  246. }
  247. bool TErrorResponse::IsOk() const
  248. {
  249. return Error_.GetCode() == 0;
  250. }
  251. void TErrorResponse::SetRawError(const TString& message)
  252. {
  253. Error_ = TYtError(message);
  254. Setup();
  255. }
  256. void TErrorResponse::SetError(TYtError error)
  257. {
  258. Error_ = std::move(error);
  259. Setup();
  260. }
  261. void TErrorResponse::ParseFromJsonError(const TString& jsonError)
  262. {
  263. Error_.ParseFrom(jsonError);
  264. Setup();
  265. }
  266. void TErrorResponse::SetIsFromTrailers(bool isFromTrailers)
  267. {
  268. IsFromTrailers_ = isFromTrailers;
  269. }
  270. bool TErrorResponse::IsFromTrailers() const
  271. {
  272. return IsFromTrailers_;
  273. }
  274. bool TErrorResponse::IsTransportError() const
  275. {
  276. return Error_.ContainsErrorCode(NClusterErrorCodes::NBus::TransportError);
  277. }
  278. TString TErrorResponse::GetRequestId() const
  279. {
  280. return RequestId_;
  281. }
  282. const TYtError& TErrorResponse::GetError() const
  283. {
  284. return Error_;
  285. }
  286. bool TErrorResponse::IsResolveError() const
  287. {
  288. return Error_.ContainsErrorCode(NClusterErrorCodes::NYTree::ResolveError);
  289. }
  290. bool TErrorResponse::IsAccessDenied() const
  291. {
  292. return Error_.ContainsErrorCode(NClusterErrorCodes::NSecurityClient::AuthorizationError);
  293. }
  294. bool TErrorResponse::IsUnauthorized() const
  295. {
  296. const auto allCodes = Error_.GetAllErrorCodes();
  297. for (auto code : {
  298. NClusterErrorCodes::NRpc::AuthenticationError,
  299. NClusterErrorCodes::NRpc::InvalidCsrfToken,
  300. NClusterErrorCodes::NRpc::InvalidCredentials,
  301. NClusterErrorCodes::NSecurityClient::AuthenticationError,
  302. }) {
  303. if (allCodes.contains(code)) {
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. bool TErrorResponse::IsConcurrentTransactionLockConflict() const
  310. {
  311. return Error_.ContainsErrorCode(NClusterErrorCodes::NCypressClient::ConcurrentTransactionLockConflict);
  312. }
  313. bool TErrorResponse::IsRequestRateLimitExceeded() const
  314. {
  315. return Error_.ContainsErrorCode(NClusterErrorCodes::NSecurityClient::RequestQueueSizeLimitExceeded);
  316. }
  317. bool TErrorResponse::IsRequestQueueSizeLimitExceeded() const
  318. {
  319. return Error_.ContainsErrorCode(NClusterErrorCodes::NRpc::RequestQueueSizeLimitExceeded);
  320. }
  321. bool TErrorResponse::IsChunkUnavailable() const
  322. {
  323. return Error_.ContainsErrorCode(NClusterErrorCodes::NChunkClient::ChunkUnavailable);
  324. }
  325. bool TErrorResponse::IsRequestTimedOut() const
  326. {
  327. return Error_.ContainsErrorCode(NClusterErrorCodes::Timeout);
  328. }
  329. bool TErrorResponse::IsNoSuchTransaction() const
  330. {
  331. return Error_.ContainsErrorCode(NClusterErrorCodes::NTransactionClient::NoSuchTransaction);
  332. }
  333. bool TErrorResponse::IsConcurrentOperationsLimitReached() const
  334. {
  335. return Error_.ContainsErrorCode(NClusterErrorCodes::NScheduler::TooManyOperations);
  336. }
  337. void TErrorResponse::Setup()
  338. {
  339. TStringStream s;
  340. *this << Error_.FullDescription();
  341. }
  342. TTransportError::TTransportError(TYtError error)
  343. {
  344. *this << error.FullDescription();
  345. }
  346. ////////////////////////////////////////////////////////////////////////////////
  347. TOperationFailedError::TOperationFailedError(
  348. EState state,
  349. TOperationId id,
  350. TYtError ytError,
  351. TVector<TFailedJobInfo> failedJobInfo)
  352. : State_(state)
  353. , OperationId_(id)
  354. , Error_(std::move(ytError))
  355. , FailedJobInfo_(std::move(failedJobInfo))
  356. {
  357. *this << Error_.FullDescription();
  358. if (!FailedJobInfo_.empty()) {
  359. *this << DumpJobInfoForException(OperationId_, FailedJobInfo_);
  360. }
  361. }
  362. TOperationFailedError::EState TOperationFailedError::GetState() const
  363. {
  364. return State_;
  365. }
  366. TOperationId TOperationFailedError::GetOperationId() const
  367. {
  368. return OperationId_;
  369. }
  370. const TYtError& TOperationFailedError::GetError() const
  371. {
  372. return Error_;
  373. }
  374. const TVector<TFailedJobInfo>& TOperationFailedError::GetFailedJobInfo() const
  375. {
  376. return FailedJobInfo_;
  377. }
  378. } // namespace NYT