/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ //! Helpers for components to "handle" errors. /// Describes what error reporting action should be taken. #[derive(Debug, Default)] pub struct ErrorReporting { /// If Some(level), will write a log message at that level. log_level: Option, /// If Some(report_class) will call the error reporter with details. report_class: Option, } /// Specifies how an "internal" error is converted to an "external" public error and /// any logging or reporting that should happen. pub struct ErrorHandling { /// The external error that should be returned. pub err: E, /// How the error should be reported. pub reporting: ErrorReporting, } impl ErrorHandling { /// Create an ErrorHandling instance with an error conversion. /// /// ErrorHandling instance are created using a builder-style API. This is always the first /// function in the chain, optionally followed by `log()`, `report()`, etc. pub fn convert(err: E) -> Self { Self { err, reporting: ErrorReporting::default(), } } /// Add logging to an ErrorHandling instance pub fn log(self, level: log::Level) -> Self { Self { err: self.err, reporting: ErrorReporting { log_level: Some(level), ..self.reporting }, } } /// Add reporting to an ErrorHandling instance pub fn report(self, report_class: impl Into) -> Self { Self { err: self.err, reporting: ErrorReporting { report_class: Some(report_class.into()), ..self.reporting }, } } // Convenience functions for the most common error reports /// log a warning pub fn log_warning(self) -> Self { self.log(log::Level::Warn) } /// log an info pub fn log_info(self) -> Self { self.log(log::Level::Info) } /// Add reporting to an ErrorHandling instance and also log an Error pub fn report_error(self, report_class: impl Into) -> Self { Self { err: self.err, reporting: ErrorReporting { log_level: Some(log::Level::Error), report_class: Some(report_class.into()), }, } } } /// A trait to define how errors are converted and reported. pub trait GetErrorHandling { type ExternalError; /// Return how to handle our internal errors fn get_error_handling(&self) -> ErrorHandling; } /// Handle the specified "internal" error, taking any logging or error /// reporting actions and converting the error to the public error. /// Called by our `handle_error` macro so needs to be public. pub fn convert_log_report_error(e: IE) -> EE where IE: GetErrorHandling + std::error::Error, EE: std::error::Error, { let handling = e.get_error_handling(); let reporting = handling.reporting; if let Some(level) = reporting.log_level { match &reporting.report_class { Some(report_class) => log::log!(level, "{report_class}: {}", e.to_string()), None => log::log!(level, "{}", e.to_string()), } } if let Some(report_class) = reporting.report_class { // notify the error reporter if the feature is enabled. // XXX - should we arrange for the `report_class` to have the // original crate calling this as a prefix, or will we still be // able to identify that? crate::report_error_to_app(report_class, e.to_string()); } handling.err }