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 { 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 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 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 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 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 80 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 86 bool Error::HasDomain(const std::string& domain) const { 87 return FindErrorOfDomain(this, domain) != nullptr; 88 } 89 90 bool Error::HasError(const std::string& domain, const std::string& code) const { 91 return FindError(this, domain, code) != nullptr; 92 } 93 94 const Error* Error::GetFirstError() const { 95 const Error* err = this; 96 while (err->GetInnerError()) 97 err = err->GetInnerError(); 98 return err; 99 } 100 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 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 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