use abscissa_core::{Component, FrameworkError, FrameworkErrorKind};
use tracing_subscriber::{filter::EnvFilter, util::SubscriberInitExt, FmtSubscriber};
use ibc_relayer::{
config::{GlobalConfig, LogLevel},
util::debug_section::DebugSection,
};
use crate::tracing_handle::ReloadHandle;
use ibc_relayer::config::Error;
const HERMES_LOG_VAR: &str = "RUST_LOG";
#[derive(Component, Debug)]
pub struct JsonTracing;
impl JsonTracing {
pub fn new(cfg: GlobalConfig, debug_sections: &[DebugSection]) -> Result<Self, FrameworkError> {
let filter = build_tracing_filter(cfg.log_level, debug_sections)?;
let use_color = false;
let builder = FmtSubscriber::builder()
.with_target(false)
.with_env_filter(filter)
.with_writer(std::io::stdout)
.with_ansi(use_color)
.with_thread_ids(true)
.json();
let subscriber = builder.finish();
subscriber.init();
Ok(Self)
}
}
#[derive(Component, Debug)]
pub struct PrettyTracing;
impl PrettyTracing {
pub fn new(cfg: GlobalConfig, debug_sections: &[DebugSection]) -> Result<Self, FrameworkError> {
let filter = build_tracing_filter(cfg.log_level, debug_sections)?;
let builder = FmtSubscriber::builder()
.with_target(false)
.with_env_filter(filter)
.with_writer(std::io::stderr)
.with_ansi(enable_ansi())
.with_thread_ids(true);
let subscriber = builder.finish();
subscriber.init();
Ok(Self)
}
pub fn new_with_reload_handle(
cfg: GlobalConfig,
debug_sections: &[DebugSection],
) -> Result<(Self, ReloadHandle<impl tracing::Subscriber + 'static>), FrameworkError> {
let filter = build_tracing_filter(cfg.log_level, debug_sections)?;
let builder = FmtSubscriber::builder()
.with_target(false)
.with_env_filter(filter)
.with_writer(std::io::stderr)
.with_ansi(enable_ansi())
.with_thread_ids(true)
.with_filter_reloading();
let reload_handle = builder.reload_handle();
let subscriber = builder.finish();
subscriber.init();
Ok((Self, reload_handle))
}
}
pub fn enable_ansi() -> bool {
use std::io::IsTerminal;
std::io::stdout().is_terminal() && std::io::stderr().is_terminal()
}
const TARGET_CRATES: [&str; 2] = ["ibc_relayer", "ibc_relayer_cli"];
pub fn default_directive(log_level: LogLevel) -> String {
use itertools::Itertools;
TARGET_CRATES
.iter()
.map(|&c| format!("{c}={log_level}"))
.join(",")
}
fn build_tracing_filter(
default_level: LogLevel,
debug_sections: &[DebugSection],
) -> Result<EnvFilter, FrameworkError> {
let mut directive =
std::env::var(HERMES_LOG_VAR).unwrap_or_else(|_| default_directive(default_level));
if debug_sections.contains(&DebugSection::Rpc) {
directive.push_str(",tendermint_rpc=debug");
}
match EnvFilter::try_new(&directive) {
Ok(out) => Ok(out),
Err(e) => {
eprintln!(
"ERROR: unable to initialize Hermes with log filtering directive {directive:?}: {e}"
);
Err(FrameworkErrorKind::ConfigError
.context(Error::invalid_log_directive(directive, e))
.into())
}
}
}