Home | History | Annotate | Download | only in errors
      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