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 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