1c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko// Copyright 2014 The Chromium OS Authors. All rights reserved.
2c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
3c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko// found in the LICENSE file.
4c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
59ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko#include <brillo/errors/error.h>
6c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
7c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko#include <base/logging.h>
8c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko#include <base/strings/stringprintf.h>
9c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
109ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkousing brillo::Error;
119ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenkousing brillo::ErrorPtr;
12c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
138f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenkonamespace {
148f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenkoinline void LogError(const tracked_objects::Location& location,
158f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                     const std::string& domain,
168f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                     const std::string& code,
178f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                     const std::string& message) {
188f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  // Use logging::LogMessage() directly instead of LOG(ERROR) to substitute
198f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  // the current error location with the location passed in to the Error object.
208f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  // This way the log will contain the actual location of the error, and not
219ed0cab99f18acb3570a35e9408f24355f6b8324Alex Vakulenko  // as if it always comes from brillo/errors/error.cc(22).
2205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  logging::LogMessage(
2305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      location.file_name(), location.line_number(), logging::LOG_ERROR).stream()
248f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko      << location.function_name() << "(...): "
2505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      << "Domain=" << domain << ", Code=" << code << ", Message=" << message;
268f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko}
278f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko}  // anonymous namespace
288f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko
298f815f563c71645fd218977f16de8e746bec28a6Alex VakulenkoErrorPtr Error::Create(const tracked_objects::Location& location,
308f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                       const std::string& domain,
31c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko                       const std::string& code,
32c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko                       const std::string& message) {
338f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  return Create(location, domain, code, message, ErrorPtr());
34c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
35c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
368f815f563c71645fd218977f16de8e746bec28a6Alex VakulenkoErrorPtr Error::Create(const tracked_objects::Location& location,
378f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                       const std::string& domain,
38c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko                       const std::string& code,
39c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko                       const std::string& message,
40c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko                       ErrorPtr inner_error) {
418f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  LogError(location, domain, code, message);
4205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko  return ErrorPtr(
4305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      new Error(location, domain, code, message, std::move(inner_error)));
44c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
45c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
468f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenkovoid Error::AddTo(ErrorPtr* error,
478f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                  const tracked_objects::Location& location,
488f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                  const std::string& domain,
498f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                  const std::string& code,
508f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                  const std::string& message) {
51c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  if (error) {
528f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko    *error = Create(location, domain, code, message, std::move(*error));
53c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  } else {
54c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko    // Create already logs the error, but if |error| is nullptr,
55c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko    // we still want to log the error...
568f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko    LogError(location, domain, code, message);
57c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  }
58c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
59c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
608f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenkovoid Error::AddToPrintf(ErrorPtr* error,
618f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                        const tracked_objects::Location& location,
628f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                        const std::string& domain,
638f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko                        const std::string& code,
6405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                        const char* format,
6505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko                        ...) {
66c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  va_list ap;
67c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  va_start(ap, format);
68c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  std::string message = base::StringPrintV(format, ap);
69c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  va_end(ap);
708f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko  AddTo(error, location, domain, code, message);
71c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
72c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
73c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly BukaErrorPtr Error::Clone() const {
74c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka  ErrorPtr inner_error = inner_error_ ? inner_error_->Clone() : nullptr;
75c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka  return ErrorPtr(
76c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka      new Error(location_, domain_, code_, message_, std::move(inner_error)));
77c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka}
78c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka
79c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenkobool Error::HasDomain(const std::string& domain) const {
80b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  return FindErrorOfDomain(this, domain) != nullptr;
81c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
82c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
83c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenkobool Error::HasError(const std::string& domain, const std::string& code) const {
84b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  return FindError(this, domain, code) != nullptr;
85c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
86c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
87c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenkoconst Error* Error::GetFirstError() const {
88c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  const Error* err = this;
89c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  while (err->GetInnerError())
90c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko    err = err->GetInnerError();
91c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko  return err;
92c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
93c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko
948f815f563c71645fd218977f16de8e746bec28a6Alex VakulenkoError::Error(const tracked_objects::Location& location,
958f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko             const std::string& domain,
96c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka             const std::string& code,
97c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka             const std::string& message,
98c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka             ErrorPtr inner_error)
99c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka    : Error{tracked_objects::LocationSnapshot{location},
100c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka            domain,
101c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka            code,
102c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka            message,
103c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka            std::move(inner_error)} {
104c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka}
105c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka
106c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly BukaError::Error(const tracked_objects::LocationSnapshot& location,
107c345858bb96cd56e3cac717cfc11ef6e8630cd9dVitaly Buka             const std::string& domain,
1088f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko             const std::string& code,
1098f815f563c71645fd218977f16de8e746bec28a6Alex Vakulenko             const std::string& message,
11005d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko             ErrorPtr inner_error)
11105d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko    : domain_(domain),
11205d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      code_(code),
11305d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      message_(message),
11405d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      location_(location),
11505d29044d14a60775ed6c51c75a414eb0cb50347Alex Vakulenko      inner_error_(std::move(inner_error)) {
116c909a9f2ea6f99d0d3ac3efd5ae1114f576cd377Alex Vakulenko}
117b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko
118b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenkoconst Error* Error::FindErrorOfDomain(const Error* error_chain_start,
119b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko                                      const std::string& domain) {
120b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  while (error_chain_start) {
121b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko    if (error_chain_start->GetDomain() == domain)
122b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko      break;
123b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko    error_chain_start = error_chain_start->GetInnerError();
124b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  }
125b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  return error_chain_start;
126b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko}
127b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko
128b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenkoconst Error* Error::FindError(const Error* error_chain_start,
129b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko                              const std::string& domain,
130b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko                              const std::string& code) {
131b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  while (error_chain_start) {
132b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko    if (error_chain_start->GetDomain() == domain &&
133b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko        error_chain_start->GetCode() == code)
134b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko      break;
135b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko    error_chain_start = error_chain_start->GetInnerError();
136b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  }
137b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko  return error_chain_start;
138b068aeb4bc7c638a5a4fe03541f216df8cbc81ebAlex Vakulenko}
139