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 tracked_objects::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 logging::LogMessage( 23 location.file_name(), location.line_number(), logging::LOG_ERROR).stream() 24 << location.function_name() << "(...): " 25 << "Domain=" << domain << ", Code=" << code << ", Message=" << message; 26 } 27 } // anonymous namespace 28 29 ErrorPtr Error::Create(const tracked_objects::Location& location, 30 const std::string& domain, 31 const std::string& code, 32 const std::string& message) { 33 return Create(location, domain, code, message, ErrorPtr()); 34 } 35 36 ErrorPtr Error::Create(const tracked_objects::Location& location, 37 const std::string& domain, 38 const std::string& code, 39 const std::string& message, 40 ErrorPtr inner_error) { 41 LogError(location, domain, code, message); 42 return ErrorPtr( 43 new Error(location, domain, code, message, std::move(inner_error))); 44 } 45 46 void Error::AddTo(ErrorPtr* error, 47 const tracked_objects::Location& location, 48 const std::string& domain, 49 const std::string& code, 50 const std::string& message) { 51 if (error) { 52 *error = Create(location, domain, code, message, std::move(*error)); 53 } else { 54 // Create already logs the error, but if |error| is nullptr, 55 // we still want to log the error... 56 LogError(location, domain, code, message); 57 } 58 } 59 60 void Error::AddToPrintf(ErrorPtr* error, 61 const tracked_objects::Location& location, 62 const std::string& domain, 63 const std::string& code, 64 const char* format, 65 ...) { 66 va_list ap; 67 va_start(ap, format); 68 std::string message = base::StringPrintV(format, ap); 69 va_end(ap); 70 AddTo(error, location, domain, code, message); 71 } 72 73 ErrorPtr Error::Clone() const { 74 ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr; 75 return ErrorPtr( 76 new Error(location_, domain_, code_, message_, std::move(inner_error))); 77 } 78 79 bool Error::HasDomain(const std::string& domain) const { 80 return FindErrorOfDomain(this, domain) != nullptr; 81 } 82 83 bool Error::HasError(const std::string& domain, const std::string& code) const { 84 return FindError(this, domain, code) != nullptr; 85 } 86 87 const Error* Error::GetFirstError() const { 88 const Error* err = this; 89 while (err->GetInnerError()) 90 err = err->GetInnerError(); 91 return err; 92 } 93 94 Error::Error(const tracked_objects::Location& location, 95 const std::string& domain, 96 const std::string& code, 97 const std::string& message, 98 ErrorPtr inner_error) 99 : Error{tracked_objects::LocationSnapshot{location}, 100 domain, 101 code, 102 message, 103 std::move(inner_error)} { 104 } 105 106 Error::Error(const tracked_objects::LocationSnapshot& location, 107 const std::string& domain, 108 const std::string& code, 109 const std::string& message, 110 ErrorPtr inner_error) 111 : domain_(domain), 112 code_(code), 113 message_(message), 114 location_(location), 115 inner_error_(std::move(inner_error)) { 116 } 117 118 const Error* Error::FindErrorOfDomain(const Error* error_chain_start, 119 const std::string& domain) { 120 while (error_chain_start) { 121 if (error_chain_start->GetDomain() == domain) 122 break; 123 error_chain_start = error_chain_start->GetInnerError(); 124 } 125 return error_chain_start; 126 } 127 128 const Error* Error::FindError(const Error* error_chain_start, 129 const std::string& domain, 130 const std::string& code) { 131 while (error_chain_start) { 132 if (error_chain_start->GetDomain() == domain && 133 error_chain_start->GetCode() == code) 134 break; 135 error_chain_start = error_chain_start->GetInnerError(); 136 } 137 return error_chain_start; 138 } 139