#![warn(missing_docs)]
#![warn(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
pub mod cache;
pub mod cli;
pub mod config;
pub mod config_reload;
pub mod error;
pub mod metrics;
pub mod server;
pub mod tools;
pub mod utils;
pub use crate::config::{
AppConfig, EnvAppConfig, EnvLoggingConfig, EnvServerConfig, LoggingConfig, PerformanceConfig,
ServerConfig,
};
pub use crate::error::{Error, Result};
pub use crate::server::CratesDocsServer;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub const NAME: &str = "crates-docs";
pub fn init_logging_with_config(config: &crate::config::LoggingConfig) -> Result<()> {
use tracing_subscriber::{fmt, prelude::*, EnvFilter};
macro_rules! fmt_layer {
() => {
fmt::layer()
.with_writer(std::io::stderr)
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.compact()
};
($writer:expr) => {
fmt::layer()
.with_writer($writer)
.with_target(true)
.with_thread_ids(true)
.with_thread_names(true)
.compact()
};
}
macro_rules! try_init {
($subscriber:expr) => {
$subscriber
.try_init()
.map_err(|e| error::Error::initialization("logging", e.to_string()))?
};
}
let level = config.level.to_lowercase();
let level = match level.as_str() {
"trace" | "debug" | "warn" | "error" => level.clone(),
_ => "info".to_string(),
};
let filter = EnvFilter::new(level);
match (config.enable_console, config.enable_file, &config.file_path) {
(true, true, Some(file_path)) => {
let (log_dir, log_file_name) = parse_log_path(file_path);
ensure_log_directory(&log_dir)?;
let file_appender = tracing_appender::rolling::daily(&log_dir, log_file_name);
try_init!(tracing_subscriber::registry()
.with(filter)
.with(fmt_layer!())
.with(fmt_layer!(file_appender)));
}
(false, true, Some(file_path)) => {
let (log_dir, log_file_name) = parse_log_path(file_path);
ensure_log_directory(&log_dir)?;
let file_appender = tracing_appender::rolling::daily(&log_dir, log_file_name);
try_init!(tracing_subscriber::registry()
.with(filter)
.with(fmt_layer!(file_appender)));
}
_ => {
try_init!(tracing_subscriber::registry()
.with(filter)
.with(fmt_layer!()));
}
}
Ok(())
}
fn parse_log_path(file_path: &str) -> (std::path::PathBuf, std::ffi::OsString) {
let path = std::path::Path::new(file_path);
let log_dir = path
.parent()
.filter(|p| !p.as_os_str().is_empty())
.map_or_else(|| std::path::PathBuf::from("."), std::path::PathBuf::from);
let log_file_name = path.file_name().map_or_else(
|| std::ffi::OsString::from("crates-docs.log"),
std::ffi::OsString::from,
);
(log_dir, log_file_name)
}
fn ensure_log_directory(log_dir: &std::path::Path) -> Result<()> {
std::fs::create_dir_all(log_dir).map_err(|e| {
error::Error::initialization("log_directory", format!("Failed to create: {e}"))
})
}