• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The Chromium OS 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 <brillo/errors/error.h>
6 
7 #include <base/logging.h>
8 #include <base/strings/stringprintf.h>
9 
10 using brillo::Error;
11 using brillo::ErrorPtr;
12 
13 namespace {
LogError(const base::Location & location,const std::string & domain,const std::string & code,const std::string & message)14 inline void LogError(const base::Location& location,
15                      const std::string& domain,
16                      const std::string& code,
17                      const std::string& message) {
18   // Use logging::LogMessage() directly instead of LOG(ERROR) to substitute
19   // the current error location with the location passed in to the Error object.
20   // This way the log will contain the actual location of the error, and not
21   // as if it always comes from brillo/errors/error.cc(22).
22   if (location.function_name() == nullptr) {
23     logging::LogMessage(location.file_name(), location.line_number(),
24                         logging::LOG_ERROR)
25             .stream()
26         << "Domain=" << domain << ", Code=" << code << ", Message=" << message;
27     return;
28   }
29   logging::LogMessage(
30       location.file_name(), location.line_number(), logging::LOG_ERROR).stream()
31       << location.function_name() << "(...): "
32       << "Domain=" << domain << ", Code=" << code << ", Message=" << message;
33 }
34 }  // anonymous namespace
35 
Create(const base::Location & location,const std::string & domain,const std::string & code,const std::string & message)36 ErrorPtr Error::Create(const base::Location& location,
37                        const std::string& domain,
38                        const std::string& code,
39                        const std::string& message) {
40   return Create(location, domain, code, message, ErrorPtr());
41 }
42 
Create(const base::Location & location,const std::string & domain,const std::string & code,const std::string & message,ErrorPtr inner_error)43 ErrorPtr Error::Create(const base::Location& location,
44                        const std::string& domain,
45                        const std::string& code,
46                        const std::string& message,
47                        ErrorPtr inner_error) {
48   LogError(location, domain, code, message);
49   return ErrorPtr(
50       new Error(location, domain, code, message, std::move(inner_error)));
51 }
52 
AddTo(ErrorPtr * error,const base::Location & location,const std::string & domain,const std::string & code,const std::string & message)53 void Error::AddTo(ErrorPtr* error,
54                   const base::Location& location,
55                   const std::string& domain,
56                   const std::string& code,
57                   const std::string& message) {
58   if (error) {
59     *error = Create(location, domain, code, message, std::move(*error));
60   } else {
61     // Create already logs the error, but if |error| is nullptr,
62     // we still want to log the error...
63     LogError(location, domain, code, message);
64   }
65 }
66 
AddToPrintf(ErrorPtr * error,const base::Location & location,const std::string & domain,const std::string & code,const char * format,...)67 void Error::AddToPrintf(ErrorPtr* error,
68                         const base::Location& location,
69                         const std::string& domain,
70                         const std::string& code,
71                         const char* format,
72                         ...) {
73   va_list ap;
74   va_start(ap, format);
75   std::string message = base::StringPrintV(format, ap);
76   va_end(ap);
77   AddTo(error, location, domain, code, message);
78 }
79 
Clone() const80 ErrorPtr Error::Clone() const {
81   ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr;
82   return ErrorPtr(
83       new Error(location_, domain_, code_, message_, std::move(inner_error)));
84 }
85 
HasDomain(const std::string & domain) const86 bool Error::HasDomain(const std::string& domain) const {
87   return FindErrorOfDomain(this, domain) != nullptr;
88 }
89 
HasError(const std::string & domain,const std::string & code) const90 bool Error::HasError(const std::string& domain, const std::string& code) const {
91   return FindError(this, domain, code) != nullptr;
92 }
93 
GetFirstError() const94 const Error* Error::GetFirstError() const {
95   const Error* err = this;
96   while (err->GetInnerError())
97     err = err->GetInnerError();
98   return err;
99 }
100 
Error(const base::Location & location,const std::string & domain,const std::string & code,const std::string & message,ErrorPtr inner_error)101 Error::Error(const base::Location& location,
102              const std::string& domain,
103              const std::string& code,
104              const std::string& message,
105              ErrorPtr inner_error)
106     : domain_(domain),
107       code_(code),
108       message_(message),
109       location_(location),
110       inner_error_(std::move(inner_error)) {
111 }
112 
FindErrorOfDomain(const Error * error_chain_start,const std::string & domain)113 const Error* Error::FindErrorOfDomain(const Error* error_chain_start,
114                                       const std::string& domain) {
115   while (error_chain_start) {
116     if (error_chain_start->GetDomain() == domain)
117       break;
118     error_chain_start = error_chain_start->GetInnerError();
119   }
120   return error_chain_start;
121 }
122 
FindError(const Error * error_chain_start,const std::string & domain,const std::string & code)123 const Error* Error::FindError(const Error* error_chain_start,
124                               const std::string& domain,
125                               const std::string& code) {
126   while (error_chain_start) {
127     if (error_chain_start->GetDomain() == domain &&
128         error_chain_start->GetCode() == code)
129       break;
130     error_chain_start = error_chain_start->GetInnerError();
131   }
132   return error_chain_start;
133 }
134