123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- #include "error_code.h"
- #include <library/cpp/yt/logging/logger.h>
- #include <library/cpp/yt/misc/global.h>
- #include <util/string/split.h>
- #include <util/system/type_name.h>
- namespace NYT {
- ////////////////////////////////////////////////////////////////////////////////
- // TODO(achulkov2): Remove this once we find all duplicate error codes.
- static YT_DEFINE_GLOBAL(NLogging::TLogger, Logger, "ErrorCode")
- ////////////////////////////////////////////////////////////////////////////////
- bool TErrorCodeRegistry::TErrorCodeInfo::operator==(const TErrorCodeInfo& rhs) const
- {
- return Namespace == rhs.Namespace && Name == rhs.Name;
- }
- TErrorCodeRegistry* TErrorCodeRegistry::Get()
- {
- return LeakySingleton<TErrorCodeRegistry>();
- }
- TErrorCodeRegistry::TErrorCodeInfo TErrorCodeRegistry::Get(int code) const
- {
- auto it = CodeToInfo_.find(code);
- if (it != CodeToInfo_.end()) {
- return it->second;
- }
- for (const auto& range : ErrorCodeRanges_) {
- if (range.Contains(code)) {
- return range.Get(code);
- }
- }
- return {"NUnknown", Format("ErrorCode%v", code)};
- }
- THashMap<int, TErrorCodeRegistry::TErrorCodeInfo> TErrorCodeRegistry::GetAllErrorCodes() const
- {
- return CodeToInfo_;
- }
- std::vector<TErrorCodeRegistry::TErrorCodeRangeInfo> TErrorCodeRegistry::GetAllErrorCodeRanges() const
- {
- return ErrorCodeRanges_;
- }
- void TErrorCodeRegistry::RegisterErrorCode(int code, const TErrorCodeInfo& errorCodeInfo)
- {
- if (!CodeToInfo_.insert({code, errorCodeInfo}).second) {
- // TODO(achulkov2): Deal with duplicate TransportError in NRpc and NBus.
- if (code == 100) {
- return;
- }
- // TODO(yuryalekseev): Deal with duplicate SslError in NRpc and NBus.
- if (code == 119) {
- return;
- }
- YT_LOG_FATAL(
- "Duplicate error code (Code: %v, StoredCodeInfo: %v, NewCodeInfo: %v)",
- code,
- CodeToInfo_[code],
- errorCodeInfo);
- }
- }
- TErrorCodeRegistry::TErrorCodeInfo TErrorCodeRegistry::TErrorCodeRangeInfo::Get(int code) const
- {
- return {Namespace, Formatter(code)};
- }
- bool TErrorCodeRegistry::TErrorCodeRangeInfo::Intersects(const TErrorCodeRangeInfo& other) const
- {
- return std::max(From, other.From) <= std::min(To, other.To);
- }
- bool TErrorCodeRegistry::TErrorCodeRangeInfo::Contains(int value) const
- {
- return From <= value && value <= To;
- }
- void TErrorCodeRegistry::RegisterErrorCodeRange(int from, int to, TString namespaceName, std::function<TString(int)> formatter)
- {
- YT_VERIFY(from <= to);
- TErrorCodeRangeInfo newRange{from, to, std::move(namespaceName), std::move(formatter)};
- for (const auto& range : ErrorCodeRanges_) {
- YT_LOG_FATAL_IF(
- range.Intersects(newRange),
- "Intersecting error code ranges registered (FirstRange: %v, SecondRange: %v)",
- range,
- newRange);
- }
- ErrorCodeRanges_.push_back(std::move(newRange));
- CheckCodesAgainstRanges();
- }
- void TErrorCodeRegistry::CheckCodesAgainstRanges() const
- {
- for (const auto& [code, info] : CodeToInfo_) {
- for (const auto& range : ErrorCodeRanges_) {
- YT_LOG_FATAL_IF(
- range.Contains(code),
- "Error code range contains another registered code "
- "(Range: %v, Code: %v, RangeCodeInfo: %v, StandaloneCodeInfo: %v)",
- range,
- code,
- range.Get(code),
- info);
- }
- }
- }
- TString TErrorCodeRegistry::ParseNamespace(const std::type_info& errorCodeEnumTypeInfo)
- {
- TString name;
- // Ensures that "EErrorCode" is found as a substring in the type name and stores the prefix before
- // the first occurrence into #name.
- YT_VERIFY(StringSplitter(
- TypeName(errorCodeEnumTypeInfo)).SplitByString("EErrorCode").Limit(2).TryCollectInto(&name, &std::ignore));
- // TypeName returns name in form "enum ErrorCode" on Windows
- if (name.StartsWith("enum ")) {
- name.remove(0, 5);
- }
- // If the enum was declared directly in the global namespace, #name should be empty.
- // Otherwise, #name should end with "::".
- if (!name.empty()) {
- YT_VERIFY(name.EndsWith("::"));
- name.resize(name.size() - 2);
- }
- return name;
- }
- void FormatValue(
- TStringBuilderBase* builder,
- const TErrorCodeRegistry::TErrorCodeInfo& errorCodeInfo,
- TStringBuf /*spec*/)
- {
- if (errorCodeInfo.Namespace.empty()) {
- Format(builder, "EErrorCode::%v", errorCodeInfo.Name);
- return;
- }
- Format(builder, "%v::EErrorCode::%v", errorCodeInfo.Namespace, errorCodeInfo.Name);
- }
- void FormatValue(
- TStringBuilderBase* builder,
- const TErrorCodeRegistry::TErrorCodeRangeInfo& errorCodeRangeInfo,
- TStringBuf /*spec*/)
- {
- Format(builder, "%v-%v", errorCodeRangeInfo.From, errorCodeRangeInfo.To);
- }
- ////////////////////////////////////////////////////////////////////////////////
- } // namespace NYT
|