1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
2
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6
7 http://www.apache.org/licenses/LICENSE-2.0
8
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15
16 #include "tensorflow/compiler/xla/status_macros.h"
17
18 #include <algorithm>
19
20 #include "absl/strings/str_cat.h"
21 #include "tensorflow/compiler/xla/types.h"
22 #include "tensorflow/core/platform/logging.h"
23 #include "tensorflow/core/platform/stacktrace.h"
24
25 namespace xla {
26 namespace status_macros {
27
28 ABSL_CONST_INIT const char kPossibleAutoJitAlternative[] =
29 "This error might be occurring with the use of xla.compile. If it is not "
30 "necessary that every Op be compiled with XLA, an alternative is to use "
31 "auto_jit with OptimizerOptions.global_jit_level = ON_2 or the environment "
32 "variable TF_XLA_FLAGS=\"tf_xla_auto_jit=2\" which will attempt to use xla "
33 "to compile as much of the graph as the compiler is able to.";
34
MakeStatus(tensorflow::error::Code code,const string & message)35 static Status MakeStatus(tensorflow::error::Code code, const string& message) {
36 return Status(code, message);
37 }
38
39 // Log the error at the given severity, optionally with a stack trace.
40 // If log_severity is NUM_SEVERITIES, nothing is logged.
LogError(const Status & status,const char * filename,int line,int log_severity,bool should_log_stack_trace)41 static void LogError(const Status& status, const char* filename, int line,
42 int log_severity, bool should_log_stack_trace) {
43 if (TF_PREDICT_TRUE(log_severity != tensorflow::NUM_SEVERITIES)) {
44 string stack_trace;
45 if (should_log_stack_trace) {
46 stack_trace = absl::StrCat("\n", tensorflow::CurrentStackTrace());
47 }
48 switch (log_severity) {
49 case tensorflow::INFO:
50 LOG(INFO) << status << stack_trace;
51 break;
52 case tensorflow::WARNING:
53 LOG(WARNING) << status << stack_trace;
54 break;
55 case tensorflow::ERROR:
56 LOG(ERROR) << status << stack_trace;
57 break;
58 case tensorflow::FATAL:
59 LOG(FATAL) << status << stack_trace;
60 break;
61 case tensorflow::NUM_SEVERITIES:
62 break;
63 default:
64 LOG(FATAL) << "Unknown LOG severity " << log_severity;
65 }
66 }
67 }
68
69 // Make a Status with a code, error message and payload,
70 // and also send it to LOG(<log_severity>) using the given filename
71 // and line (unless should_log is false, or log_severity is
72 // NUM_SEVERITIES). If should_log_stack_trace is true, the stack
73 // trace is included in the log message (ignored if should_log is
74 // false).
MakeError(const char * filename,int line,tensorflow::error::Code code,const string & message,bool should_log,int log_severity,bool should_log_stack_trace)75 static Status MakeError(const char* filename, int line,
76 tensorflow::error::Code code, const string& message,
77 bool should_log, int log_severity,
78 bool should_log_stack_trace) {
79 if (TF_PREDICT_FALSE(code == tensorflow::error::OK)) {
80 LOG(ERROR) << "Cannot create error with status OK";
81 code = tensorflow::error::UNKNOWN;
82 }
83 const Status status = MakeStatus(code, message);
84 if (TF_PREDICT_TRUE(should_log)) {
85 LogError(status, filename, line, log_severity, should_log_stack_trace);
86 }
87 return status;
88 }
89
90 // This method is written out-of-line rather than in the header to avoid
91 // generating a lot of inline code for error cases in all callers.
CheckNotDone() const92 void MakeErrorStream::CheckNotDone() const { impl_->CheckNotDone(); }
93
Impl(const char * file,int line,tensorflow::error::Code code,MakeErrorStream * error_stream,bool is_logged_by_default)94 MakeErrorStream::Impl::Impl(const char* file, int line,
95 tensorflow::error::Code code,
96 MakeErrorStream* error_stream,
97 bool is_logged_by_default)
98 : file_(file),
99 line_(line),
100 code_(code),
101 is_done_(false),
102 should_log_(is_logged_by_default),
103 log_severity_(tensorflow::ERROR),
104 should_log_stack_trace_(false),
105 make_error_stream_with_output_wrapper_(error_stream) {}
106
Impl(const Status & status,PriorMessageHandling prior_message_handling,const char * file,int line,MakeErrorStream * error_stream)107 MakeErrorStream::Impl::Impl(const Status& status,
108 PriorMessageHandling prior_message_handling,
109 const char* file, int line,
110 MakeErrorStream* error_stream)
111 : file_(file),
112 line_(line),
113 // Make sure we show some error, even if the call is incorrect.
114 code_(!status.ok() ? status.code() : tensorflow::error::UNKNOWN),
115 prior_message_handling_(prior_message_handling),
116 prior_message_(status.error_message()),
117 is_done_(false),
118 // Error code type is not visible here, so we can't call
119 // IsLoggedByDefault.
120 should_log_(true),
121 log_severity_(tensorflow::ERROR),
122 should_log_stack_trace_(false),
123 make_error_stream_with_output_wrapper_(error_stream) {
124 DCHECK(!status.ok()) << "Attempted to append/prepend error text to status OK";
125 }
126
~Impl()127 MakeErrorStream::Impl::~Impl() {
128 // Note: error messages refer to the public MakeErrorStream class.
129
130 if (!is_done_) {
131 LOG(ERROR) << "MakeErrorStream destructed without getting Status: " << file_
132 << ":" << line_ << " " << stream_.str();
133 }
134 }
135
GetStatus()136 Status MakeErrorStream::Impl::GetStatus() {
137 // Note: error messages refer to the public MakeErrorStream class.
138
139 // Getting a Status object out more than once is not harmful, but
140 // it doesn't match the expected pattern, where the stream is constructed
141 // as a temporary, loaded with a message, and then casted to Status.
142 if (is_done_) {
143 LOG(ERROR) << "MakeErrorStream got Status more than once: " << file_ << ":"
144 << line_ << " " << stream_.str();
145 }
146
147 is_done_ = true;
148
149 const string& stream_str = stream_.str();
150 const string str = prior_message_handling_ == kAppendToPriorMessage
151 ? absl::StrCat(prior_message_, stream_str)
152 : absl::StrCat(stream_str, prior_message_);
153 if (TF_PREDICT_FALSE(str.empty())) {
154 return MakeError(
155 file_, line_, code_,
156 absl::StrCat(str, "Error without message at ", file_, ":", line_),
157 true /* should_log */, tensorflow::ERROR /* log_severity */,
158 should_log_stack_trace_);
159 } else {
160 return MakeError(file_, line_, code_, str, should_log_, log_severity_,
161 should_log_stack_trace_);
162 }
163 }
164
CheckNotDone() const165 void MakeErrorStream::Impl::CheckNotDone() const {
166 if (is_done_) {
167 LOG(ERROR) << "MakeErrorStream shift called after getting Status: " << file_
168 << ":" << line_ << " " << stream_.str();
169 }
170 }
171
172 } // namespace status_macros
173 } // namespace xla
174