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