diff options
Diffstat (limited to 'yt')
-rw-r--r-- | yt/yt/core/misc/error.cpp | 74 | ||||
-rw-r--r-- | yt/yt/core/misc/error.h | 3 | ||||
-rw-r--r-- | yt/yt/core/misc/unittests/error_ut.cpp | 61 |
3 files changed, 126 insertions, 12 deletions
diff --git a/yt/yt/core/misc/error.cpp b/yt/yt/core/misc/error.cpp index 4b16e27591..dad759be23 100644 --- a/yt/yt/core/misc/error.cpp +++ b/yt/yt/core/misc/error.cpp @@ -140,6 +140,11 @@ public: Message_ = std::move(message); } + TString* MutableMessage() + { + return &Message_; + } + bool HasOriginAttributes() const { return Host_.operator bool(); @@ -599,10 +604,10 @@ TError TError::Sanitize() const return TError(std::move(result)); } -TError TError::Truncate(int maxInnerErrorCount, i64 stringLimit) const -{ - static const TString InnerErrorsTruncatedKey("inner_errors_truncated"); +const TString InnerErrorsTruncatedKey("inner_errors_truncated"); +TError TError::Truncate(int maxInnerErrorCount, i64 stringLimit) const & +{ if (!Impl_) { return TError(); } @@ -619,16 +624,20 @@ TError TError::Truncate(int maxInnerErrorCount, i64 stringLimit) const }; auto truncateAttributes = [stringLimit] (const IAttributeDictionary& attributes) { - auto clonedAttributes = attributes.Clone(); - for (const auto& key : clonedAttributes->ListKeys()) { - if (std::ssize(clonedAttributes->FindYson(key).AsStringBuf()) > stringLimit) { - clonedAttributes->SetYson( + auto truncatedAttributes = CreateEphemeralAttributes(); + for (const auto& key : attributes.ListKeys()) { + if (const auto& value = attributes.FindYson(key); std::ssize(value.AsStringBuf()) > stringLimit) { + truncatedAttributes->SetYson( key, BuildYsonStringFluently() .Value("...<attribute truncated>...")); + } else { + truncatedAttributes->SetYson( + key, + value); } } - return clonedAttributes; + return truncatedAttributes; }; auto result = std::make_unique<TImpl>(); @@ -654,6 +663,55 @@ TError TError::Truncate(int maxInnerErrorCount, i64 stringLimit) const return TError(std::move(result)); } +TError TError::Truncate(int maxInnerErrorCount, i64 stringLimit) && +{ + if (!Impl_) { + return TError(); + } + + auto truncateInnerError = [=] (TError& innerError) { + innerError = std::move(innerError).Truncate(maxInnerErrorCount, stringLimit); + }; + + auto truncateString = [stringLimit] (TString* string) { + if (std::ssize(*string) > stringLimit) { + *string = Format("%v...<message truncated>", string->substr(0, stringLimit)); + } + }; + + auto truncateAttributes = [stringLimit] (IAttributeDictionary* attributes) { + for (const auto& key : attributes->ListKeys()) { + if (std::ssize(attributes->FindYson(key).AsStringBuf()) > stringLimit) { + attributes->SetYson( + key, + BuildYsonStringFluently() + .Value("...<attribute truncated>...")); + } + } + }; + + truncateString(Impl_->MutableMessage()); + if (Impl_->HasAttributes()) { + truncateAttributes(Impl_->MutableAttributes()); + } + if (std::ssize(InnerErrors()) <= maxInnerErrorCount) { + for (auto& innerError : *MutableInnerErrors()) { + truncateInnerError(innerError); + } + } else { + auto& innerErrors = *MutableInnerErrors(); + MutableAttributes()->Set(InnerErrorsTruncatedKey, true); + for (int i = 0; i + 1 < maxInnerErrorCount; ++i) { + truncateInnerError(innerErrors[i]); + } + truncateInnerError(innerErrors.back()); + innerErrors[maxInnerErrorCount - 1] = std::move(innerErrors.back()); + innerErrors.resize(maxInnerErrorCount); + } + + return std::move(*this); +} + bool TError::IsOK() const { if (!Impl_) { diff --git a/yt/yt/core/misc/error.h b/yt/yt/core/misc/error.h index cdac4ab81e..b4edbf50f4 100644 --- a/yt/yt/core/misc/error.h +++ b/yt/yt/core/misc/error.h @@ -144,7 +144,8 @@ public: // TODO(gritukan): This method is used only outside of YT. Remove it. TError Sanitize() const; - TError Truncate(int maxInnerErrorCount = 2, i64 stringLimit = 16_KB) const; + TError Truncate(int maxInnerErrorCount = 2, i64 stringLimit = 16_KB) const &; + TError Truncate(int maxInnerErrorCount = 2, i64 stringLimit = 16_KB) &&; bool IsOK() const; diff --git a/yt/yt/core/misc/unittests/error_ut.cpp b/yt/yt/core/misc/unittests/error_ut.cpp index 53bd4d434c..22997c5118 100644 --- a/yt/yt/core/misc/unittests/error_ut.cpp +++ b/yt/yt/core/misc/unittests/error_ut.cpp @@ -70,7 +70,8 @@ TEST(TErrorTest, FormatCtor) TEST(TErrorTest, TruncateSimple) { auto error = TError("Some error") - << TErrorAttribute("my_attr", "Attr value"); + << TErrorAttribute("my_attr", "Attr value") + << TError("Inner error"); auto truncatedError = error.Truncate(); EXPECT_EQ(error.GetCode(), truncatedError.GetCode()); EXPECT_EQ(error.GetMessage(), truncatedError.GetMessage()); @@ -79,17 +80,71 @@ TEST(TErrorTest, TruncateSimple) EXPECT_EQ(error.GetSpanId(), truncatedError.GetSpanId()); EXPECT_EQ(error.GetDatetime(), truncatedError.GetDatetime()); EXPECT_EQ(error.Attributes().Get<TString>("my_attr"), truncatedError.Attributes().Get<TString>("my_attr")); + EXPECT_EQ(error.InnerErrors().size(), truncatedError.InnerErrors().size()); + EXPECT_EQ(error.InnerErrors()[0].GetMessage(), truncatedError.InnerErrors()[0].GetMessage()); } TEST(TErrorTest, TruncateLarge) { - auto error = TError("Some long long error"); + auto error = TError("Some long long error") + << TError("First inner error") + << TError("Second inner error") + << TError("Third inner error") + << TError("Fourth inner error"); error.MutableAttributes()->Set("my_attr", "Some long long attr"); - auto truncatedError = error.Truncate(/*maxInnerErrorCount*/ 2, /*stringLimit*/ 10); + auto truncatedError = error.Truncate(/*maxInnerErrorCount*/ 3, /*stringLimit*/ 10); EXPECT_EQ(error.GetCode(), truncatedError.GetCode()); EXPECT_EQ("Some long ...<message truncated>", truncatedError.GetMessage()); EXPECT_EQ("...<attribute truncated>...", truncatedError.Attributes().Get<TString>("my_attr")); + EXPECT_EQ(truncatedError.InnerErrors().size(), 3u); + + EXPECT_EQ("First inne...<message truncated>", truncatedError.InnerErrors()[0].GetMessage()); + EXPECT_EQ("Second inn...<message truncated>", truncatedError.InnerErrors()[1].GetMessage()); + EXPECT_EQ("Fourth inn...<message truncated>", truncatedError.InnerErrors()[2].GetMessage()); +} + +TEST(TErrorTest, TruncateSimpleRValue) +{ + auto error = TError("Some error") + << TErrorAttribute("my_attr", "Attr value") + << TError("Inner error"); + auto errorCopy = error; + auto truncatedError = std::move(errorCopy).Truncate(); + EXPECT_EQ(NYT::EErrorCode::OK, errorCopy.GetCode()); + + EXPECT_EQ(error.GetCode(), truncatedError.GetCode()); + EXPECT_EQ(error.GetMessage(), truncatedError.GetMessage()); + EXPECT_EQ(error.GetPid(), truncatedError.GetPid()); + EXPECT_EQ(error.GetTid(), truncatedError.GetTid()); + EXPECT_EQ(error.GetSpanId(), truncatedError.GetSpanId()); + EXPECT_EQ(error.GetDatetime(), truncatedError.GetDatetime()); + EXPECT_EQ(error.Attributes().Get<TString>("my_attr"), truncatedError.Attributes().Get<TString>("my_attr")); + EXPECT_EQ(error.InnerErrors().size(), truncatedError.InnerErrors().size()); + EXPECT_EQ(error.InnerErrors()[0].GetMessage(), truncatedError.InnerErrors()[0].GetMessage()); +} + +TEST(TErrorTest, TruncateLargeRValue) +{ + auto error = TError("Some long long error") + << TError("First inner error") + << TError("Second inner error") + << TError("Third inner error") + << TError("Fourth inner error"); + error.MutableAttributes()->Set("my_attr", "Some long long attr"); + + auto errorCopy = error; + auto truncatedError = std::move(errorCopy).Truncate(/*maxInnerErrorCount*/ 3, /*stringLimit*/ 10); + EXPECT_EQ(NYT::EErrorCode::OK, errorCopy.GetCode()); + + EXPECT_EQ(error.GetCode(), truncatedError.GetCode()); + EXPECT_EQ("Some long ...<message truncated>", truncatedError.GetMessage()); + EXPECT_EQ("...<attribute truncated>...", truncatedError.Attributes().Get<TString>("my_attr")); + EXPECT_EQ(truncatedError.InnerErrors().size(), 3u); + + EXPECT_EQ("First inne...<message truncated>", truncatedError.InnerErrors()[0].GetMessage()); + EXPECT_EQ("Second inn...<message truncated>", truncatedError.InnerErrors()[1].GetMessage()); + EXPECT_EQ("Fourth inn...<message truncated>", truncatedError.InnerErrors()[2].GetMessage()); } TEST(TErrorTest, YTExceptionToError) |