use std::{
net::SocketAddr,
ops::{Deref, DerefMut},
path::PathBuf,
};
use serde::{Deserialize, Serialize};
mod component;
mod endpoint;
#[cfg(feature = "flamegraph")]
mod flame;
#[cfg(feature = "opentelemetry")]
mod otel;
pub use component::Tracing;
pub use endpoint::TracingEndpoint;
#[cfg(feature = "flamegraph")]
pub use flame::{layer, Grapher};
#[derive(Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(
deny_unknown_fields,
default,
from = "InnerConfig",
into = "InnerConfig"
)]
pub struct Config {
inner: InnerConfig,
}
impl Deref for Config {
type Target = InnerConfig;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl DerefMut for Config {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl From<InnerConfig> for Config {
fn from(mut inner: InnerConfig) -> Self {
inner.log_file = runtime_default_log_file(inner.log_file, inner.progress_bar);
Self { inner }
}
}
impl From<Config> for InnerConfig {
fn from(mut config: Config) -> Self {
config.log_file = disk_default_log_file(config.log_file.clone(), config.progress_bar);
config.inner
}
}
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
#[serde(deny_unknown_fields, default)]
pub struct InnerConfig {
pub use_color: bool,
pub force_use_color: bool,
pub filter: Option<String>,
pub buffer_limit: usize,
pub endpoint_addr: Option<SocketAddr>,
pub flamegraph: Option<PathBuf>,
pub progress_bar: Option<ProgressConfig>,
pub log_file: Option<PathBuf>,
pub use_journald: bool,
pub opentelemetry_endpoint: Option<String>,
pub opentelemetry_service_name: Option<String>,
pub opentelemetry_sample_percent: Option<u8>,
}
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum ProgressConfig {
Detailed,
#[default]
#[serde(other)]
Summary,
}
impl Config {
pub fn use_color_stdout(&self) -> bool {
self.force_use_color || (self.use_color && atty::is(atty::Stream::Stdout))
}
pub fn use_color_stderr(&self) -> bool {
self.force_use_color || (self.use_color && atty::is(atty::Stream::Stderr))
}
pub fn use_color_stdout_and_stderr(&self) -> bool {
self.force_use_color
|| (self.use_color && atty::is(atty::Stream::Stdout) && atty::is(atty::Stream::Stderr))
}
}
impl Default for InnerConfig {
fn default() -> Self {
let progress_bar = None;
Self {
use_color: true,
force_use_color: false,
filter: None,
buffer_limit: 128_000,
endpoint_addr: None,
flamegraph: None,
progress_bar,
log_file: runtime_default_log_file(None, progress_bar),
use_journald: false,
opentelemetry_endpoint: None,
opentelemetry_service_name: None,
opentelemetry_sample_percent: None,
}
}
}
fn runtime_default_log_file(
log_file: Option<PathBuf>,
progress_bar: Option<ProgressConfig>,
) -> Option<PathBuf> {
if let Some(log_file) = log_file {
return Some(log_file);
}
if progress_bar.is_some() {
return default_log_file();
}
None
}
fn disk_default_log_file(
log_file: Option<PathBuf>,
progress_bar: Option<ProgressConfig>,
) -> Option<PathBuf> {
if progress_bar.is_some() && log_file == default_log_file() {
return None;
}
log_file
}
fn default_log_file() -> Option<PathBuf> {
dirs::state_dir()
.or_else(dirs::data_local_dir)
.map(|dir| dir.join("zebrad.log"))
}