• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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 #ifndef TENSORFLOW_CORE_PLATFORM_ERRORS_H_
17 #define TENSORFLOW_CORE_PLATFORM_ERRORS_H_
18 
19 #include <sstream>
20 #include <string>
21 #include <utility>
22 
23 #include "absl/strings/str_join.h"
24 #include "tensorflow/core/platform/logging.h"
25 #include "tensorflow/core/platform/macros.h"
26 #include "tensorflow/core/platform/status.h"
27 #include "tensorflow/core/platform/str_util.h"
28 #include "tensorflow/core/platform/strcat.h"
29 
30 namespace tensorflow {
31 namespace errors {
32 
33 typedef ::tensorflow::error::Code Code;
34 
35 namespace internal {
36 
37 // The DECLARE_ERROR macro below only supports types that can be converted
38 // into StrCat's AlphaNum. For the other types we rely on a slower path
39 // through std::stringstream. To add support of a new type, it is enough to
40 // make sure there is an operator<<() for it:
41 //
42 //   std::ostream& operator<<(std::ostream& os, const MyType& foo) {
43 //     os << foo.ToString();
44 //     return os;
45 //   }
46 // Eventually absl::strings will have native support for this and we will be
47 // able to completely remove PrepareForStrCat().
48 template <typename T>
49 typename std::enable_if<!std::is_convertible<T, strings::AlphaNum>::value,
50                         std::string>::type
PrepareForStrCat(const T & t)51 PrepareForStrCat(const T& t) {
52   std::stringstream ss;
53   ss << t;
54   return ss.str();
55 }
PrepareForStrCat(const strings::AlphaNum & a)56 inline const strings::AlphaNum& PrepareForStrCat(const strings::AlphaNum& a) {
57   return a;
58 }
59 
60 }  // namespace internal
61 
62 // Append some context to an error message.  Each time we append
63 // context put it on a new line, since it is possible for there
64 // to be several layers of additional context.
65 template <typename... Args>
AppendToMessage(::tensorflow::Status * status,Args...args)66 void AppendToMessage(::tensorflow::Status* status, Args... args) {
67   std::vector<StackFrame> stack_trace = status->stack_trace();
68   const std::unordered_map<std::string, std::string> payloads =
69       status->GetAllPayloads();
70   *status = ::tensorflow::Status(
71       status->code(),
72       ::tensorflow::strings::StrCat(status->error_message(), "\n\t", args...),
73       std::move(stack_trace));
74   for (const std::pair<const std::string, std::string>& element : payloads) {
75     status->SetPayload(element.first, element.second);
76   }
77 }
78 
79 // For propagating errors when calling a function.
80 #define TF_RETURN_IF_ERROR(...)                          \
81   do {                                                   \
82     ::tensorflow::Status _status = (__VA_ARGS__);        \
83     if (TF_PREDICT_FALSE(!_status.ok())) return _status; \
84   } while (0)
85 
86 #define TF_RETURN_WITH_CONTEXT_IF_ERROR(expr, ...)                  \
87   do {                                                              \
88     ::tensorflow::Status _status = (expr);                          \
89     if (TF_PREDICT_FALSE(!_status.ok())) {                          \
90       ::tensorflow::errors::AppendToMessage(&_status, __VA_ARGS__); \
91       return _status;                                               \
92     }                                                               \
93   } while (0)
94 
95 // Convenience functions for generating and using error status.
96 // Example usage:
97 //   status.Update(errors::InvalidArgument("The ", foo, " isn't right."));
98 //   if (errors::IsInvalidArgument(status)) { ... }
99 //   switch (status.code()) { case error::INVALID_ARGUMENT: ... }
100 
101 #define DECLARE_ERROR(FUNC, CONST)                                       \
102   template <typename... Args>                                            \
103   ::tensorflow::Status FUNC(Args... args) {                              \
104     return ::tensorflow::Status(                                         \
105         ::tensorflow::error::CONST,                                      \
106         ::tensorflow::strings::StrCat(                                   \
107             ::tensorflow::errors::internal::PrepareForStrCat(args)...)); \
108   }                                                                      \
109   inline bool Is##FUNC(const ::tensorflow::Status& status) {             \
110     return status.code() == ::tensorflow::error::CONST;                  \
111   }
112 
DECLARE_ERROR(Cancelled,CANCELLED)113 DECLARE_ERROR(Cancelled, CANCELLED)
114 DECLARE_ERROR(InvalidArgument, INVALID_ARGUMENT)
115 DECLARE_ERROR(NotFound, NOT_FOUND)
116 DECLARE_ERROR(AlreadyExists, ALREADY_EXISTS)
117 DECLARE_ERROR(ResourceExhausted, RESOURCE_EXHAUSTED)
118 DECLARE_ERROR(Unavailable, UNAVAILABLE)
119 DECLARE_ERROR(FailedPrecondition, FAILED_PRECONDITION)
120 DECLARE_ERROR(OutOfRange, OUT_OF_RANGE)
121 DECLARE_ERROR(Unimplemented, UNIMPLEMENTED)
122 DECLARE_ERROR(Internal, INTERNAL)
123 DECLARE_ERROR(Aborted, ABORTED)
124 DECLARE_ERROR(DeadlineExceeded, DEADLINE_EXCEEDED)
125 DECLARE_ERROR(DataLoss, DATA_LOSS)
126 DECLARE_ERROR(Unknown, UNKNOWN)
127 DECLARE_ERROR(PermissionDenied, PERMISSION_DENIED)
128 DECLARE_ERROR(Unauthenticated, UNAUTHENTICATED)
129 
130 #undef DECLARE_ERROR
131 
132 // Produces a formatted string pattern from the name which can uniquely identify
133 // this node upstream to produce an informative error message. The pattern
134 // followed is: {{node <name>}}
135 // Note: The pattern below determines the regex _NODEDEF_NAME_RE in the file
136 // tensorflow/python/client/session.py
137 // LINT.IfChange
138 inline std::string FormatNodeNameForError(const std::string& name) {
139   return strings::StrCat("{{node ", name, "}}");
140 }
141 // LINT.ThenChange(//tensorflow/python/client/session.py)
142 template <typename T>
FormatNodeNamesForError(const T & names)143 std::string FormatNodeNamesForError(const T& names) {
144   return absl::StrJoin(
145       names, ", ", [](std::string* output, const std::string& s) {
146         ::tensorflow::strings::StrAppend(output, FormatNodeNameForError(s));
147       });
148 }
149 // LINT.IfChange
FormatColocationNodeForError(const std::string & name)150 inline std::string FormatColocationNodeForError(const std::string& name) {
151   return strings::StrCat("{{colocation_node ", name, "}}");
152 }
153 // LINT.ThenChange(//tensorflow/python/framework/error_interpolation.py)
154 template <typename T>
FormatColocationNodeForError(const T & names)155 std::string FormatColocationNodeForError(const T& names) {
156   return absl::StrJoin(names, ", ",
157                        [](std::string* output, const std::string& s) {
158                          ::tensorflow::strings::StrAppend(
159                              output, FormatColocationNodeForError(s));
160                        });
161 }
162 
FormatFunctionForError(const std::string & name)163 inline std::string FormatFunctionForError(const std::string& name) {
164   return strings::StrCat("{{function_node ", name, "}}");
165 }
166 
ReplaceErrorFromNonCommunicationOps(const Status s,const std::string & op_name)167 inline Status ReplaceErrorFromNonCommunicationOps(const Status s,
168                                                   const std::string& op_name) {
169   assert(IsUnavailable(s));
170   return Status(
171       error::INTERNAL,
172       strings::StrCat(
173           s.error_message(), "\nExecuting non-communication op <", op_name,
174           "> originally returned UnavailableError, and was replaced by "
175           "InternalError to avoid invoking TF network error handling logic."));
176 }
177 
178 // The CanonicalCode() for non-errors.
179 using ::tensorflow::error::OK;
180 
181 }  // namespace errors
182 }  // namespace tensorflow
183 
184 #endif  // TENSORFLOW_CORE_PLATFORM_ERRORS_H_
185