error_code.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. #include "error_code.h"
  2. #include <library/cpp/yt/logging/logger.h>
  3. #include <library/cpp/yt/misc/global.h>
  4. #include <util/string/split.h>
  5. #include <util/system/type_name.h>
  6. namespace NYT {
  7. ////////////////////////////////////////////////////////////////////////////////
  8. // TODO(achulkov2): Remove this once we find all duplicate error codes.
  9. static YT_DEFINE_GLOBAL(NLogging::TLogger, Logger, "ErrorCode")
  10. ////////////////////////////////////////////////////////////////////////////////
  11. bool TErrorCodeRegistry::TErrorCodeInfo::operator==(const TErrorCodeInfo& rhs) const
  12. {
  13. return Namespace == rhs.Namespace && Name == rhs.Name;
  14. }
  15. TErrorCodeRegistry* TErrorCodeRegistry::Get()
  16. {
  17. return LeakySingleton<TErrorCodeRegistry>();
  18. }
  19. TErrorCodeRegistry::TErrorCodeInfo TErrorCodeRegistry::Get(int code) const
  20. {
  21. auto it = CodeToInfo_.find(code);
  22. if (it != CodeToInfo_.end()) {
  23. return it->second;
  24. }
  25. for (const auto& range : ErrorCodeRanges_) {
  26. if (range.Contains(code)) {
  27. return range.Get(code);
  28. }
  29. }
  30. return {"NUnknown", Format("ErrorCode%v", code)};
  31. }
  32. THashMap<int, TErrorCodeRegistry::TErrorCodeInfo> TErrorCodeRegistry::GetAllErrorCodes() const
  33. {
  34. return CodeToInfo_;
  35. }
  36. std::vector<TErrorCodeRegistry::TErrorCodeRangeInfo> TErrorCodeRegistry::GetAllErrorCodeRanges() const
  37. {
  38. return ErrorCodeRanges_;
  39. }
  40. void TErrorCodeRegistry::RegisterErrorCode(int code, const TErrorCodeInfo& errorCodeInfo)
  41. {
  42. if (!CodeToInfo_.insert({code, errorCodeInfo}).second) {
  43. // TODO(achulkov2): Deal with duplicate TransportError in NRpc and NBus.
  44. if (code == 100) {
  45. return;
  46. }
  47. // TODO(yuryalekseev): Deal with duplicate SslError in NRpc and NBus.
  48. if (code == 119) {
  49. return;
  50. }
  51. YT_LOG_FATAL(
  52. "Duplicate error code (Code: %v, StoredCodeInfo: %v, NewCodeInfo: %v)",
  53. code,
  54. CodeToInfo_[code],
  55. errorCodeInfo);
  56. }
  57. }
  58. TErrorCodeRegistry::TErrorCodeInfo TErrorCodeRegistry::TErrorCodeRangeInfo::Get(int code) const
  59. {
  60. return {Namespace, Formatter(code)};
  61. }
  62. bool TErrorCodeRegistry::TErrorCodeRangeInfo::Intersects(const TErrorCodeRangeInfo& other) const
  63. {
  64. return std::max(From, other.From) <= std::min(To, other.To);
  65. }
  66. bool TErrorCodeRegistry::TErrorCodeRangeInfo::Contains(int value) const
  67. {
  68. return From <= value && value <= To;
  69. }
  70. void TErrorCodeRegistry::RegisterErrorCodeRange(int from, int to, TString namespaceName, std::function<TString(int)> formatter)
  71. {
  72. YT_VERIFY(from <= to);
  73. TErrorCodeRangeInfo newRange{from, to, std::move(namespaceName), std::move(formatter)};
  74. for (const auto& range : ErrorCodeRanges_) {
  75. YT_LOG_FATAL_IF(
  76. range.Intersects(newRange),
  77. "Intersecting error code ranges registered (FirstRange: %v, SecondRange: %v)",
  78. range,
  79. newRange);
  80. }
  81. ErrorCodeRanges_.push_back(std::move(newRange));
  82. CheckCodesAgainstRanges();
  83. }
  84. void TErrorCodeRegistry::CheckCodesAgainstRanges() const
  85. {
  86. for (const auto& [code, info] : CodeToInfo_) {
  87. for (const auto& range : ErrorCodeRanges_) {
  88. YT_LOG_FATAL_IF(
  89. range.Contains(code),
  90. "Error code range contains another registered code "
  91. "(Range: %v, Code: %v, RangeCodeInfo: %v, StandaloneCodeInfo: %v)",
  92. range,
  93. code,
  94. range.Get(code),
  95. info);
  96. }
  97. }
  98. }
  99. TString TErrorCodeRegistry::ParseNamespace(const std::type_info& errorCodeEnumTypeInfo)
  100. {
  101. TString name;
  102. // Ensures that "EErrorCode" is found as a substring in the type name and stores the prefix before
  103. // the first occurrence into #name.
  104. YT_VERIFY(StringSplitter(
  105. TypeName(errorCodeEnumTypeInfo)).SplitByString("EErrorCode").Limit(2).TryCollectInto(&name, &std::ignore));
  106. // TypeName returns name in form "enum ErrorCode" on Windows
  107. if (name.StartsWith("enum ")) {
  108. name.remove(0, 5);
  109. }
  110. // If the enum was declared directly in the global namespace, #name should be empty.
  111. // Otherwise, #name should end with "::".
  112. if (!name.empty()) {
  113. YT_VERIFY(name.EndsWith("::"));
  114. name.resize(name.size() - 2);
  115. }
  116. return name;
  117. }
  118. void FormatValue(
  119. TStringBuilderBase* builder,
  120. const TErrorCodeRegistry::TErrorCodeInfo& errorCodeInfo,
  121. TStringBuf /*spec*/)
  122. {
  123. if (errorCodeInfo.Namespace.empty()) {
  124. Format(builder, "EErrorCode::%v", errorCodeInfo.Name);
  125. return;
  126. }
  127. Format(builder, "%v::EErrorCode::%v", errorCodeInfo.Namespace, errorCodeInfo.Name);
  128. }
  129. void FormatValue(
  130. TStringBuilderBase* builder,
  131. const TErrorCodeRegistry::TErrorCodeRangeInfo& errorCodeRangeInfo,
  132. TStringBuf /*spec*/)
  133. {
  134. Format(builder, "%v-%v", errorCodeRangeInfo.From, errorCodeRangeInfo.To);
  135. }
  136. ////////////////////////////////////////////////////////////////////////////////
  137. } // namespace NYT