@@ -15,7 +15,197 @@ limitations under the License.
1515
1616#include " research/carls/base/status_helper.h"
1717
18+ #include " absl/status/status.h"
19+ #include " absl/strings/str_cat.h"
20+ #include " tensorflow/core/platform/abi.h"
21+
22+ #if defined(TF_HAS_STACKTRACE)
23+ #include < dlfcn.h>
24+ #include < execinfo.h>
25+ #include < stdio.h>
26+ #include < string.h>
27+ #include < unistd.h>
28+ #endif
29+
1830namespace carls {
31+ namespace internal {
32+ namespace {
33+
34+ static absl::Status MakeStatus (absl::StatusCode code,
35+ const std::string& message) {
36+ return absl::Status (code, message);
37+ }
38+
39+ // Function to create a pretty stacktrace.
40+ inline std::string CurrentStackTrace () {
41+ #if defined(TF_HAS_STACKTRACE)
42+ std::stringstream ss (" " );
43+ ss << " *** Begin stack trace ***" << std::endl;
44+
45+ // Get the mangled stack trace.
46+ int buffer_size = 128 ;
47+ void * trace[128 ];
48+ buffer_size = backtrace (trace, buffer_size);
49+
50+ for (int i = 0 ; i < buffer_size; ++i) {
51+ const char * symbol = " " ;
52+ Dl_info info;
53+ if (dladdr (trace[i], &info)) {
54+ if (info.dli_sname != nullptr ) {
55+ symbol = info.dli_sname ;
56+ }
57+ }
58+
59+ std::string demangled = tensorflow::port::MaybeAbiDemangle (symbol);
60+ if (demangled.length ()) {
61+ ss << " \t " << demangled << std::endl;
62+ } else {
63+ ss << " \t " << symbol << std::endl;
64+ }
65+ }
66+
67+ ss << " *** End stack trace ***" << std::endl;
68+ return ss.str ();
69+ #else
70+ return std::string ();
71+ #endif // defined(TF_HAS_STACKTRACE)
72+ }
73+
74+ // Log the error at the given severity, optionally with a stack trace.
75+ // If log_severity is NUM_SEVERITIES, nothing is logged.
76+ static void LogError (const absl::Status& status, const char * filename, int line,
77+ int log_severity, bool should_log_stack_trace) {
78+ if (TF_PREDICT_TRUE (log_severity != tensorflow::NUM_SEVERITIES)) {
79+ std::string stack_trace;
80+ if (should_log_stack_trace) {
81+ stack_trace = absl::StrCat (" \n " , CurrentStackTrace ());
82+ }
83+ switch (log_severity) {
84+ case tensorflow::INFO:
85+ LOG (INFO) << status << stack_trace;
86+ break ;
87+ case tensorflow::WARNING:
88+ LOG (WARNING) << status << stack_trace;
89+ break ;
90+ case tensorflow::ERROR:
91+ LOG (ERROR) << status << stack_trace;
92+ break ;
93+ case tensorflow::FATAL:
94+ LOG (FATAL) << status << stack_trace;
95+ break ;
96+ case tensorflow::NUM_SEVERITIES:
97+ break ;
98+ default :
99+ LOG (FATAL) << " Unknown LOG severity " << log_severity;
100+ }
101+ }
102+ }
103+
104+ // Make a Status with a code, error message and payload,
105+ // and also send it to LOG(<log_severity>) using the given filename
106+ // and line (unless should_log is false, or log_severity is
107+ // NUM_SEVERITIES). If should_log_stack_trace is true, the stack
108+ // trace is included in the log message (ignored if should_log is
109+ // false).
110+ static absl::Status MakeError (const char * filename, int line,
111+ absl::StatusCode code, const std::string& message,
112+ bool should_log, int log_severity,
113+ bool should_log_stack_trace) {
114+ if (TF_PREDICT_FALSE (code == absl::StatusCode::kOk )) {
115+ LOG (ERROR) << " Cannot create error with status OK" ;
116+ code = absl::StatusCode::kUnknown ;
117+ }
118+ const absl::Status status = MakeStatus (code, message);
119+ if (TF_PREDICT_TRUE (should_log)) {
120+ LogError (status, filename, line, log_severity, should_log_stack_trace);
121+ }
122+ return status;
123+ }
124+
125+ } // namespace
126+
127+ // This method is written out-of-line rather than in the header to avoid
128+ // generating a lot of inline code for error cases in all callers.
129+ void MakeErrorStream::CheckNotDone () const { impl_->CheckNotDone (); }
130+
131+ MakeErrorStream::Impl::Impl (const char * file, int line, absl::StatusCode code,
132+ MakeErrorStream* error_stream,
133+ bool is_logged_by_default)
134+ : file_(file),
135+ line_ (line),
136+ code_(code),
137+ is_done_(false ),
138+ should_log_(is_logged_by_default),
139+ log_severity_(tensorflow::ERROR),
140+ should_log_stack_trace_(false ),
141+ make_error_stream_with_output_wrapper_(error_stream) {}
142+
143+ MakeErrorStream::Impl::Impl (const absl::Status& status,
144+ PriorMessageHandling prior_message_handling,
145+ const char * file, int line,
146+ MakeErrorStream* error_stream)
147+ : file_(file),
148+ line_(line),
149+ // Make sure we show some error, even if the call is incorrect.
150+ code_(!status.ok() ? status.code() : absl::StatusCode::kUnknown),
151+ prior_message_handling_(prior_message_handling),
152+ prior_message_(status.message()),
153+ is_done_(false ),
154+ // Error code type is not visible here, so we can't call
155+ // IsLoggedByDefault.
156+ should_log_(true ),
157+ log_severity_(tensorflow::ERROR),
158+ should_log_stack_trace_(false ),
159+ make_error_stream_with_output_wrapper_(error_stream) {
160+ DCHECK (!status.ok ()) << " Attempted to append/prepend error text to status OK" ;
161+ }
162+
163+ MakeErrorStream::Impl::~Impl () {
164+ // Note: error messages refer to the public MakeErrorStream class.
165+
166+ if (!is_done_) {
167+ LOG (ERROR) << " MakeErrorStream destructed without getting Status: " << file_
168+ << " :" << line_ << " " << stream_.str ();
169+ }
170+ }
171+
172+ absl::Status MakeErrorStream::Impl::GetStatus () {
173+ // Note: error messages refer to the public MakeErrorStream class.
174+
175+ // Getting a Status object out more than once is not harmful, but
176+ // it doesn't match the expected pattern, where the stream is constructed
177+ // as a temporary, loaded with a message, and then casted to Status.
178+ if (is_done_) {
179+ LOG (ERROR) << " MakeErrorStream got Status more than once: " << file_ << " :"
180+ << line_ << " " << stream_.str ();
181+ }
182+
183+ is_done_ = true ;
184+
185+ const std::string& stream_str = stream_.str ();
186+ const std::string str = prior_message_handling_ == kAppendToPriorMessage
187+ ? absl::StrCat (prior_message_, stream_str)
188+ : absl::StrCat (stream_str, prior_message_);
189+ if (TF_PREDICT_FALSE (str.empty ())) {
190+ return MakeError (
191+ file_, line_, code_,
192+ absl::StrCat (str, " Error without message at " , file_, " :" , line_),
193+ true /* should_log */ , tensorflow::ERROR /* log_severity */ ,
194+ should_log_stack_trace_);
195+ } else {
196+ return MakeError (file_, line_, code_, str, should_log_, log_severity_,
197+ should_log_stack_trace_);
198+ }
199+ }
200+
201+ void MakeErrorStream::Impl::CheckNotDone () const {
202+ if (is_done_) {
203+ LOG (ERROR) << " MakeErrorStream shift called after getting Status: " << file_
204+ << " :" << line_ << " " << stream_.str ();
205+ }
206+ }
207+
208+ } // namespace internal
19209
20210absl::Status ToAbslStatus (const grpc::Status& status) {
21211 return absl::Status (static_cast <absl::StatusCode>(status.error_code ()),
0 commit comments