aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsvkrasnov <svkrasnov@yandex-team.ru>2022-03-23 14:49:38 +0300
committersvkrasnov <svkrasnov@yandex-team.ru>2022-03-23 14:49:38 +0300
commit0e6dafca9899ab0baf5ec5874ab205f0d8fa7f11 (patch)
tree5ef144b410bbc505a4dd07a3d1cc830d874bc606
parentea82b3450005272f1a406cf1eac7a245c2e7c1ee (diff)
downloadydb-0e6dafca9899ab0baf5ec5874ab205f0d8fa7f11.tar.gz
Introduce FormatCurrentException() based on TBackTrace::FromCurrentException()
ref:60218909c48b580eebc0b518f039afd46ca51713
-rw-r--r--util/generic/yexception.cpp53
-rw-r--r--util/generic/yexception.h12
-rw-r--r--util/generic/yexception_ut.cpp50
3 files changed, 114 insertions, 1 deletions
diff --git a/util/generic/yexception.cpp b/util/generic/yexception.cpp
index 26c75b5f51..ee6d6ebe17 100644
--- a/util/generic/yexception.cpp
+++ b/util/generic/yexception.cpp
@@ -10,8 +10,14 @@
#include <cstdio>
+static void FormatExceptionTo(IOutputStream& out, const std::exception& exception) {
+ out << "(" << TypeName(exception) << ") " << exception.what();
+}
+
TString FormatExc(const std::exception& exception) {
- return TString::Join(TStringBuf("("), TypeName(exception), TStringBuf(") "), exception.what());
+ TStringStream out;
+ FormatExceptionTo(out, exception);
+ return out.Str();
}
TString CurrentExceptionMessage() {
@@ -38,6 +44,51 @@ TString CurrentExceptionMessage() {
return "(NO EXCEPTION)";
}
+Y_DECLARE_UNUSED static void FormatBackTraceTo(IOutputStream& out, const TBackTrace& backtrace) {
+ if (backtrace.size() == 0) {
+ out << "backtrace is empty";
+ return;
+ }
+ try {
+ backtrace.PrintTo(out);
+ } catch (const std::exception& e) {
+ out << "Failed to print backtrace: ";
+ FormatExceptionTo(out, e);
+ }
+}
+
+void FormatCurrentExceptionTo(IOutputStream& out) {
+ auto exceptionPtr = std::current_exception();
+ /*
+ * The lack of current exception indicates a logical bug in the client code.
+ * Do not make any attempts to workaround it, just panic and abort.
+ */
+ Y_VERIFY(exceptionPtr != nullptr, "there is no current exception");
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ TBackTrace backtrace = TBackTrace::FromCurrentException();
+#endif
+ try {
+ std::rethrow_exception(exceptionPtr);
+ } catch (const std::exception& e) {
+ out << "Caught:\n";
+ FormatExceptionTo(out, e);
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ out << "\n\n";
+ FormatBackTraceTo(out, backtrace);
+#endif
+ return;
+ } catch (...) {
+ out << "unknown error";
+ return;
+ }
+}
+
+TString FormatCurrentException() {
+ TStringStream out;
+ FormatCurrentExceptionTo(out);
+ return out.Str();
+}
+
bool UncaughtException() noexcept {
return std::uncaught_exceptions() > 0;
}
diff --git a/util/generic/yexception.h b/util/generic/yexception.h
index b0c604e8c4..660c772061 100644
--- a/util/generic/yexception.h
+++ b/util/generic/yexception.h
@@ -156,6 +156,18 @@ void fputs(const std::exception& e, FILE* f = stderr);
TString CurrentExceptionMessage();
+/**
+ * Formats current exception for logging purposes. Includes formatted backtrace if it is stored
+ * alongside the exception.
+ * The output format is a subject to change, do not depend or canonize it.
+ * The speed of this method is not guaranteed either. Do not call it in hot paths of your code.
+ *
+ * The lack of current exception prior to the invocation indicates logical bug in the client code.
+ * Y_VERIFY asserts the existence of exception, otherwise panic and abort.
+ */
+TString FormatCurrentException();
+void FormatCurrentExceptionTo(IOutputStream& out);
+
/*
* A neat method that detects wrether stack unwinding is in progress.
* As its std counterpart (that is std::uncaught_exception())
diff --git a/util/generic/yexception_ut.cpp b/util/generic/yexception_ut.cpp
index cb3e29fed8..89869fcbe8 100644
--- a/util/generic/yexception_ut.cpp
+++ b/util/generic/yexception_ut.cpp
@@ -15,6 +15,7 @@ static inline void Throw2DontMove() {
#include <util/random/mersenne.h>
#include <util/stream/output.h>
#include <util/string/subst.h>
+#include <util/string/split.h>
#include "yexception_ut.h"
#include "bt_exception.h"
@@ -48,6 +49,10 @@ class TExceptionTest: public TTestBase {
UNIT_TEST(TestBackTrace)
UNIT_TEST(TestEnsureWithBackTrace1)
UNIT_TEST(TestEnsureWithBackTrace2)
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ UNIT_TEST(TestFormatCurrentException)
+ UNIT_TEST(TestFormatCurrentExceptionWithInvalidBacktraceFormatter)
+#endif
UNIT_TEST(TestRethrowAppend)
UNIT_TEST(TestMacroOverload)
UNIT_TEST(TestMessageCrop)
@@ -128,6 +133,51 @@ private:
UNIT_ASSERT(false);
}
+ // TODO(svkrasnov): the output should be canonized after https://st.yandex-team.ru/YMAKE-103
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ void TestFormatCurrentException() {
+ try {
+ throw std::logic_error("some exception"); // is instance of std::exception
+ UNIT_ASSERT(false);
+ } catch (...) {
+ TString exceptionMessage = FormatCurrentException();
+ UNIT_ASSERT(exceptionMessage.Contains("(std::logic_error) some exception"));
+ TVector<TString> backtraceStrs = StringSplitter(exceptionMessage).Split('\n');
+ UNIT_ASSERT(backtraceStrs.size() > 1);
+ }
+ }
+#endif
+
+#ifdef _YNDX_LIBUNWIND_ENABLE_EXCEPTION_BACKTRACE
+ void TestFormatCurrentExceptionWithInvalidBacktraceFormatter() {
+ auto invalidFormatter = [](IOutputStream*, void* const*, size_t) {
+ Throw2DontMove();
+ };
+ SetFormatBackTraceFn(invalidFormatter);
+
+ try {
+ Throw1DontMove();
+ UNIT_ASSERT(false);
+ } catch (...) {
+ TString expected = "Caught:\n"
+ "(yexception) util/generic/yexception_ut.cpp:4: blabla\n\n"
+ "Failed to print backtrace: "
+ "(yexception) util/generic/yexception_ut.cpp:8: 1 qw 12.1";
+ UNIT_ASSERT_EQUAL(FormatCurrentException(), expected);
+ }
+ try {
+ throw std::logic_error("std exception");
+ UNIT_ASSERT(false);
+ } catch (...) {
+ TString expected = "Caught:\n"
+ "(std::logic_error) std exception\n\n"
+ "Failed to print backtrace: "
+ "(yexception) util/generic/yexception_ut.cpp:8: 1 qw 12.1";
+ UNIT_ASSERT_EQUAL(FormatCurrentException(), expected);
+ }
+ }
+#endif
+
inline void TestVirtualInheritance() {
TStringStream ss;