1 // Copyright 2015 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <weave/error.h>
6 
7 #include <base/logging.h>
8 #include <base/strings/stringprintf.h>
9 
10 namespace weave {
11 
12 namespace {
LogError(const tracked_objects::Location & location,const std::string & code,const std::string & message)13 inline void LogError(const tracked_objects::Location& location,
14                      const std::string& code,
15                      const std::string& message) {
16   // Use logging::LogMessage() directly instead of LOG(ERROR) to substitute
17   // the current error location with the location passed in to the Error object.
18   // This way the log will contain the actual location of the error, and not
19   // as if it always comes from chromeos/errors/error.cc(22).
20   logging::LogMessage(location.file_name(), location.line_number(),
21                       logging::LOG_ERROR)
22           .stream()
23       << location.function_name() << "(...): "
24       << "Code=" << code << ", Message=" << message;
25 }
26 }  // anonymous namespace
27 
Create(const tracked_objects::Location & location,const std::string & code,const std::string & message)28 ErrorPtr Error::Create(const tracked_objects::Location& location,
29                        const std::string& code,
30                        const std::string& message) {
31   return Create(location, code, message, ErrorPtr());
32 }
33 
Create(const tracked_objects::Location & location,const std::string & code,const std::string & message,ErrorPtr inner_error)34 ErrorPtr Error::Create(const tracked_objects::Location& location,
35                        const std::string& code,
36                        const std::string& message,
37                        ErrorPtr inner_error) {
38   LogError(location, code, message);
39   return ErrorPtr(new Error(location, code, message, std::move(inner_error)));
40 }
41 
AddTo(ErrorPtr * error,const tracked_objects::Location & location,const std::string & code,const std::string & message)42 Error::AddToTypeProxy Error::AddTo(ErrorPtr* error,
43                                    const tracked_objects::Location& location,
44                                    const std::string& code,
45                                    const std::string& message) {
46   if (error) {
47     *error = Create(location, code, message, std::move(*error));
48   } else {
49     // Create already logs the error, but if |error| is nullptr,
50     // we still want to log the error...
51     LogError(location, code, message);
52   }
53   return {};
54 }
55 
AddToPrintf(ErrorPtr * error,const tracked_objects::Location & location,const std::string & code,const char * format,...)56 Error::AddToTypeProxy Error::AddToPrintf(
57     ErrorPtr* error,
58     const tracked_objects::Location& location,
59     const std::string& code,
60     const char* format,
61     ...) {
62   va_list ap;
63   va_start(ap, format);
64   std::string message = base::StringPrintV(format, ap);
65   va_end(ap);
66   AddTo(error, location, code, message);
67   return {};
68 }
69 
Clone() const70 ErrorPtr Error::Clone() const {
71   ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr;
72   return ErrorPtr(
73       new Error(location_, code_, message_, std::move(inner_error)));
74 }
75 
HasError(const std::string & code) const76 bool Error::HasError(const std::string& code) const {
77   return FindError(this, code) != nullptr;
78 }
79 
GetFirstError() const80 const Error* Error::GetFirstError() const {
81   const Error* err = this;
82   while (err->GetInnerError())
83     err = err->GetInnerError();
84   return err;
85 }
86 
Error(const tracked_objects::Location & location,const std::string & code,const std::string & message,ErrorPtr inner_error)87 Error::Error(const tracked_objects::Location& location,
88              const std::string& code,
89              const std::string& message,
90              ErrorPtr inner_error)
91     : Error{tracked_objects::LocationSnapshot{location}, code, message,
92             std::move(inner_error)} {}
93 
Error(const tracked_objects::LocationSnapshot & location,const std::string & code,const std::string & message,ErrorPtr inner_error)94 Error::Error(const tracked_objects::LocationSnapshot& location,
95              const std::string& code,
96              const std::string& message,
97              ErrorPtr inner_error)
98     : code_(code),
99       message_(message),
100       location_(location),
101       inner_error_(std::move(inner_error)) {}
102 
FindError(const Error * error_chain_start,const std::string & code)103 const Error* Error::FindError(const Error* error_chain_start,
104                               const std::string& code) {
105   while (error_chain_start) {
106     if (error_chain_start->GetCode() == code)
107       break;
108     error_chain_start = error_chain_start->GetInnerError();
109   }
110   return error_chain_start;
111 }
112 
113 }  // namespace weave
114