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