From 15daadb3720b3d7a38ecba2d2c8d73a5e9ea0f8a Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Sat, 22 Nov 2025 04:27:58 +0900 Subject: [PATCH 01/14] chore: initial draft commit Signed-off-by: Shingo OKAWA From baf3332c65f7c8c46a1f4c5aaa160670dfc9f1b9 Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Tue, 13 Jan 2026 14:44:28 +0900 Subject: [PATCH 02/14] feat/migrate env_logger to tracing Signed-off-by: Shingo OKAWA --- Cargo.lock | 180 ++++++++++++++++++++----- Cargo.toml | 1 + git-cliff-core/Cargo.toml | 5 + git-cliff/Cargo.toml | 6 +- git-cliff/src/logger.rs | 273 +++++++++++++++++++++++--------------- 5 files changed, 321 insertions(+), 144 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5d675478a..4bce764b08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -732,19 +732,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "env_logger" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "equator" version = "0.4.2" @@ -1003,12 +990,12 @@ dependencies = [ "clap_complete", "clap_mangen", "dirs", - "env_logger", "git-cliff-core", "glob", "indicatif", "lazy_static", "log", + "owo-colors", "pathdiff", "pprof", "pretty_assertions", @@ -1017,6 +1004,9 @@ dependencies = [ "reqwest", "secrecy", "shellexpand", + "tracing", + "tracing-indicatif", + "tracing-subscriber", "update-informer", "url", ] @@ -1060,6 +1050,7 @@ dependencies = [ "time", "tokio", "toml", + "tracing", "url", "urlencoding", ] @@ -1284,12 +1275,6 @@ dependencies = [ "libm", ] -[[package]] -name = "humantime" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" - [[package]] name = "hyper" version = "1.7.0" @@ -1552,6 +1537,7 @@ dependencies = [ "portable-atomic", "unicode-width 0.2.2", "unit-prefix", + "vt100", "web-time", ] @@ -1771,6 +1757,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "memchr" version = "2.7.6" @@ -1860,6 +1855,15 @@ dependencies = [ "libc", ] +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -1918,6 +1922,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +[[package]] +name = "owo-colors" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c6901729fa79e91a0913333229e9ca5dc725089d1c363b2f4b4760709dc4a52" + [[package]] name = "parse-zoneinfo" version = "0.3.1" @@ -2713,6 +2723,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shellexpand" version = "3.1.1" @@ -2921,15 +2940,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "terminal_size" version = "0.4.3" @@ -2980,6 +2990,15 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + [[package]] name = "time" version = "0.3.44" @@ -3187,21 +3206,89 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ + "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-indicatif" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1ef6990e0438749f0080573248e96631171a0b5ddfddde119aa5ba8c3a9c47e" +dependencies = [ + "indicatif", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ + "log", "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -3363,6 +3450,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "vcpkg" version = "0.2.15" @@ -3381,6 +3474,27 @@ version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" +[[package]] +name = "vt100" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ff75fb8fa83e609e685106df4faeffdf3a735d3c74ebce97ec557d5d36fd9" +dependencies = [ + "itoa", + "unicode-width 0.2.2", + "vte", +] + +[[package]] +name = "vte" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd" +dependencies = [ + "arrayvec", + "memchr", +] + [[package]] name = "walkdir" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 237458d9df..05df44621b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ reqwest = { version = "0.12.25", default-features = false, features = [ "json", "zstd", ] } +tracing = "0.1.44" [profile.dev] opt-level = 0 diff --git a/git-cliff-core/Cargo.toml b/git-cliff-core/Cargo.toml index 81b218265b..0c0c46baa8 100644 --- a/git-cliff-core/Cargo.toml +++ b/git-cliff-core/Cargo.toml @@ -46,6 +46,10 @@ gitea = ["remote"] ## You can turn this off if you don't use Azure DevOps and don't want ## to make network requests to the Azure DevOps API. azure_devops = ["remote"] +## Enable tracing instrumentation in git-cliff-core. +## This is intentionally feature-gated to keep the core library +## lightweight and to allow downstream users to opt in to tracing. +tracing = ["dep:tracing"] [dependencies] glob.workspace = true @@ -83,6 +87,7 @@ urlencoding = "2.1.3" cacache = { version = "13.1.0", features = ["mmap", "tokio-runtime"], default-features = false } time = "0.3.44" chrono = { version = "0.4.41", features = ["serde"] } +tracing = { workspace = true, optional = true } [dependencies.git2] version = "0.20.3" diff --git a/git-cliff/Cargo.toml b/git-cliff/Cargo.toml index f9dd681e21..26aed30d35 100644 --- a/git-cliff/Cargo.toml +++ b/git-cliff/Cargo.toml @@ -57,15 +57,19 @@ clap_mangen = "0.2.31" shellexpand = "3.1.0" update-informer = { version = "1.3.0", optional = true } indicatif = { version = "0.18.3", optional = true } -env_logger = "=0.10.2" pprof = { version = "0.15.0", optional = true } rand = { version = "0.9.2", optional = true } reqwest = { workspace = true, optional = true } url.workspace = true pathdiff = "0.2.3" +tracing = { workspace = true, features = ["log"] } +tracing-subscriber = { version = "0.3.22", features = ["env-filter", "json"] } +tracing-indicatif = "0.3.14" +owo-colors = "4.2.3" [dependencies.git-cliff-core] version = "2.11.0" # managed by release.sh +features = ["tracing"] path = "../git-cliff-core" [dev-dependencies] diff --git a/git-cliff/src/logger.rs b/git-cliff/src/logger.rs index 6e4e0a29e5..660d691610 100644 --- a/git-cliff/src/logger.rs +++ b/git-cliff/src/logger.rs @@ -1,20 +1,24 @@ -use std::io::Write; +use std::fmt; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::{env, fmt}; -use env_logger::Builder; -use env_logger::fmt::{Color, Style, StyledValue}; use git_cliff_core::error::{Error, Result}; -#[cfg(feature = "remote")] -use indicatif::{ProgressBar, ProgressStyle}; -use log::Level; - -/// Environment variable to use for the logger. -const LOGGER_ENV: &str = "RUST_LOG"; +use indicatif::{ProgressState, ProgressStyle}; +use owo_colors::{OwoColorize, Style, Styled}; +use tracing::{Event, Level, Subscriber}; +use tracing_indicatif::IndicatifLayer; +use tracing_subscriber::fmt::format::{self, FormatEvent, FormatFields}; +use tracing_subscriber::fmt::{FmtContext, FormattedFields}; +use tracing_subscriber::layer::SubscriberExt; +use tracing_subscriber::registry::LookupSpan; +use tracing_subscriber::util::SubscriberInitExt; +use tracing_subscriber::{EnvFilter, Registry}; /// Global variable for storing the maximum width of the modules. static MAX_MODULE_WIDTH: AtomicUsize = AtomicUsize::new(0); +/// Unicode braille spinner frames used by indicatif. +const SPINNER_TICKS: &[&str] = &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]; + /// Wrapper for the padded values. struct Padded { value: T, @@ -38,120 +42,169 @@ fn max_target_width(target: &str) -> usize { } } -/// Adds colors to the given level and returns it. -fn colored_level(style: &mut Style, level: Level) -> StyledValue<'_, &'static str> { - match level { - Level::Trace => style.set_color(Color::Magenta).value("TRACE"), - Level::Debug => style.set_color(Color::Blue).value("DEBUG"), - Level::Info => style.set_color(Color::Green).value("INFO "), - Level::Warn => style.set_color(Color::Yellow).value("WARN "), - Level::Error => style.set_color(Color::Red).value("ERROR"), +/// Adds styles/colors to the given level and returns it. +fn style_level(level: &Level) -> Styled<&'static str> { + match *level { + Level::ERROR => Style::new().red().bold().style("ERROR"), + Level::WARN => Style::new().yellow().bold().style("WARN"), + Level::INFO => Style::new().green().bold().style("INFO"), + Level::DEBUG => Style::new().blue().bold().style("DEBUG"), + Level::TRACE => Style::new().magenta().bold().style("TRACE"), + } +} + +/// Shortens the target string to fit within the specified width. +/// TODO: This function is currently unused but kept for future. +#[allow(dead_code)] +fn shorten_target(target: &str, width: usize) -> String { + if target.len() <= width { + return target.to_string(); + } + let parts: Vec<&str> = target.split("::").collect(); + if parts.len() >= 2 { + format!("{}...{}", parts[0], parts[parts.len() - 1]) + } else { + target.to_string() } } -#[cfg(feature = "remote")] -lazy_static::lazy_static! { - /// Lazily initialized progress bar. - pub static ref PROGRESS_BAR: ProgressBar = { - let progress_bar = ProgressBar::new_spinner(); - progress_bar.set_style( - ProgressStyle::with_template("{spinner:.green} {msg}") - .unwrap() - .tick_strings(&[ - "▹▹▹▹▹", - "▸▹▹▹▹", - "▹▸▹▹▹", - "▹▹▸▹▹", - "▹▹▹▸▹", - "▹▹▹▹▸", - "▪▪▪▪▪", - ]), - ); - progress_bar +/// Formats the elapsed time as `X.Ys` (sub-second precision). +fn elapsed_subsec_key(state: &ProgressState, writer: &mut dyn fmt::Write) { + let seconds = state.elapsed().as_secs(); + let sub_seconds = (state.elapsed().as_millis() % 1000) / 100; + let _ = write!(writer, "{}.{}s", seconds, sub_seconds); +} + +/// Emits an ANSI color escape sequence for the spinner, based on elapsed time. +/// +/// The color gradually transitions: +/// - green -> yellow (0–4s) +/// - yellow -> red (4–8s) +fn color_start_key(state: &ProgressState, writer: &mut dyn fmt::Write) { + let elapsed = state.elapsed().as_secs_f32(); + let t = (elapsed / 8.0).min(1.0); // 8秒で変化 + let (r, g, b) = if t < 0.5 { + let nt = t * 2.0; + (lerp(140, 230, nt), lerp(200, 210, nt), lerp(160, 150, nt)) + } else { + let nt = (t - 0.5) * 2.0; + (lerp(230, 230, nt), lerp(210, 140, nt), lerp(150, 140, nt)) }; + let _ = write!(writer, "\x1b[38;2;{};{};{}m", r, g, b); +} + +/// Performs linear interpolation between two color components. +fn lerp(a: u8, b: u8, t: f32) -> u8 { + (a as f32 + (b as f32 - a as f32) * t) as u8 } -/// Initializes the global logger. +/// Resets ANSI styling to the terminal default. /// -/// This method also creates a progress bar which is triggered -/// by the network operations that are related to GitHub. -#[allow(unreachable_code, clippy::needless_return)] -pub fn init() -> Result<()> { - let mut builder = Builder::new(); - builder.format(move |f, record| { - let target = record.target(); - let max_width = max_target_width(target); - - let mut style = f.style(); - let level = colored_level(&mut style, record.level()); - - let mut style = f.style(); - let target = style.set_bold(true).value(Padded { - value: target, - width: max_width, - }); - - #[cfg(feature = "github")] - { - let message = record.args().to_string(); - if message.starts_with(git_cliff_core::remote::github::START_FETCHING_MSG) { - PROGRESS_BAR.enable_steady_tick(std::time::Duration::from_millis(80)); - PROGRESS_BAR.set_message(message); - return Ok(()); - } else if message.starts_with(git_cliff_core::remote::github::FINISHED_FETCHING_MSG) { - PROGRESS_BAR.finish_and_clear(); - return Ok(()); - } - } +/// This must be paired with `color_start_key` to avoid leaking color state into subsequent log +/// output. +fn color_end_key(_: &ProgressState, writer: &mut dyn fmt::Write) { + let _ = writer.write_str("\x1b[0m"); +} - #[cfg(feature = "gitlab")] - { - let message = record.args().to_string(); - if message.starts_with(git_cliff_core::remote::gitlab::START_FETCHING_MSG) { - PROGRESS_BAR.enable_steady_tick(std::time::Duration::from_millis(80)); - PROGRESS_BAR.set_message(message); - return Ok(()); - } else if message.starts_with(git_cliff_core::remote::gitlab::FINISHED_FETCHING_MSG) { - PROGRESS_BAR.finish_and_clear(); - return Ok(()); - } - } +/// Emits an ANSI escape sequence for dim (muted) foreground text. +fn dim_start_key(_: &ProgressState, writer: &mut dyn fmt::Write) { + let _ = writer.write_str("\x1b[90m"); +} - #[cfg(feature = "gitea")] - { - let message = record.args().to_string(); - if message.starts_with(git_cliff_core::remote::gitea::START_FETCHING_MSG) { - PROGRESS_BAR.enable_steady_tick(std::time::Duration::from_millis(80)); - PROGRESS_BAR.set_message(message); - return Ok(()); - } else if message.starts_with(git_cliff_core::remote::gitea::FINISHED_FETCHING_MSG) { - PROGRESS_BAR.finish_and_clear(); - return Ok(()); - } - } +/// Resets ANSI styling to the terminal default. +/// +/// This must be paired with `dim_start_key` to avoid leaking color state into subsequent log +/// output. +fn dim_end_key(_: &ProgressState, writer: &mut dyn fmt::Write) { + let _ = writer.write_str("\x1b[0m"); +} - #[cfg(feature = "bitbucket")] - { - let message = record.args().to_string(); - if message.starts_with(git_cliff_core::remote::bitbucket::START_FETCHING_MSG) { - PROGRESS_BAR.enable_steady_tick(std::time::Duration::from_millis(80)); - PROGRESS_BAR.set_message(message); - return Ok(()); - } else if message.starts_with(git_cliff_core::remote::bitbucket::FINISHED_FETCHING_MSG) - { - PROGRESS_BAR.finish_and_clear(); - return Ok(()); +/// Builds the `indicatif::ProgressStyle` used for tracing spans. +/// +/// This style: +/// - renders a Unicode spinner for active spans +/// - colorizes the spinner based on elapsed time +/// - shows span name, fields, and wide messages +/// - appends a sub-second elapsed timer +fn indicatif_progress_style() -> ProgressStyle { + ProgressStyle::with_template( + "{span_child_prefix}{color_start}{spinner}{color_end} {dim_start}{span_name} \ + {span_fields} {wide_msg}{dim_end} [{color_start}{elapsed_subsec}{color_end}]", + ) + .unwrap() + .with_key("elapsed_subsec", elapsed_subsec_key) + .with_key("color_start", color_start_key) + .with_key("color_end", color_end_key) + .with_key("dim_start", dim_start_key) + .with_key("eim_end", dim_end_key) + .tick_strings(SPINNER_TICKS) +} + +/// Simple formatter. We format: "LEVEL TARGET > MESSAGE", with a basic padding for target. +struct GitCliffFormatter; + +impl FormatEvent for GitCliffFormatter +where + S: Subscriber + for<'a> LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, +{ + fn format_event( + &self, + ctx: &FmtContext<'_, S, N>, + mut writer: format::Writer<'_>, + event: &Event<'_>, + ) -> fmt::Result { + let metadata = event.metadata(); + let level = style_level(metadata.level()); + let target = metadata.target(); + let max_width = max_target_width(&target); + write!( + &mut writer, + "{} {} > ", + Padded { + value: level, + width: 5, + }, + Padded { + value: target.bright_black().bold(), + width: max_width, + }, + )?; + if let Some(scope) = ctx.event_scope() { + for span in scope.from_root() { + write!(writer, "{}", span.name().bright_black().bold())?; + let ext = span.extensions(); + let fields = &ext + .get::>() + .expect("will never be `None`"); + if !fields.is_empty() { + write!(writer, "{{{}}}", fields)?; + } + write!(writer, "{}", ": ".bright_black().bold())?; } } - - writeln!(f, " {} {} > {}", level, target, record.args()) - }); - - if let Ok(var) = env::var(LOGGER_ENV) { - builder.parse_filters(&var); + ctx.field_format().format_fields(writer.by_ref(), event)?; + writeln!(writer) } +} - builder +/// Initializes the global tracing subscriber. +pub fn init() -> Result<()> { + // Build EnvFilter from `RUST_LOG` or fallback to "info" + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| "info".into()); + let indicatif_layer = IndicatifLayer::new() + .with_progress_style(indicatif_progress_style()) + .with_span_child_prefix_symbol("↳ ") + .with_span_child_prefix_indent(" "); + let fmt_layer = tracing_subscriber::fmt::layer() + .with_writer(indicatif_layer.get_stderr_writer()) + .with_ansi(true) + .event_format(GitCliffFormatter); + let subscriber = Registry::default() + .with(env_filter) + .with(indicatif_layer) + .with(fmt_layer); + subscriber .try_init() .map_err(|e| Error::LoggerError(e.to_string())) } From 5e9d0756536a0f5d7a3e28aec5ef9aeb61211826 Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Tue, 13 Jan 2026 19:41:47 +0900 Subject: [PATCH 03/14] fix: cargo optional dependency Signed-off-by: Shingo OKAWA --- git-cliff/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/git-cliff/Cargo.toml b/git-cliff/Cargo.toml index 26aed30d35..af2bc95f2d 100644 --- a/git-cliff/Cargo.toml +++ b/git-cliff/Cargo.toml @@ -29,7 +29,7 @@ integrations = ["github", "gitlab", "gitea", "bitbucket", "azure_devops"] # inform about new releases update-informer = ["dep:update-informer"] # enable remote repository integration -remote = ["dep:indicatif", "dep:reqwest"] +remote = ["dep:reqwest"] # enable GitHub integration github = ["remote", "git-cliff-core/github"] # enable GitLab integration @@ -56,7 +56,7 @@ clap_complete = "4.5.61" clap_mangen = "0.2.31" shellexpand = "3.1.0" update-informer = { version = "1.3.0", optional = true } -indicatif = { version = "0.18.3", optional = true } +indicatif = "0.18.3" pprof = { version = "0.15.0", optional = true } rand = { version = "0.9.2", optional = true } reqwest = { workspace = true, optional = true } From 1d7f0093d77fd3bb65c1be2f8ce020875695e0e6 Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Tue, 13 Jan 2026 19:51:34 +0900 Subject: [PATCH 04/14] fix: lint Signed-off-by: Shingo OKAWA --- git-cliff/src/logger.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-cliff/src/logger.rs b/git-cliff/src/logger.rs index 660d691610..904607b8d0 100644 --- a/git-cliff/src/logger.rs +++ b/git-cliff/src/logger.rs @@ -157,7 +157,7 @@ where let metadata = event.metadata(); let level = style_level(metadata.level()); let target = metadata.target(); - let max_width = max_target_width(&target); + let max_width = max_target_width(target); write!( &mut writer, "{} {} > ", From d98529441dde1d242b04a083bb653e267d85a05a Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Tue, 13 Jan 2026 20:26:36 +0900 Subject: [PATCH 05/14] feat: add spans to remote module Signed-off-by: Shingo OKAWA --- git-cliff-core/src/remote/azure_devops.rs | 12 ++++++------ git-cliff-core/src/remote/bitbucket.rs | 12 ++++++------ git-cliff-core/src/remote/gitea.rs | 12 ++++++------ git-cliff-core/src/remote/github.rs | 12 ++++++------ git-cliff-core/src/remote/gitlab.rs | 14 ++++++++------ 5 files changed, 32 insertions(+), 30 deletions(-) diff --git a/git-cliff-core/src/remote/azure_devops.rs b/git-cliff-core/src/remote/azure_devops.rs index 4f86de3025..60ae3db1d6 100644 --- a/git-cliff-core/src/remote/azure_devops.rs +++ b/git-cliff-core/src/remote/azure_devops.rs @@ -7,12 +7,6 @@ use super::*; use crate::config::Remote; use crate::error::*; -/// Log message to show while fetching data from Azure DevOps. -pub const START_FETCHING_MSG: &str = "Retrieving data from Azure DevOps..."; - -/// Log message to show when done fetching from Azure DevOps. -pub const FINISHED_FETCHING_MSG: &str = "Done fetching Azure DevOps data."; - /// Template variables related to this remote. pub(crate) const TEMPLATE_VARIABLES: &[&str] = &[ "azure_devops", @@ -187,6 +181,7 @@ impl RemoteClient for AzureDevOpsClient { impl AzureDevOpsClient { /// Constructs the URL for Azure DevOps commits API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn commits_url(api_url: &str, remote: &Remote, ref_name: Option<&str>, page: i32) -> String { let skip = page * MAX_PAGE_SIZE as i32; let mut url = format!( @@ -209,6 +204,7 @@ impl AzureDevOpsClient { } /// Constructs the URL for Azure DevOps pull requests API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn pull_requests_url(api_url: &str, remote: &Remote, page: i32) -> String { let skip = page * MAX_PAGE_SIZE as i32; format!( @@ -225,6 +221,7 @@ impl AzureDevOpsClient { /// Fetches the complete list of commits. /// This is inefficient for large repositories; consider using /// `get_commit_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_commits(&self, ref_name: Option<&str>) -> Result>> { use futures::TryStreamExt; self.get_commit_stream(ref_name).try_collect().await @@ -233,11 +230,13 @@ impl AzureDevOpsClient { /// Fetches the complete list of pull requests. /// This is inefficient for large repositories; consider using /// `get_pull_request_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_pull_requests(&self) -> Result>> { use futures::TryStreamExt; self.get_pull_request_stream().try_collect().await } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_commit_stream<'a>( &'a self, ref_name: Option<&str>, @@ -276,6 +275,7 @@ impl AzureDevOpsClient { } } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_pull_request_stream<'a>( &'a self, ) -> impl Stream>> + 'a { diff --git a/git-cliff-core/src/remote/bitbucket.rs b/git-cliff-core/src/remote/bitbucket.rs index 0c689dc931..2856032657 100644 --- a/git-cliff-core/src/remote/bitbucket.rs +++ b/git-cliff-core/src/remote/bitbucket.rs @@ -7,12 +7,6 @@ use super::*; use crate::config::Remote; use crate::error::*; -/// Log message to show while fetching data from Bitbucket. -pub const START_FETCHING_MSG: &str = "Retrieving data from Bitbucket..."; - -/// Log message to show when done fetching from Bitbucket. -pub const FINISHED_FETCHING_MSG: &str = "Done fetching Bitbucket data."; - /// Template variables related to this remote. pub(crate) const TEMPLATE_VARIABLES: &[&str] = &["bitbucket", "commit.bitbucket", "commit.remote"]; @@ -153,6 +147,7 @@ impl RemoteClient for BitbucketClient { impl BitbucketClient { /// Constructs the URL for Bitbucket commits API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn commits_url(api_url: &str, remote: &Remote, ref_name: Option<&str>, page: i32) -> String { let mut url = format!( "{}/{}/{}/commits?pagelen={MAX_PAGE_SIZE}&page={page}", @@ -167,6 +162,7 @@ impl BitbucketClient { } /// Constructs the URL for Bitbucket pull requests API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn pull_requests_url(api_url: &str, remote: &Remote, page: i32) -> String { format!( "{}/{}/{}/pullrequests?&pagelen={BITBUCKET_MAX_PAGE_PRS}&page={page}&state=MERGED", @@ -177,6 +173,7 @@ impl BitbucketClient { /// Fetches the complete list of commits. /// This is inefficient for large repositories; consider using /// `get_commit_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_commits(&self, ref_name: Option<&str>) -> Result>> { use futures::TryStreamExt; @@ -186,12 +183,14 @@ impl BitbucketClient { /// Fetches the complete list of pull requests. /// This is inefficient for large repositories; consider using /// `get_pull_request_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_pull_requests(&self) -> Result>> { use futures::TryStreamExt; self.get_pull_request_stream().try_collect().await } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_commit_stream<'a>( &'a self, ref_name: Option<&str>, @@ -231,6 +230,7 @@ impl BitbucketClient { } } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_pull_request_stream<'a>( &'a self, ) -> impl Stream>> + 'a { diff --git a/git-cliff-core/src/remote/gitea.rs b/git-cliff-core/src/remote/gitea.rs index fed634089b..57d4afcc5a 100644 --- a/git-cliff-core/src/remote/gitea.rs +++ b/git-cliff-core/src/remote/gitea.rs @@ -7,12 +7,6 @@ use super::*; use crate::config::Remote; use crate::error::*; -/// Log message to show while fetching data from Gitea. -pub const START_FETCHING_MSG: &str = "Retrieving data from Gitea..."; - -/// Log message to show when done fetching from Gitea. -pub const FINISHED_FETCHING_MSG: &str = "Done fetching Gitea data."; - /// Template variables related to this remote. pub(crate) const TEMPLATE_VARIABLES: &[&str] = &["gitea", "commit.gitea", "commit.remote"]; @@ -122,6 +116,7 @@ impl RemoteClient for GiteaClient { impl GiteaClient { /// Constructs the URL for Gitea commits API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn commits_url(api_url: &str, remote: &Remote, ref_name: Option<&str>, page: i32) -> String { let mut url = format!( "{}/api/v1/repos/{}/{}/commits?limit={MAX_PAGE_SIZE}&page={page}", @@ -136,6 +131,7 @@ impl GiteaClient { } /// Constructs the URL for Gitea pull requests API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn pull_requests_url(api_url: &str, remote: &Remote, page: i32) -> String { format!( "{}/api/v1/repos/{}/{}/pulls?limit={MAX_PAGE_SIZE}&page={page}&state=closed", @@ -146,6 +142,7 @@ impl GiteaClient { /// Fetches the complete list of commits. /// This is inefficient for large repositories; consider using /// `get_commit_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_commits(&self, ref_name: Option<&str>) -> Result>> { use futures::TryStreamExt; self.get_commit_stream(ref_name).try_collect().await @@ -154,11 +151,13 @@ impl GiteaClient { /// Fetches the complete list of pull requests. /// This is inefficient for large repositories; consider using /// `get_pull_request_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_pull_requests(&self) -> Result>> { use futures::TryStreamExt; self.get_pull_request_stream().try_collect().await } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_commit_stream<'a>( &'a self, ref_name: Option<&str>, @@ -197,6 +196,7 @@ impl GiteaClient { } } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_pull_request_stream<'a>( &'a self, ) -> impl Stream>> + 'a { diff --git a/git-cliff-core/src/remote/github.rs b/git-cliff-core/src/remote/github.rs index b3820e97ce..58cbb63be4 100644 --- a/git-cliff-core/src/remote/github.rs +++ b/git-cliff-core/src/remote/github.rs @@ -7,12 +7,6 @@ use super::*; use crate::config::Remote; use crate::error::*; -/// Log message to show while fetching data from GitHub. -pub const START_FETCHING_MSG: &str = "Retrieving data from GitHub..."; - -/// Log message to show when done fetching from GitHub. -pub const FINISHED_FETCHING_MSG: &str = "Done fetching GitHub data."; - /// Template variables related to this remote. pub(crate) const TEMPLATE_VARIABLES: &[&str] = &["github", "commit.github", "commit.remote"]; @@ -138,6 +132,7 @@ impl RemoteClient for GitHubClient { impl GitHubClient { /// Constructs the URL for GitHub commits API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn commits_url(api_url: &str, remote: &Remote, ref_name: Option<&str>, page: i32) -> String { let mut url = format!( "{}/repos/{}/{}/commits?per_page={MAX_PAGE_SIZE}&page={page}", @@ -152,6 +147,7 @@ impl GitHubClient { } /// Constructs the URL for GitHub pull requests API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn pull_requests_url(api_url: &str, remote: &Remote, page: i32) -> String { format!( "{}/repos/{}/{}/pulls?per_page={MAX_PAGE_SIZE}&page={page}&state=closed", @@ -162,6 +158,7 @@ impl GitHubClient { /// Fetches the complete list of commits. /// This is inefficient for large repositories; consider using /// `get_commit_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_commits(&self, ref_name: Option<&str>) -> Result>> { use futures::TryStreamExt; self.get_commit_stream(ref_name).try_collect().await @@ -170,11 +167,13 @@ impl GitHubClient { /// Fetches the complete list of pull requests. /// This is inefficient for large repositories; consider using /// `get_pull_request_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_pull_requests(&self) -> Result>> { use futures::TryStreamExt; self.get_pull_request_stream().try_collect().await } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_commit_stream<'a>( &'a self, ref_name: Option<&str>, @@ -213,6 +212,7 @@ impl GitHubClient { } } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_pull_request_stream<'a>( &'a self, ) -> impl Stream>> + 'a { diff --git a/git-cliff-core/src/remote/gitlab.rs b/git-cliff-core/src/remote/gitlab.rs index 06df8fb567..d83c45d7d1 100644 --- a/git-cliff-core/src/remote/gitlab.rs +++ b/git-cliff-core/src/remote/gitlab.rs @@ -7,12 +7,6 @@ use super::*; use crate::config::Remote; use crate::error::*; -/// Log message to show while fetching data from GitLab. -pub const START_FETCHING_MSG: &str = "Retrieving data from GitLab..."; - -/// Log message to show when done fetching from GitLab. -pub const FINISHED_FETCHING_MSG: &str = "Done fetching GitLab data."; - /// Template variables related to this remote. pub(crate) const TEMPLATE_VARIABLES: &[&str] = &["gitlab", "commit.gitlab", "commit.remote"]; @@ -202,6 +196,7 @@ impl RemoteClient for GitLabClient { impl GitLabClient { /// Constructs the URL for GitLab project API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn project_url(api_url: &str, remote: &Remote) -> String { format!( "{}/projects/{}%2F{}", @@ -212,6 +207,7 @@ impl GitLabClient { } /// Constructs the URL for GitLab commits API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn commits_url(project_id: i64, api_url: &str, ref_name: Option<&str>, page: i32) -> String { let mut url = format!( "{api_url}/projects/{project_id}/repository/commits?per_page={MAX_PAGE_SIZE}&\ @@ -225,6 +221,7 @@ impl GitLabClient { url } /// Constructs the URL for GitLab merge requests API. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn pull_requests_url(project_id: i64, api_url: &str, page: i32) -> String { format!( "{api_url}/projects/{project_id}/merge_requests?per_page={MAX_PAGE_SIZE}&page={page}&\ @@ -233,6 +230,7 @@ impl GitLabClient { } /// Looks up the project details. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_project(&self) -> Result { let url = Self::project_url(&self.api_url(), &self.remote()); self.get_json::(&url).await @@ -241,6 +239,7 @@ impl GitLabClient { /// Fetches the complete list of commits. /// This is inefficient for large repositories; consider using /// `get_commit_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_commits( &self, project_id: i64, @@ -255,6 +254,7 @@ impl GitLabClient { /// Fetches the complete list of pull requests. /// This is inefficient for large repositories; consider using /// `get_pull_request_stream` instead. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub async fn get_pull_requests( &self, project_id: i64, @@ -263,6 +263,7 @@ impl GitLabClient { self.get_pull_request_stream(project_id).try_collect().await } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_commit_stream<'a>( &'a self, project_id: i64, @@ -303,6 +304,7 @@ impl GitLabClient { } } + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_pull_request_stream<'a>( &'a self, project_id: i64, From 72f43ca8819a2b1ac7d232cb74fc1488b9ed7624 Mon Sep 17 00:00:00 2001 From: Shingo OKAWA Date: Tue, 13 Jan 2026 20:29:33 +0900 Subject: [PATCH 06/14] feat: add spans to changelog module Signed-off-by: Shingo OKAWA --- git-cliff-core/src/changelog.rs | 77 ++++++++++++++------------------- 1 file changed, 32 insertions(+), 45 deletions(-) diff --git a/git-cliff-core/src/changelog.rs b/git-cliff-core/src/changelog.rs index 91b596acd6..b4a68aba7c 100644 --- a/git-cliff-core/src/changelog.rs +++ b/git-cliff-core/src/changelog.rs @@ -33,6 +33,7 @@ pub struct Changelog<'a> { impl<'a> Changelog<'a> { /// Constructs a new instance. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn new(releases: Vec>, config: Config, range: Option<&str>) -> Result { let is_offline = config.remote.offline; let mut changelog = Changelog::build(releases, config)?; @@ -49,6 +50,7 @@ impl<'a> Changelog<'a> { } /// Builds a changelog from releases and config. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn build(releases: Vec>, config: Config) -> Result { let trim = config.changelog.trim; Ok(Self { @@ -68,6 +70,7 @@ impl<'a> Changelog<'a> { } /// Constructs an instance from a serialized context object. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn from_context(input: &mut R, config: Config) -> Result { Changelog::build(serde_json::from_reader(input)?, config) } @@ -79,6 +82,7 @@ impl<'a> Changelog<'a> { /// # Errors /// /// This operation fails if the deserialization fails. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn add_context( &mut self, key: impl Into, @@ -90,6 +94,7 @@ impl<'a> Changelog<'a> { } /// Processes a single commit and returns/logs the result. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn process_commit(commit: &Commit<'a>, git_config: &GitConfig) -> Option> { match commit.process(git_config) { Ok(commit) => Some(commit), @@ -111,6 +116,7 @@ impl<'a> Changelog<'a> { /// Checks the commits and returns an error if any unconventional commits /// are found. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn check_conventional_commits(commits: &Vec>) -> Result<()> { log::debug!("Verifying that all commits are conventional"); let mut unconventional_count = 0; @@ -139,6 +145,7 @@ impl<'a> Changelog<'a> { /// Checks the commits and returns an error if any commits are not matched /// by any commit parser. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn check_unmatched_commits(commits: &Vec>) -> Result<()> { log::debug!("Verifying that no commits are unmatched by commit parsers"); let mut unmatched_count = 0; @@ -166,6 +173,8 @@ impl<'a> Changelog<'a> { Ok(()) } + /// Processes a commit list by applying parsing, splitting, and validation rules. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn process_commit_list(commits: &mut Vec>, git_config: &GitConfig) -> Result<()> { *commits = commits .iter() @@ -205,6 +214,7 @@ impl<'a> Changelog<'a> { /// Processes the commits and omits the ones that doesn't match the /// criteria set by configuration file. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn process_commits(&mut self) -> Result<()> { log::debug!("Processing the commits"); for release in self.releases.iter_mut() { @@ -217,6 +227,7 @@ impl<'a> Changelog<'a> { } /// Processes the releases and filters them out based on the configuration. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn process_releases(&mut self) { log::debug!("Processing {} release(s)", self.releases.len()); let skip_regex = self.config.git.skip_tags.as_ref(); @@ -282,6 +293,7 @@ impl<'a> Changelog<'a> { /// If no GitHub related variable is used in the template then this function /// returns empty vectors. #[cfg(feature = "github")] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_github_metadata(&self, ref_name: Option<&str>) -> Result { use crate::remote::github; if self.config.remote.github.is_custom || @@ -292,12 +304,7 @@ impl<'a> Changelog<'a> { .is_some_and(|v| v.contains_variable(github::TEMPLATE_VARIABLES)) { let github_client = GitHubClient::try_from(self.config.remote.github.clone())?; - log::info!( - "{} ({})", - github::START_FETCHING_MSG, - self.config.remote.github - ); - let data = tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(async { @@ -308,9 +315,7 @@ impl<'a> Changelog<'a> { log::debug!("Number of GitHub commits: {}", commits.len()); log::debug!("Number of GitHub pull requests: {}", pull_requests.len()); Ok((commits, pull_requests)) - }); - log::info!("{}", github::FINISHED_FETCHING_MSG); - data + }) } else { Ok((vec![], vec![])) } @@ -332,6 +337,7 @@ impl<'a> Changelog<'a> { /// If no GitLab related variable is used in the template then this function /// returns empty vectors. #[cfg(feature = "gitlab")] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_gitlab_metadata(&self, ref_name: Option<&str>) -> Result { use crate::remote::gitlab; if self.config.remote.gitlab.is_custom || @@ -342,12 +348,7 @@ impl<'a> Changelog<'a> { .is_some_and(|v| v.contains_variable(gitlab::TEMPLATE_VARIABLES)) { let gitlab_client = GitLabClient::try_from(self.config.remote.gitlab.clone())?; - log::info!( - "{} ({})", - gitlab::START_FETCHING_MSG, - self.config.remote.gitlab - ); - let data = tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(async { @@ -367,9 +368,7 @@ impl<'a> Changelog<'a> { log::debug!("Number of GitLab commits: {}", commits.len()); log::debug!("Number of GitLab merge requests: {}", merge_requests.len()); Ok((commits, merge_requests)) - }); - log::info!("{}", gitlab::FINISHED_FETCHING_MSG); - data + }) } else { Ok((vec![], vec![])) } @@ -389,6 +388,7 @@ impl<'a> Changelog<'a> { /// If no Gitea related variable is used in the template then this function /// returns empty vectors. #[cfg(feature = "gitea")] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_gitea_metadata(&self, ref_name: Option<&str>) -> Result { use crate::remote::gitea; if self.config.remote.gitea.is_custom || @@ -399,12 +399,7 @@ impl<'a> Changelog<'a> { .is_some_and(|v| v.contains_variable(gitea::TEMPLATE_VARIABLES)) { let gitea_client = GiteaClient::try_from(self.config.remote.gitea.clone())?; - log::info!( - "{} ({})", - gitea::START_FETCHING_MSG, - self.config.remote.gitea - ); - let data = tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(async { @@ -415,9 +410,7 @@ impl<'a> Changelog<'a> { log::debug!("Number of Gitea commits: {}", commits.len()); log::debug!("Number of Gitea pull requests: {}", pull_requests.len()); Ok((commits, pull_requests)) - }); - log::info!("{}", gitea::FINISHED_FETCHING_MSG); - data + }) } else { Ok((vec![], vec![])) } @@ -439,6 +432,7 @@ impl<'a> Changelog<'a> { /// If no bitbucket related variable is used in the template then this /// function returns empty vectors. #[cfg(feature = "bitbucket")] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_bitbucket_metadata( &self, ref_name: Option<&str>, @@ -452,12 +446,7 @@ impl<'a> Changelog<'a> { .is_some_and(|v| v.contains_variable(bitbucket::TEMPLATE_VARIABLES)) { let bitbucket_client = BitbucketClient::try_from(self.config.remote.bitbucket.clone())?; - log::info!( - "{} ({})", - bitbucket::START_FETCHING_MSG, - self.config.remote.bitbucket - ); - let data = tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(async { @@ -468,9 +457,7 @@ impl<'a> Changelog<'a> { log::debug!("Number of Bitbucket commits: {}", commits.len()); log::debug!("Number of Bitbucket pull requests: {}", pull_requests.len()); Ok((commits, pull_requests)) - }); - log::info!("{}", bitbucket::FINISHED_FETCHING_MSG); - data + }) } else { Ok((vec![], vec![])) } @@ -490,6 +477,7 @@ impl<'a> Changelog<'a> { /// If no Azure DevOps related variable is used in the template then this /// function returns empty vectors. #[cfg(feature = "azure_devops")] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_azure_devops_metadata( &self, ref_name: Option<&str>, @@ -504,12 +492,7 @@ impl<'a> Changelog<'a> { { let azure_devops_client = AzureDevOpsClient::try_from(self.config.remote.azure_devops.clone())?; - log::info!( - "{} ({})", - azure_devops::START_FETCHING_MSG, - self.config.remote.azure_devops - ); - let data = tokio::runtime::Builder::new_multi_thread() + tokio::runtime::Builder::new_multi_thread() .enable_all() .build()? .block_on(async { @@ -523,9 +506,7 @@ impl<'a> Changelog<'a> { pull_requests.len() ); Ok((commits, pull_requests)) - }); - log::info!("{}", azure_devops::FINISHED_FETCHING_MSG); - data + }) } else { Ok((vec![], vec![])) } @@ -542,6 +523,7 @@ impl<'a> Changelog<'a> { /// Adds remote data (e.g. GitHub commits) to the releases. #[allow(unused_variables)] + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn add_remote_data(&mut self, range: Option<&str>) -> Result<()> { log::debug!("Adding remote data"); @@ -612,6 +594,7 @@ impl<'a> Changelog<'a> { } /// Increments the version for the unreleased changes based on semver. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn bump_version(&mut self) -> Result> { if let Some(ref mut last_release) = self.releases.iter_mut().next() { if last_release.version.is_none() { @@ -632,6 +615,7 @@ impl<'a> Changelog<'a> { } /// Generates the changelog and writes it to the given output. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn generate(&self, out: &mut W) -> Result<()> { log::debug!("Generating changelog"); let postprocessors = self.config.changelog.postprocessors.clone(); @@ -695,6 +679,7 @@ impl<'a> Changelog<'a> { } /// Generates a changelog and prepends it to the given changelog. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn prepend(&self, mut changelog: String, out: &mut W) -> Result<()> { log::debug!("Generating changelog and prepending"); if let Some(header) = &self.config.changelog.header { @@ -706,6 +691,7 @@ impl<'a> Changelog<'a> { } /// Prints the changelog context to the given output. + #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] pub fn write_context(&self, out: &mut W) -> Result<()> { let output = Releases { releases: &self.releases, @@ -716,6 +702,7 @@ impl<'a> Changelog<'a> { } } +#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))] fn get_body_template(config: &Config, trim: bool) -> Result