mirror of
https://gitlab.com/famedly/conduit.git
synced 2025-06-27 16:35:59 +00:00
return a concrete error type from try_main
Also adds a utility for printing out an error message in addition to all of its sources, i.e. errors that came before it that led to the current error. This helps us to provide better error messages to users by including more information: both our own error message and all of the underlying error messages, if any, instead of only one or the other.
This commit is contained in:
parent
5b35b73b56
commit
ecc1bde825
3 changed files with 74 additions and 12 deletions
64
src/error.rs
Normal file
64
src/error.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
//! Error handling facilities
|
||||
|
||||
use std::{fmt, iter};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Wraps any [`Error`][e] type so that [`Display`][d] includes its [sources][s]
|
||||
///
|
||||
/// [e]: std::error::Error
|
||||
/// [d]: fmt::Display
|
||||
/// [s]: std::error::Error::source
|
||||
pub struct Chain<'a>(pub &'a dyn std::error::Error);
|
||||
|
||||
impl fmt::Display for Chain<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.0)?;
|
||||
|
||||
let mut source = self.0.source();
|
||||
|
||||
source
|
||||
.into_iter()
|
||||
.chain(iter::from_fn(|| {
|
||||
source = source.and_then(std::error::Error::source);
|
||||
source
|
||||
}))
|
||||
.try_for_each(|source| write!(f, ": {source}"))
|
||||
}
|
||||
}
|
||||
|
||||
/// Top-level errors
|
||||
// Missing docs are allowed here since that kind of information should be
|
||||
// encoded in the error messages themselves anyway.
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Error, Debug)]
|
||||
pub enum CliError {
|
||||
#[error(
|
||||
"the `CONDUIT_CONFIG` environment variable must either be set to a configuration file path \
|
||||
or set to an empty string to force configuration through environment variables"
|
||||
)]
|
||||
ConfigPathUnset,
|
||||
|
||||
#[error("invalid configuration")]
|
||||
ConfigInvalid(#[from] figment::Error),
|
||||
|
||||
// Upstream's documentation on what this error means is very sparse
|
||||
#[error("opentelemetry error")]
|
||||
Otel(#[from] opentelemetry::trace::TraceError),
|
||||
|
||||
#[error("invalid log filter syntax")]
|
||||
EnvFilter(#[from] tracing_subscriber::filter::ParseError),
|
||||
|
||||
#[error("failed to install global default tracing subscriber")]
|
||||
SetSubscriber(#[from] tracing::subscriber::SetGlobalDefaultError),
|
||||
|
||||
// Upstream's documentation on what this error means is very sparse
|
||||
#[error("tracing_flame error")]
|
||||
TracingFlame(#[from] tracing_flame::Error),
|
||||
|
||||
#[error("failed to load or create the database")]
|
||||
DatabaseError(#[source] crate::utils::error::Error),
|
||||
|
||||
#[error("failed to serve requests")]
|
||||
Serve(#[source] std::io::Error),
|
||||
}
|
|
@ -2,6 +2,7 @@ pub mod api;
|
|||
pub mod clap;
|
||||
mod config;
|
||||
mod database;
|
||||
pub mod error;
|
||||
mod service;
|
||||
mod utils;
|
||||
|
||||
|
|
21
src/main.rs
21
src/main.rs
|
@ -48,25 +48,20 @@ async fn main() -> ExitCode {
|
|||
return ExitCode::SUCCESS;
|
||||
};
|
||||
|
||||
eprintln!("error: {e}");
|
||||
eprintln!("error: {}", error::Chain(&e));
|
||||
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
|
||||
/// Fallible entrypoint
|
||||
async fn try_main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
async fn try_main() -> Result<(), error::CliError> {
|
||||
use error::CliError as Error;
|
||||
|
||||
clap::parse();
|
||||
|
||||
// Initialize config
|
||||
let raw_config = Figment::new()
|
||||
.merge(
|
||||
Toml::file(Env::var("CONDUIT_CONFIG").ok_or(
|
||||
"the `CONDUIT_CONFIG` environment variable must either be set to a \
|
||||
configuration file path or set to the empty string to force configuration \
|
||||
through environment variables",
|
||||
)?)
|
||||
.nested(),
|
||||
)
|
||||
.merge(Toml::file(Env::var("CONDUIT_CONFIG").ok_or(Error::ConfigPathUnset)?).nested())
|
||||
.merge(Env::prefixed("CONDUIT_").global());
|
||||
|
||||
let config = raw_config.extract::<Config>()?;
|
||||
|
@ -116,11 +111,13 @@ async fn try_main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
maximize_fd_limit().expect("should be able to increase the soft limit to the hard limit");
|
||||
|
||||
info!("Loading database");
|
||||
KeyValueDatabase::load_or_create(config).await?;
|
||||
KeyValueDatabase::load_or_create(config)
|
||||
.await
|
||||
.map_err(Error::DatabaseError)?;
|
||||
let config = &services().globals.config;
|
||||
|
||||
info!("Starting server");
|
||||
run_server().await?;
|
||||
run_server().await.map_err(Error::Serve)?;
|
||||
|
||||
if config.allow_jaeger {
|
||||
opentelemetry::global::shutdown_tracer_provider();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue