From 3e673ce424b9f7bd5df795954cc95e1cd581dda2 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 12 Sep 2025 06:13:45 -0700 Subject: [PATCH] Switch from log to tracing This switches to using the tracing crate instead of log. Tracing provides a lot of nice features which we can take advantage of moving forward. This also adjusts the output fairly significantly. This includes: - Switched the environment variable from RUST_LOG to MDBOOK_LOG. - Dropped the timestamp. I experimented with various different time displays, but ultimately decided to omit it for now. I don't think I've ever found it to be useful, and it takes up a very significant amount of space. It could potentially be useful for basic profiling, but I think there are other, better mechanisms for that. We could consider leveraging tracing itself for doing some basic profiling (like using something like tracing-chrome). - Dropped the target unless MDBOOK_LOG is set. The target tends to be pretty noisy, and doesn't really convey much information unless you are debugging or otherwise trying to adjust the log output. - Added color. - Slightly reworked the way the error cause trace is displayed. - Slightly changed the way html5ever filtering is done, as well as add handlebars to the list since they both are very noisy. You can override this now by explicitly listing them as targets. I still expect that mdbook will eventually change how it displays things to the console, possibly switching away from tracing and printing things itself. However, that is a larger project for the future. --- Cargo.lock | 166 ++++++++++-------- Cargo.toml | 8 +- crates/mdbook-core/Cargo.toml | 2 +- crates/mdbook-core/src/config.rs | 6 +- crates/mdbook-core/src/utils/fs.rs | 2 +- crates/mdbook-core/src/utils/mod.rs | 9 +- crates/mdbook-driver/Cargo.toml | 2 +- .../src/builtin_preprocessors/cmd.rs | 2 +- .../src/builtin_preprocessors/index.rs | 2 +- .../src/builtin_preprocessors/links.rs | 2 +- .../builtin_renderers/markdown_renderer.rs | 2 +- .../src/builtin_renderers/mod.rs | 4 +- crates/mdbook-driver/src/init.rs | 2 +- crates/mdbook-driver/src/lib.rs | 2 +- crates/mdbook-driver/src/load.rs | 2 +- crates/mdbook-driver/src/mdbook.rs | 4 +- crates/mdbook-html/Cargo.toml | 2 +- .../src/html_handlebars/hbs_renderer.rs | 9 +- .../html_handlebars/helpers/fontawesome.rs | 2 +- .../mdbook-html/src/html_handlebars/search.rs | 2 +- .../src/html_handlebars/static_files.rs | 2 +- crates/mdbook-html/src/theme/mod.rs | 4 +- crates/mdbook-markdown/Cargo.toml | 2 +- crates/mdbook-markdown/src/lib.rs | 7 +- crates/mdbook-summary/Cargo.toml | 2 +- crates/mdbook-summary/src/lib.rs | 2 +- guide/src/for_developers/backends.md | 2 +- src/cmd/build.rs | 1 + src/cmd/init.rs | 1 + src/cmd/serve.rs | 1 + src/cmd/watch.rs | 1 + src/cmd/watch/native.rs | 3 +- src/cmd/watch/poller.rs | 1 + src/main.rs | 56 +++--- tests/testsuite/book_test.rs | 20 +-- tests/testsuite/build.rs | 24 +-- tests/testsuite/config.rs | 16 +- tests/testsuite/includes.rs | 8 +- tests/testsuite/init.rs | 6 +- tests/testsuite/markdown.rs | 14 +- tests/testsuite/preprocessor.rs | 75 ++++---- tests/testsuite/redirects.rs | 18 +- tests/testsuite/renderer.rs | 52 +++--- tests/testsuite/search.rs | 8 +- tests/testsuite/test.rs | 22 +-- tests/testsuite/theme.rs | 32 ++-- 46 files changed, 320 insertions(+), 292 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df36d277..2cc45ea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -559,29 +559,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - [[package]] name = "equivalent" version = "1.0.2" @@ -1132,30 +1109,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "jiff" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "js-sys" version = "0.3.77" @@ -1186,6 +1139,12 @@ dependencies = [ "libc", ] +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.174" @@ -1291,6 +1250,15 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + [[package]] name = "matchit" version = "0.8.4" @@ -1306,11 +1274,9 @@ dependencies = [ "chrono", "clap", "clap_complete", - "env_logger", "futures-util", "glob", "ignore", - "log", "mdbook-core", "mdbook-driver", "mdbook-html", @@ -1331,6 +1297,8 @@ dependencies = [ "tokio", "toml", "tower-http", + "tracing", + "tracing-subscriber", "walkdir", ] @@ -1339,12 +1307,12 @@ name = "mdbook-core" version = "0.5.0-alpha.1" dependencies = [ "anyhow", - "log", "regex", "serde", "serde_json", "tempfile", "toml", + "tracing", ] [[package]] @@ -1353,7 +1321,6 @@ version = "0.5.0-alpha.1" dependencies = [ "anyhow", "indexmap", - "log", "mdbook-core", "mdbook-html", "mdbook-markdown", @@ -1367,6 +1334,7 @@ dependencies = [ "tempfile", "toml", "topological-sort", + "tracing", ] [[package]] @@ -1379,7 +1347,6 @@ dependencies = [ "font-awesome-as-a-crate", "handlebars", "hex", - "log", "mdbook-core", "mdbook-markdown", "mdbook-renderer", @@ -1391,15 +1358,16 @@ dependencies = [ "sha2", "tempfile", "toml", + "tracing", ] [[package]] name = "mdbook-markdown" version = "0.5.0-alpha.1" dependencies = [ - "log", "pulldown-cmark", "regex", + "tracing", ] [[package]] @@ -1437,11 +1405,11 @@ name = "mdbook-summary" version = "0.5.0-alpha.1" dependencies = [ "anyhow", - "log", "mdbook-core", "memchr", "pulldown-cmark", "serde", + "tracing", ] [[package]] @@ -1544,6 +1512,15 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" +[[package]] +name = "nu-ansi-term" +version = "0.50.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "num-modular" version = "0.6.1" @@ -1781,21 +1758,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - [[package]] name = "potential_utf" version = "0.1.2" @@ -2126,6 +2088,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 = "shlex" version = "1.3.0" @@ -2333,6 +2304,15 @@ dependencies = [ "syn 2.0.104", ] +[[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 = "tinystr" version = "0.8.1" @@ -2504,9 +2484,21 @@ checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "tracing-core" version = "0.1.34" @@ -2514,6 +2506,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -2598,6 +2620,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index c458b371..b2710149 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,6 @@ chrono = { version = "0.4.41", default-features = false, features = ["clock"] } clap = { version = "4.5.41", features = ["cargo", "wrap_help"] } clap_complete = "4.5.55" elasticlunr-rs = "3.0.2" -env_logger = "0.11.8" font-awesome-as-a-crate = "0.3.0" futures-util = "0.3.31" glob = "0.3.3" @@ -40,7 +39,6 @@ handlebars = "6.3.2" hex = "0.4.3" indexmap = "2.10.0" ignore = "0.4.23" -log = "0.4.27" mdbook-core = { path = "crates/mdbook-core" } mdbook-driver = { path = "crates/mdbook-driver" } mdbook-html = { path = "crates/mdbook-html" } @@ -68,6 +66,8 @@ tokio = "1.46.1" toml = "0.9.2" topological-sort = "0.2.2" tower-http = "0.6.6" +tracing = "0.1.41" +tracing-subscriber = { version = "0.3.20", features = ["env-filter"] } walkdir = "2.5.0" [package] @@ -93,8 +93,6 @@ anyhow.workspace = true chrono.workspace = true clap.workspace = true clap_complete.workspace = true -env_logger.workspace = true -log.workspace = true mdbook-core.workspace = true mdbook-driver.workspace = true mdbook-html.workspace = true @@ -104,6 +102,8 @@ mdbook-renderer.workspace = true mdbook-summary.workspace = true opener.workspace = true toml.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true # Watch feature ignore = { workspace = true, optional = true } diff --git a/crates/mdbook-core/Cargo.toml b/crates/mdbook-core/Cargo.toml index 6841704b..a964b72a 100644 --- a/crates/mdbook-core/Cargo.toml +++ b/crates/mdbook-core/Cargo.toml @@ -9,11 +9,11 @@ rust-version.workspace = true [dependencies] anyhow.workspace = true -log.workspace = true regex.workspace = true serde.workspace = true serde_json.workspace = true toml.workspace = true +tracing.workspace = true [dev-dependencies] tempfile.workspace = true diff --git a/crates/mdbook-core/src/config.rs b/crates/mdbook-core/src/config.rs index 85319e49..98ca169d 100644 --- a/crates/mdbook-core/src/config.rs +++ b/crates/mdbook-core/src/config.rs @@ -46,7 +46,6 @@ use crate::utils::TomlExt; use crate::utils::log_backtrace; use anyhow::{Context, Error, Result, bail}; -use log::{debug, trace}; use serde::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashMap}; use std::env; @@ -56,6 +55,7 @@ use std::path::{Path, PathBuf}; use std::str::FromStr; use toml::Value; use toml::value::Table; +use tracing::{debug, trace}; /// The overall configuration object for MDBook, essentially an in-memory /// representation of `book.toml`. @@ -162,6 +162,10 @@ impl Config { env::vars().filter_map(|(key, value)| parse_env(&key).map(|index| (index, value))); for (key, value) in overrides { + if key == "log" { + // MDBOOK_LOG is used to control logging. + continue; + } trace!("{} => {}", key, value); let parsed_value = serde_json::from_str(&value) .unwrap_or_else(|_| serde_json::Value::String(value.to_string())); diff --git a/crates/mdbook-core/src/utils/fs.rs b/crates/mdbook-core/src/utils/fs.rs index c8500a73..d32f5705 100644 --- a/crates/mdbook-core/src/utils/fs.rs +++ b/crates/mdbook-core/src/utils/fs.rs @@ -1,10 +1,10 @@ //! Filesystem utilities and helpers. use anyhow::{Context, Result}; -use log::{debug, trace}; use std::fs::{self, File}; use std::io::Write; use std::path::{Component, Path, PathBuf}; +use tracing::{debug, trace}; /// Naively replaces any path separator with a forward-slash '/' pub fn normalize_path(path: &str) -> String { diff --git a/crates/mdbook-core/src/utils/mod.rs b/crates/mdbook-core/src/utils/mod.rs index c36b16e9..1a026f1a 100644 --- a/crates/mdbook-core/src/utils/mod.rs +++ b/crates/mdbook-core/src/utils/mod.rs @@ -1,11 +1,12 @@ //! Various helpers and utilities. use anyhow::Error; -use log::error; use regex::Regex; use std::borrow::Cow; use std::collections::HashMap; +use std::fmt::Write; use std::sync::LazyLock; +use tracing::error; pub mod fs; mod string; @@ -79,11 +80,13 @@ pub fn unique_id_from_content(content: &str, id_counter: &mut HashMap` for HTML. diff --git a/crates/mdbook-driver/Cargo.toml b/crates/mdbook-driver/Cargo.toml index 9f7936a4..9c6281e8 100644 --- a/crates/mdbook-driver/Cargo.toml +++ b/crates/mdbook-driver/Cargo.toml @@ -10,7 +10,6 @@ rust-version.workspace = true [dependencies] anyhow.workspace = true indexmap.workspace = true -log.workspace = true mdbook-core.workspace = true mdbook-html.workspace = true mdbook-markdown.workspace = true @@ -24,6 +23,7 @@ shlex.workspace = true tempfile.workspace = true toml.workspace = true topological-sort.workspace = true +tracing.workspace = true [lints] workspace = true diff --git a/crates/mdbook-driver/src/builtin_preprocessors/cmd.rs b/crates/mdbook-driver/src/builtin_preprocessors/cmd.rs index 498b055d..efd5c4b9 100644 --- a/crates/mdbook-driver/src/builtin_preprocessors/cmd.rs +++ b/crates/mdbook-driver/src/builtin_preprocessors/cmd.rs @@ -1,10 +1,10 @@ use anyhow::{Context, Result, ensure}; -use log::{debug, trace, warn}; use mdbook_core::book::Book; use mdbook_preprocessor::{Preprocessor, PreprocessorContext}; use std::io::Write; use std::path::PathBuf; use std::process::{Child, Stdio}; +use tracing::{debug, trace, warn}; /// A custom preprocessor which will shell out to a 3rd-party program. /// diff --git a/crates/mdbook-driver/src/builtin_preprocessors/index.rs b/crates/mdbook-driver/src/builtin_preprocessors/index.rs index 046b20de..ad353fa3 100644 --- a/crates/mdbook-driver/src/builtin_preprocessors/index.rs +++ b/crates/mdbook-driver/src/builtin_preprocessors/index.rs @@ -1,9 +1,9 @@ use anyhow::Result; -use log::warn; use mdbook_core::book::{Book, BookItem}; use mdbook_preprocessor::{Preprocessor, PreprocessorContext}; use regex::Regex; use std::{path::Path, sync::LazyLock}; +use tracing::warn; /// A preprocessor for converting file name `README.md` to `index.md` since /// `README.md` is the de facto index file in markdown-based documentation. diff --git a/crates/mdbook-driver/src/builtin_preprocessors/links.rs b/crates/mdbook-driver/src/builtin_preprocessors/links.rs index e6466ee9..e68ad9b3 100644 --- a/crates/mdbook-driver/src/builtin_preprocessors/links.rs +++ b/crates/mdbook-driver/src/builtin_preprocessors/links.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Result}; -use log::{error, warn}; use mdbook_core::book::{Book, BookItem}; use mdbook_core::utils::{ take_anchored_lines, take_lines, take_rustdoc_include_anchored_lines, @@ -11,6 +10,7 @@ use std::fs; use std::ops::{Bound, Range, RangeBounds, RangeFrom, RangeFull, RangeTo}; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +use tracing::{error, warn}; const ESCAPE_CHAR: char = '\\'; const MAX_LINK_NESTED_DEPTH: usize = 10; diff --git a/crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs b/crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs index d626cf17..d0f0a744 100644 --- a/crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs +++ b/crates/mdbook-driver/src/builtin_renderers/markdown_renderer.rs @@ -1,9 +1,9 @@ use anyhow::{Context, Result}; -use log::trace; use mdbook_core::book::BookItem; use mdbook_core::utils; use mdbook_renderer::{RenderContext, Renderer}; use std::fs; +use tracing::trace; /// A renderer to output the Markdown after the preprocessors have run. Mostly useful /// when debugging preprocessors. diff --git a/crates/mdbook-driver/src/builtin_renderers/mod.rs b/crates/mdbook-driver/src/builtin_renderers/mod.rs index b319ff1f..65cff5c7 100644 --- a/crates/mdbook-driver/src/builtin_renderers/mod.rs +++ b/crates/mdbook-driver/src/builtin_renderers/mod.rs @@ -3,10 +3,10 @@ //! The HTML renderer can be found in the [`mdbook_html`] crate. use anyhow::{Context, Result, bail}; -use log::{error, info, trace, warn}; use mdbook_renderer::{RenderContext, Renderer}; use std::fs; use std::process::Stdio; +use tracing::{error, info, trace, warn}; pub use self::markdown_renderer::MarkdownRenderer; @@ -30,7 +30,7 @@ mod markdown_renderer; /// whatever it wants, to avoid spamming users it is recommended to avoid /// unnecessary output. /// -/// To help choose the appropriate output level, the `RUST_LOG` environment +/// To help choose the appropriate output level, the `MDBOOK_LOG` environment /// variable will be passed through to the subprocess, if set. /// /// If the subprocess wishes to indicate that rendering failed, it should exit diff --git a/crates/mdbook-driver/src/init.rs b/crates/mdbook-driver/src/init.rs index df5945ca..78a2de63 100644 --- a/crates/mdbook-driver/src/init.rs +++ b/crates/mdbook-driver/src/init.rs @@ -6,10 +6,10 @@ use std::path::PathBuf; use super::MDBook; use anyhow::{Context, Result}; -use log::{debug, error, info, trace}; use mdbook_core::config::Config; use mdbook_core::utils::fs::write_file; use mdbook_html::theme; +use tracing::{debug, error, info, trace}; /// A helper for setting up a new book and its directory structure. #[derive(Debug, Clone, PartialEq)] diff --git a/crates/mdbook-driver/src/lib.rs b/crates/mdbook-driver/src/lib.rs index c2b3123f..f89ef811 100644 --- a/crates/mdbook-driver/src/lib.rs +++ b/crates/mdbook-driver/src/lib.rs @@ -65,12 +65,12 @@ mod load; mod mdbook; use anyhow::{Context, Result, bail}; -use log::{error, warn}; pub use mdbook::MDBook; pub use mdbook_core::{book, config, errors}; use shlex::Shlex; use std::path::{Path, PathBuf}; use std::process::Command; +use tracing::{error, warn}; /// Creates a [`Command`] for command renderers and preprocessors. fn compose_command(cmd: &str, root: &Path) -> Result { diff --git a/crates/mdbook-driver/src/load.rs b/crates/mdbook-driver/src/load.rs index 401f08fc..ab7b13b4 100644 --- a/crates/mdbook-driver/src/load.rs +++ b/crates/mdbook-driver/src/load.rs @@ -1,5 +1,4 @@ use anyhow::{Context, Result}; -use log::debug; use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::config::BuildConfig; use mdbook_core::utils::bracket_escape; @@ -7,6 +6,7 @@ use mdbook_summary::{Link, Summary, SummaryItem, parse_summary}; use std::fs::{self, File}; use std::io::{Read, Write}; use std::path::Path; +use tracing::debug; /// Load a book into memory from its `src/` directory. pub(crate) fn load_book>(src_dir: P, cfg: &BuildConfig) -> Result { diff --git a/crates/mdbook-driver/src/mdbook.rs b/crates/mdbook-driver/src/mdbook.rs index d173502b..27683bd7 100644 --- a/crates/mdbook-driver/src/mdbook.rs +++ b/crates/mdbook-driver/src/mdbook.rs @@ -6,7 +6,6 @@ use crate::init::BookBuilder; use crate::load::{load_book, load_book_from_disk}; use anyhow::{Context, Error, Result, bail}; use indexmap::IndexMap; -use log::{debug, error, info, log_enabled, trace, warn}; use mdbook_core::book::{Book, BookItem, BookItems}; use mdbook_core::config::{Config, RustEdition}; use mdbook_core::utils; @@ -21,6 +20,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use tempfile::Builder as TempFileBuilder; use topological_sort::TopologicalSort; +use tracing::{debug, error, info, trace, warn}; #[cfg(test)] mod tests; @@ -58,7 +58,7 @@ impl MDBook { config.update_from_env(); - if log_enabled!(log::Level::Trace) { + if tracing::enabled!(tracing::Level::TRACE) { for line in format!("Config: {config:#?}").lines() { trace!("{}", line); } diff --git a/crates/mdbook-html/Cargo.toml b/crates/mdbook-html/Cargo.toml index e7b288cc..0b5e5fcb 100644 --- a/crates/mdbook-html/Cargo.toml +++ b/crates/mdbook-html/Cargo.toml @@ -14,7 +14,6 @@ elasticlunr-rs = { workspace = true, optional = true } font-awesome-as-a-crate.workspace = true handlebars.workspace = true hex.workspace = true -log.workspace = true mdbook-core.workspace = true mdbook-markdown.workspace = true mdbook-renderer.workspace = true @@ -23,6 +22,7 @@ regex.workspace = true serde.workspace = true serde_json.workspace = true sha2.workspace = true +tracing.workspace = true [dev-dependencies] pretty_assertions.workspace = true diff --git a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs index 86c16eb1..2fa6efbc 100644 --- a/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs +++ b/crates/mdbook-html/src/html_handlebars/hbs_renderer.rs @@ -3,7 +3,6 @@ use super::static_files::StaticFiles; use crate::theme::Theme; use anyhow::{Context, Result, bail}; use handlebars::Handlebars; -use log::{debug, info, trace, warn}; use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::config::{BookConfig, Code, Config, HtmlConfig, Playground, RustEdition}; use mdbook_core::utils; @@ -18,6 +17,8 @@ use std::collections::HashMap; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +use tracing::error; +use tracing::{debug, info, trace, warn}; /// The HTML renderer for mdBook. #[derive(Default)] @@ -286,7 +287,7 @@ impl HtmlHandlebars { return Ok(()); } - log::debug!("Emitting redirects"); + debug!("Emitting redirects"); let redirects = combine_fragment_redirects(redirects); for (original, (dest, fragment_map)) in redirects { @@ -306,7 +307,7 @@ impl HtmlHandlebars { destination." ); } - log::debug!("Redirecting \"{}\" → \"{}\"", original, dest); + debug!("Redirecting \"{}\" → \"{}\"", original, dest); self.emit_redirect(handlebars, &filename, &dest, &fragment_map)?; } @@ -1034,7 +1035,7 @@ fn combine_fragment_redirects(redirects: &HashMap) -> CombinedRe if let Some((source_path, source_fragment)) = original.rsplit_once('#') { let e = combined.entry(source_path.to_string()).or_default(); if let Some(old) = e.1.insert(format!("#{source_fragment}"), new.clone()) { - log::error!( + error!( "internal error: found duplicate fragment redirect \ {old} for {source_path}#{source_fragment}" ); diff --git a/crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs b/crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs index f1b04c03..3ece0973 100644 --- a/crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs +++ b/crates/mdbook-html/src/html_handlebars/helpers/fontawesome.rs @@ -2,8 +2,8 @@ use font_awesome_as_a_crate as fa; use handlebars::{ Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason, }; -use log::trace; use std::str::FromStr; +use tracing::trace; pub(crate) fn fa_helper( h: &Helper<'_>, diff --git a/crates/mdbook-html/src/html_handlebars/search.rs b/crates/mdbook-html/src/html_handlebars/search.rs index a424f801..9575ea31 100644 --- a/crates/mdbook-html/src/html_handlebars/search.rs +++ b/crates/mdbook-html/src/html_handlebars/search.rs @@ -2,7 +2,6 @@ use super::static_files::StaticFiles; use crate::theme::searcher; use anyhow::{Context, Result, bail}; use elasticlunr::{Index, IndexBuilder}; -use log::{debug, warn}; use mdbook_core::book::{Book, BookItem, Chapter}; use mdbook_core::config::{Search, SearchChapterSettings}; use mdbook_core::utils; @@ -14,6 +13,7 @@ use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +use tracing::{debug, warn}; const MAX_WORD_LENGTH_TO_INDEX: usize = 80; diff --git a/crates/mdbook-html/src/html_handlebars/static_files.rs b/crates/mdbook-html/src/html_handlebars/static_files.rs index 8c370214..62f07f50 100644 --- a/crates/mdbook-html/src/html_handlebars/static_files.rs +++ b/crates/mdbook-html/src/html_handlebars/static_files.rs @@ -3,7 +3,6 @@ use super::helpers::resources::ResourceHelper; use crate::theme::{self, Theme, playground_editor}; use anyhow::{Context, Result}; -use log::debug; use mdbook_core::config::HtmlConfig; use mdbook_core::utils; use std::borrow::Cow; @@ -11,6 +10,7 @@ use std::collections::HashMap; use std::fs::{self, File}; use std::path::{Path, PathBuf}; use std::sync::LazyLock; +use tracing::debug; /// Map static files to their final names and contents. /// diff --git a/crates/mdbook-html/src/theme/mod.rs b/crates/mdbook-html/src/theme/mod.rs index e863f283..ab5b0fb2 100644 --- a/crates/mdbook-html/src/theme/mod.rs +++ b/crates/mdbook-html/src/theme/mod.rs @@ -1,10 +1,10 @@ #![allow(missing_docs)] use anyhow::Result; -use log::warn; use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; +use tracing::{info, warn}; pub mod fonts; pub mod playground_editor; @@ -133,7 +133,7 @@ impl Theme { if entry.file_name() == "fonts.css" { None } else if entry.file_type().ok()?.is_dir() { - log::info!("skipping font directory {:?}", entry.path()); + info!("skipping font directory {:?}", entry.path()); None } else { Some(entry.path()) diff --git a/crates/mdbook-markdown/Cargo.toml b/crates/mdbook-markdown/Cargo.toml index 0dc3e723..f6414074 100644 --- a/crates/mdbook-markdown/Cargo.toml +++ b/crates/mdbook-markdown/Cargo.toml @@ -8,9 +8,9 @@ repository.workspace = true rust-version.workspace = true [dependencies] -log.workspace = true pulldown-cmark.workspace = true regex.workspace = true +tracing.workspace = true [lints] workspace = true diff --git a/crates/mdbook-markdown/src/lib.rs b/crates/mdbook-markdown/src/lib.rs index dda97757..22c11f8a 100644 --- a/crates/mdbook-markdown/src/lib.rs +++ b/crates/mdbook-markdown/src/lib.rs @@ -15,6 +15,7 @@ use std::collections::HashMap; use std::fmt::Write; use std::path::Path; use std::sync::LazyLock; +use tracing::warn; #[doc(inline)] pub use pulldown_cmark; @@ -126,7 +127,7 @@ pub fn render_markdown(text: &str, options: &HtmlRenderOptions<'_>) -> String { Event::Start(Tag::FootnoteDefinition(name)) => { prev_was_footnote = false; if !in_footnote.is_empty() { - log::warn!( + warn!( "internal bug: nested footnote not expected in {:?}", options.path ); @@ -139,7 +140,7 @@ pub fn render_markdown(text: &str, options: &HtmlRenderOptions<'_>) -> String { let name = std::mem::take(&mut in_footnote_name); if footnote_defs.contains_key(&name) { - log::warn!( + warn!( "footnote `{name}` in {} defined multiple times - \ not updating to new definition", options.path.display() @@ -212,7 +213,7 @@ fn add_footnote_defs( // Remove unused. defs.retain(|(name, _)| { if !numbers.contains_key(name) { - log::warn!( + warn!( "footnote `{name}` in `{}` is defined but not referenced", options.path.display() ); diff --git a/crates/mdbook-summary/Cargo.toml b/crates/mdbook-summary/Cargo.toml index 4d52abb2..d6b8e4a2 100644 --- a/crates/mdbook-summary/Cargo.toml +++ b/crates/mdbook-summary/Cargo.toml @@ -9,11 +9,11 @@ rust-version.workspace = true [dependencies] anyhow.workspace = true -log.workspace = true mdbook-core.workspace = true memchr.workspace = true pulldown-cmark.workspace = true serde.workspace = true +tracing.workspace = true [lints] workspace = true diff --git a/crates/mdbook-summary/src/lib.rs b/crates/mdbook-summary/src/lib.rs index 2039a63e..9cf959f5 100644 --- a/crates/mdbook-summary/src/lib.rs +++ b/crates/mdbook-summary/src/lib.rs @@ -5,7 +5,6 @@ //! file structure for [mdBook](https://rust-lang.github.io/mdBook/). use anyhow::{Context, Error, Result, bail}; -use log::{debug, trace, warn}; pub use mdbook_core::book::SectionNumber; use memchr::Memchr; use pulldown_cmark::{DefaultBrokenLinkCallback, Event, HeadingLevel, Tag, TagEnd}; @@ -13,6 +12,7 @@ use serde::{Deserialize, Serialize}; use std::collections::HashSet; use std::fmt::Display; use std::path::{Path, PathBuf}; +use tracing::{debug, trace, warn}; /// Parse the text from a `SUMMARY.md` file into a sort of "recipe" to be /// used when loading a book from disk. diff --git a/guide/src/for_developers/backends.md b/guide/src/for_developers/backends.md index 1c0dc40e..2ab3b3b7 100644 --- a/guide/src/for_developers/backends.md +++ b/guide/src/for_developers/backends.md @@ -317,7 +317,7 @@ the "rule of silence" and only generate output when necessary (e.g. an error in generation or a warning). All environment variables are passed through to the backend, allowing you to use -the usual `RUST_LOG` to control logging verbosity. +the usual `MDBOOK_LOG` to control logging verbosity. ## Wrapping up diff --git a/src/cmd/build.rs b/src/cmd/build.rs index b4ac4857..41536cae 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -2,6 +2,7 @@ use super::command_prelude::*; use crate::{get_book_dir, open}; use anyhow::Result; use mdbook_driver::MDBook; +use tracing::error; // Create clap subcommand arguments pub fn make_subcommand() -> Command { diff --git a/src/cmd/init.rs b/src/cmd/init.rs index 9b0c35bc..df018257 100644 --- a/src/cmd/init.rs +++ b/src/cmd/init.rs @@ -6,6 +6,7 @@ use mdbook_driver::MDBook; use std::io; use std::io::Write; use std::process::Command; +use tracing::debug; // Create clap subcommand arguments pub fn make_subcommand() -> ClapCommand { diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 6d8a0616..7bb216da 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -15,6 +15,7 @@ use std::net::{SocketAddr, ToSocketAddrs}; use std::path::PathBuf; use tokio::sync::broadcast; use tower_http::services::{ServeDir, ServeFile}; +use tracing::{error, info, trace}; /// The HTTP endpoint for the websocket used to trigger reloads when a file changes. const LIVE_RELOAD_ENDPOINT: &str = "__livereload"; diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index bd9c19b2..0c6fa87c 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -3,6 +3,7 @@ use crate::{get_book_dir, open}; use anyhow::Result; use mdbook_driver::MDBook; use std::path::{Path, PathBuf}; +use tracing::error; mod native; mod poller; diff --git a/src/cmd/watch/native.rs b/src/cmd/watch/native.rs index 0eb04e0a..b4cbc9a7 100644 --- a/src/cmd/watch/native.rs +++ b/src/cmd/watch/native.rs @@ -6,6 +6,7 @@ use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::thread::sleep; use std::time::Duration; +use tracing::{error, info, warn}; pub fn rebuild_on_change( book_dir: &Path, @@ -71,7 +72,7 @@ pub fn rebuild_on_change( .filter_map(|event| match event { Ok(events) => Some(events), Err(error) => { - log::warn!("error while watching for changes: {error}"); + warn!("error while watching for changes: {error}"); None } }) diff --git a/src/cmd/watch/poller.rs b/src/cmd/watch/poller.rs index 65a51188..666a6c77 100644 --- a/src/cmd/watch/poller.rs +++ b/src/cmd/watch/poller.rs @@ -11,6 +11,7 @@ use std::collections::HashMap; use std::fs::FileType; use std::path::{Path, PathBuf}; use std::time::{Duration, Instant, SystemTime}; +use tracing::{debug, error, info, trace, warn}; use walkdir::WalkDir; /// Calls the closure when a book source file is changed, blocking indefinitely. diff --git a/src/main.rs b/src/main.rs index b35d0019..2bd83425 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,20 +4,15 @@ #[macro_use] extern crate clap; -#[macro_use] -extern crate log; use anyhow::anyhow; -use chrono::Local; use clap::{Arg, ArgMatches, Command}; use clap_complete::Shell; -use env_logger::Builder; -use log::LevelFilter; use mdbook_core::utils; use std::env; use std::ffi::OsStr; -use std::io::Write; use std::path::PathBuf; +use tracing::{error, info}; mod cmd; @@ -99,29 +94,36 @@ fn create_clap_command() -> Command { } fn init_logger() { - let mut builder = Builder::new(); + let filter = tracing_subscriber::EnvFilter::builder() + .with_env_var("MDBOOK_LOG") + .with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into()) + .from_env_lossy(); + let log_env = std::env::var("MDBOOK_LOG"); + // Silence some particularly noisy dependencies unless the user + // specifically asks for them. + let silence_unless_specified = |filter: tracing_subscriber::EnvFilter, target| { + if !log_env.as_ref().map_or(false, |s| { + s.split(',').any(|directive| directive.starts_with(target)) + }) { + filter.add_directive(format!("{target}=warn").parse().unwrap()) + } else { + filter + } + }; + let filter = silence_unless_specified(filter, "handlebars"); + let filter = silence_unless_specified(filter, "html5ever"); - builder.format(|formatter, record| { - writeln!( - formatter, - "{} [{}] ({}): {}", - Local::now().format("%Y-%m-%d %H:%M:%S"), - record.level(), - record.target(), - record.args() - ) - }); + // Don't show the target by default, since it generally isn't useful + // unless you are overriding the level. + let with_target = log_env.is_ok(); - if let Ok(var) = env::var("RUST_LOG") { - builder.parse_filters(&var); - } else { - // if no RUST_LOG provided, default to logging at the Info level - builder.filter(None, LevelFilter::Info); - // Filter extraneous html5ever not-implemented messages - builder.filter(Some("html5ever"), LevelFilter::Error); - } - - builder.init(); + tracing_subscriber::fmt() + .without_time() + .with_ansi(std::io::IsTerminal::is_terminal(&std::io::stderr())) + .with_writer(std::io::stderr) + .with_env_filter(filter) + .with_target(with_target) + .init(); } fn get_book_dir(args: &ArgMatches) -> PathBuf { diff --git a/tests/testsuite/book_test.rs b/tests/testsuite/book_test.rs index 5b7369d8..5b9db068 100644 --- a/tests/testsuite/book_test.rs +++ b/tests/testsuite/book_test.rs @@ -360,7 +360,7 @@ impl BookCommand { /// Use this to debug a command. /// - /// Pass the value that you would normally pass to `RUST_LOG`, and this + /// Pass the value that you would normally pass to `MDBOOK_LOG`, and this /// will enable logging, print the command that runs and its output. /// /// This will fail if you use it in CI. @@ -378,7 +378,7 @@ impl BookCommand { let mut cmd = Command::new(env!("CARGO_BIN_EXE_mdbook")); cmd.current_dir(&self.dir) .args(&self.args) - .env_remove("RUST_LOG") + .env_remove("MDBOOK_LOG") // Don't read the system git config which is out of our control. .env("GIT_CONFIG_NOSYSTEM", "1") .env("GIT_CONFIG_GLOBAL", &self.dir) @@ -389,7 +389,7 @@ impl BookCommand { .env_remove("GIT_COMMITTER_NAME"); if let Some(debug) = &self.debug { - cmd.env("RUST_LOG", debug); + cmd.env("MDBOOK_LOG", debug); } for (k, v) in &self.env { @@ -479,23 +479,9 @@ static LITERAL_REDACTIONS: &[(&str, &str)] = &[ ("[EXE]", std::env::consts::EXE_SUFFIX), ]; -/// This makes it easier to write regex replacements that are guaranteed to only -/// get compiled once -macro_rules! regex { - ($re:literal $(,)?) => {{ - static RE: std::sync::OnceLock = std::sync::OnceLock::new(); - RE.get_or_init(|| regex::Regex::new($re).unwrap()) - }}; -} - fn assert(root: &Path) -> snapbox::Assert { let mut subs = snapbox::Redactions::new(); subs.insert("[ROOT]", root.to_path_buf()).unwrap(); - subs.insert( - "[TIMESTAMP]", - regex!(r"(?m)(?20\d\d-\d{2}-\d{2} \d{2}:\d{2}:\d{2})"), - ) - .unwrap(); subs.insert("[VERSION]", mdbook_core::MDBOOK_VERSION) .unwrap(); diff --git a/tests/testsuite/build.rs b/tests/testsuite/build.rs index 7b6cfc4d..e3851c12 100644 --- a/tests/testsuite/build.rs +++ b/tests/testsuite/build.rs @@ -10,9 +10,9 @@ use crate::prelude::*; fn basic_build() { BookTest::from_dir("build/basic_build").run("build", |cmd| { cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }); @@ -24,8 +24,8 @@ fn basic_build() { fn failure_on_missing_file() { BookTest::from_dir("build/missing_file").run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Chapter file not found, ./chapter_1.md -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] +ERROR Chapter file not found, ./chapter_1.md +[TAB]Caused by: [NOT_FOUND] "#]]); }); @@ -46,10 +46,10 @@ fn create_missing() { fn no_reserved_filename() { BookTest::from_dir("build/no_reserved_filename").run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: print.md is reserved for internal use + INFO Book building has started + INFO Running the html backend +ERROR Rendering failed +[TAB]Caused by: print.md is reserved for internal use "#]]); }); @@ -77,9 +77,9 @@ fn dest_dir_relative_path() { cmd.args(&["--dest-dir", "foo", ".."]) .current_dir(¤t_dir) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/work/foo` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/work/foo` "#]]); }); diff --git a/tests/testsuite/config.rs b/tests/testsuite/config.rs index 52c45d33..f5b14875 100644 --- a/tests/testsuite/config.rs +++ b/tests/testsuite/config.rs @@ -120,8 +120,8 @@ fn bad_config_top_level() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 1, column 1 +ERROR Invalid configuration file +[TAB]Caused by: TOML parse error at line 1, column 1 | 1 | foo = 123 | ^^^ @@ -145,8 +145,8 @@ fn bad_config_top_level_table() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 1, column 2 +ERROR Invalid configuration file +[TAB]Caused by: TOML parse error at line 1, column 2 | 1 | [other] | ^^^^^ @@ -171,8 +171,8 @@ fn bad_config_in_book_table() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 3, column 1 +ERROR Invalid configuration file +[TAB]Caused by: TOML parse error at line 3, column 1 | 3 | foo = 123 | ^^^ @@ -196,8 +196,8 @@ fn bad_config_in_rust_table() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Invalid configuration file -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: TOML parse error at line 2, column 1 +ERROR Invalid configuration file +[TAB]Caused by: TOML parse error at line 2, column 1 | 2 | title = "bad-config" | ^^^^^ diff --git a/tests/testsuite/includes.rs b/tests/testsuite/includes.rs index 300df28e..7bf94808 100644 --- a/tests/testsuite/includes.rs +++ b/tests/testsuite/includes.rs @@ -45,10 +45,10 @@ fn recursive_include() { BookTest::from_dir("includes/all_includes") .run("build", |cmd| { cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [ERROR] (mdbook_driver::builtin_preprocessors::links): Stack depth exceeded in recursive.md. Check for cyclic includes -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started +ERROR Stack depth exceeded in recursive.md. Check for cyclic includes + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }) diff --git a/tests/testsuite/init.rs b/tests/testsuite/init.rs index 852f1a2f..06b4f5f5 100644 --- a/tests/testsuite/init.rs +++ b/tests/testsuite/init.rs @@ -19,7 +19,7 @@ All done, no errors... "#]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content + INFO Creating a new book with stub content "#]]); }) @@ -84,7 +84,7 @@ All done, no errors... "#]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content + INFO Creating a new book with stub content "#]]); }) @@ -115,7 +115,7 @@ All done, no errors... "#]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::init): Creating a new book with stub content + INFO Creating a new book with stub content "#]]) .args(&["--title", "Example title"]); diff --git a/tests/testsuite/markdown.rs b/tests/testsuite/markdown.rs index cc1cb896..8317b2a6 100644 --- a/tests/testsuite/markdown.rs +++ b/tests/testsuite/markdown.rs @@ -20,13 +20,13 @@ fn footnotes() { BookTest::from_dir("markdown/footnotes") .run("build", |cmd| { cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [WARN] (mdbook_markdown): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition -[TIMESTAMP] [WARN] (mdbook_markdown): footnote `unused` in `footnotes.md` is defined but not referenced -[TIMESTAMP] [WARN] (mdbook_markdown): footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition -[TIMESTAMP] [WARN] (mdbook_markdown): footnote `unused` in `footnotes.md` is defined but not referenced -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + WARN footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition + WARN footnote `unused` in `footnotes.md` is defined but not referenced + WARN footnote `multiple-definitions` in footnotes.md defined multiple times - not updating to new definition + WARN footnote `unused` in `footnotes.md` is defined but not referenced + INFO HTML book written to `[ROOT]/book` "#]]); }) diff --git a/tests/testsuite/preprocessor.rs b/tests/testsuite/preprocessor.rs index 7c929679..cd8b9efa 100644 --- a/tests/testsuite/preprocessor.rs +++ b/tests/testsuite/preprocessor.rs @@ -49,9 +49,9 @@ fn runs_preprocessors() { fn nop_preprocessor() { BookTest::from_dir("preprocessor/nop_preprocessor").run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }); @@ -60,17 +60,16 @@ fn nop_preprocessor() { // Failing preprocessor generates an error. #[test] fn failing_preprocessor() { - BookTest::from_dir("preprocessor/failing_preprocessor") - .run("build", |cmd| { - cmd.expect_failure() - .expect_stdout(str![[""]]) - .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started + BookTest::from_dir("preprocessor/failing_preprocessor").run("build", |cmd| { + cmd.expect_failure() + .expect_stdout(str![[""]]) + .expect_stderr(str![[r#" + INFO Book building has started Boom!!1! -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: The "nop-preprocessor" preprocessor exited unsuccessfully with [EXIT_STATUS]: 1 status +ERROR The "nop-preprocessor" preprocessor exited unsuccessfully with [EXIT_STATUS]: 1 status "#]]); - }); + }); } fn example() -> CmdPreprocessor { @@ -128,9 +127,9 @@ fn relative_command_path() { ) .run("build", |cmd| { cmd.expect_stdout(str![""]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }) @@ -143,9 +142,9 @@ fn relative_command_path() { cmd.current_dir(cmd.dir.join("src")) .expect_stdout(str![""]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/src/../book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/src/../book` "#]]); }) @@ -160,10 +159,10 @@ fn missing_preprocessor() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [ERROR] (mdbook_driver): The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` preprocessor installed? If you want to ignore this error when the `missing` preprocessor is not installed, set `optional = true` in the `[preprocessor.missing]` section of the book.toml configuration file. -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Unable to run the preprocessor `missing` -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] + INFO Book building has started +ERROR The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` preprocessor installed? If you want to ignore this error when the `missing` preprocessor is not installed, set `optional = true` in the `[preprocessor.missing]` section of the book.toml configuration file. +ERROR Unable to run the preprocessor `missing` +[TAB]Caused by: [NOT_FOUND] "#]]); }); @@ -174,10 +173,10 @@ fn missing_preprocessor() { fn missing_optional_not_fatal() { BookTest::from_dir("preprocessor/missing_optional_not_fatal").run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [WARN] (mdbook_driver): The command `trduyvbhijnorgevfuhn` for preprocessor `missing` was not found, but is marked as optional. -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + WARN The command `trduyvbhijnorgevfuhn` for preprocessor `missing` was not found, but is marked as optional. + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }); @@ -239,14 +238,14 @@ fn extension_compatibility() { // that the built book is identical with the preprocessor enabled. test.run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book/html` -[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the my-renderer backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "my-renderer" renderer -[TIMESTAMP] [WARN] (mdbook_driver): The command `./my-renderer` for backend `my-renderer` was not found, but is marked as optional. + INFO Book building has started + WARN The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. + INFO Running the html backend + INFO HTML book written to `[ROOT]/book/html` + WARN The command `./my-preprocessor` for preprocessor `my-preprocessor` was not found, but is marked as optional. + INFO Running the my-renderer backend + INFO Invoking the "my-renderer" renderer + WARN The command `./my-renderer` for backend `my-renderer` was not found, but is marked as optional. "#]]); }); @@ -441,11 +440,11 @@ fn extension_compatibility() { ) .run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book/html` -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the my-renderer backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "my-renderer" renderer + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book/html` + INFO Running the my-renderer backend + INFO Invoking the "my-renderer" renderer "#]]); }) diff --git a/tests/testsuite/redirects.rs b/tests/testsuite/redirects.rs index c73703ca..84c77683 100644 --- a/tests/testsuite/redirects.rs +++ b/tests/testsuite/redirects.rs @@ -22,11 +22,11 @@ fn redirects_are_emitted_correctly() { fn redirect_removed_with_fragments_only() { BookTest::from_dir("redirects/redirect_removed_with_fragments_only").run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: Unable to emit redirects -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: redirect entry for `old-file.html` only has source paths with `#` fragments + INFO Book building has started + INFO Running the html backend +ERROR Rendering failed +[TAB]Caused by: Unable to emit redirects +[TAB]Caused by: redirect entry for `old-file.html` only has source paths with `#` fragments There must be an entry without the `#` fragment to determine the default destination. "#]]); @@ -38,10 +38,10 @@ There must be an entry without the `#` fragment to determine the default destina fn redirect_existing_page() { BookTest::from_dir("redirects/redirect_existing_page").run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: redirect found for existing chapter at `/chapter_1.html` + INFO Book building has started + INFO Running the html backend +ERROR Rendering failed +[TAB]Caused by: redirect found for existing chapter at `/chapter_1.html` Either delete the redirect or remove the chapter. "#]]); diff --git a/tests/testsuite/renderer.rs b/tests/testsuite/renderer.rs index b8070c5c..2dbe2727 100644 --- a/tests/testsuite/renderer.rs +++ b/tests/testsuite/renderer.rs @@ -64,12 +64,12 @@ fn failing_command() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the failing backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "failing" renderer -[TIMESTAMP] [ERROR] (mdbook_driver::builtin_renderers): Renderer exited with non-zero return code. -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: The "failing" renderer failed + INFO Book building has started + INFO Running the failing backend + INFO Invoking the "failing" renderer +ERROR Renderer exited with non-zero return code. +ERROR Rendering failed +[TAB]Caused by: The "failing" renderer failed "#]]); }); @@ -82,13 +82,13 @@ fn missing_renderer() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the missing backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "missing" renderer -[TIMESTAMP] [ERROR] (mdbook_driver): The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` backend installed? If you want to ignore this error when the `missing` backend is not installed, set `optional = true` in the `[output.missing]` section of the book.toml configuration file. -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: Unable to run the backend `missing` -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [NOT_FOUND] + INFO Book building has started + INFO Running the missing backend + INFO Invoking the "missing" renderer +ERROR The command `trduyvbhijnorgevfuhn` wasn't found, is the `missing` backend installed? If you want to ignore this error when the `missing` backend is not installed, set `optional = true` in the `[output.missing]` section of the book.toml configuration file. +ERROR Rendering failed +[TAB]Caused by: Unable to run the backend `missing` +[TAB]Caused by: [NOT_FOUND] "#]]); }); @@ -99,10 +99,10 @@ fn missing_renderer() { fn missing_optional_not_fatal() { BookTest::from_dir("renderer/missing_optional_not_fatal").run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the missing backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "missing" renderer -[TIMESTAMP] [WARN] (mdbook_driver): The command `trduyvbhijnorgevfuhn` for backend `missing` was not found, but is marked as optional. + INFO Book building has started + INFO Running the missing backend + INFO Invoking the "missing" renderer + WARN The command `trduyvbhijnorgevfuhn` for backend `missing` was not found, but is marked as optional. "#]]); }); @@ -131,9 +131,9 @@ Hello World! "#]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the arguments backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "arguments" renderer + INFO Book building has started + INFO Running the arguments backend + INFO Invoking the "arguments" renderer "#]]); }); @@ -156,9 +156,9 @@ fn backends_receive_render_context_via_stdin() { ) .run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the cat-to-file backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "cat-to-file" renderer + INFO Book building has started + INFO Running the cat-to-file backend + INFO Invoking the "cat-to-file" renderer "#]]); }) @@ -233,9 +233,9 @@ fn relative_command_path() { ) .run("build", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the myrenderer backend -[TIMESTAMP] [INFO] (mdbook_driver::builtin_renderers): Invoking the "myrenderer" renderer + INFO Book building has started + INFO Running the myrenderer backend + INFO Invoking the "myrenderer" renderer "#]]); }) diff --git a/tests/testsuite/search.rs b/tests/testsuite/search.rs index 5471399c..0596f9c7 100644 --- a/tests/testsuite/search.rs +++ b/tests/testsuite/search.rs @@ -126,10 +126,10 @@ fn with_no_source_path() { fn chapter_settings_validation_error() { BookTest::from_dir("search/chapter_settings_validation_error").run("build", |cmd| { cmd.expect_failure().expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: [output.html.search.chapter] key `does-not-exist` does not match any chapter paths + INFO Book building has started + INFO Running the html backend +ERROR Rendering failed +[TAB]Caused by: [output.html.search.chapter] key `does-not-exist` does not match any chapter paths "#]]); }); diff --git a/tests/testsuite/test.rs b/tests/testsuite/test.rs index dc43988e..e83a94ef 100644 --- a/tests/testsuite/test.rs +++ b/tests/testsuite/test.rs @@ -7,9 +7,9 @@ use crate::prelude::*; fn passing_tests() { BookTest::from_dir("test/passing_tests").run("test", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Intro': "intro.md" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 1': "passing1.md" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 2': "passing2.md" + INFO Testing chapter 'Intro': "intro.md" + INFO Testing chapter 'Passing 1': "passing1.md" + INFO Testing chapter 'Passing 2': "passing2.md" "#]]); }); @@ -27,8 +27,8 @@ fn failing_tests() { // still includes a little bit of output, so if that is a problem, // add more redactions. .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Failing Tests': "failing.md" -[TIMESTAMP] [ERROR] (mdbook_driver::mdbook): rustdoc returned an error: + INFO Testing chapter 'Failing Tests': "failing.md" +ERROR rustdoc returned an error: --- stdout @@ -38,8 +38,8 @@ test failing.md - Failing_Tests (line 3) ... FAILED thread [..] panicked at failing.md:3:1: fail ... -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Failing Include': "failing_include.md" -[TIMESTAMP] [ERROR] (mdbook_driver::mdbook): rustdoc returned an error: + INFO Testing chapter 'Failing Include': "failing_include.md" +ERROR rustdoc returned an error: --- stdout ... @@ -48,7 +48,7 @@ test failing_include.md - Failing_Include (line 3) ... FAILED thread [..] panicked at failing_include.md:3:1: failing! ... -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: One or more tests failed +ERROR One or more tests failed "#]]); }); @@ -62,14 +62,14 @@ fn test_individual_chapter() { cmd.args(&["Passing 1"]) .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 1': "passing1.md" + INFO Testing chapter 'Passing 1': "passing1.md" "#]]); }) // Can also be a source path. .run("test -c passing2.md", |cmd| { cmd.expect_stdout(str![[""]]).expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Testing chapter 'Passing 2': "passing2.md" + INFO Testing chapter 'Passing 2': "passing2.md" "#]]); }); @@ -82,7 +82,7 @@ fn chapter_not_found() { cmd.expect_failure() .expect_stdout(str![[""]]) .expect_stderr(str![[r#" -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Chapter not found: bogus +ERROR Chapter not found: bogus "#]]); }); diff --git a/tests/testsuite/theme.rs b/tests/testsuite/theme.rs index 97cb2a18..0cbb3724 100644 --- a/tests/testsuite/theme.rs +++ b/tests/testsuite/theme.rs @@ -5,14 +5,12 @@ use crate::prelude::*; // Checks what happens if the theme directory is missing. #[test] fn missing_theme() { - BookTest::from_dir("theme/missing_theme") - .run("build", |cmd| { -cmd.expect_failure() - .expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [ERROR] (mdbook_core::utils): Error: Rendering failed -[TIMESTAMP] [ERROR] (mdbook_core::utils): [TAB]Caused By: theme dir [ROOT]/./non-existent-directory does not exist + BookTest::from_dir("theme/missing_theme").run("build", |cmd| { + cmd.expect_failure().expect_stderr(str![[r#" + INFO Book building has started + INFO Running the html backend +ERROR Rendering failed +[TAB]Caused by: theme dir [ROOT]/./non-existent-directory does not exist "#]]); }); @@ -24,9 +22,9 @@ fn empty_theme() { BookTest::from_dir("theme/empty_theme").run("build", |cmd| { std::fs::create_dir(cmd.dir.join("theme")).unwrap(); cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }); @@ -147,9 +145,9 @@ fn empty_fonts_css() { BookTest::from_dir("theme/empty_fonts_css") .run("build", |cmd| { cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); }) @@ -163,9 +161,9 @@ fn custom_fonts_css() { BookTest::from_dir("theme/custom_fonts_css") .run("build", |cmd| { cmd.expect_stderr(str![[r#" -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Book building has started -[TIMESTAMP] [INFO] (mdbook_driver::mdbook): Running the html backend -[TIMESTAMP] [INFO] (mdbook_html::html_handlebars::hbs_renderer): HTML book written to `[ROOT]/book` + INFO Book building has started + INFO Running the html backend + INFO HTML book written to `[ROOT]/book` "#]]); })