diff --git a/Cargo.lock b/Cargo.lock index 9985799689030..1b09bcf785965 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -259,7 +259,7 @@ dependencies = [ "log", "parking", "polling", - "rustix 0.37.11", + "rustix", "slab", "socket2", "waker-fn", @@ -2112,19 +2112,6 @@ dependencies = [ "termcolor", ] -[[package]] -name = "env_logger" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" -dependencies = [ - "humantime", - "is-terminal", - "log", - "regex", - "termcolor", -] - [[package]] name = "erased-serde" version = "0.3.25" @@ -2134,17 +2121,6 @@ dependencies = [ "serde", ] -[[package]] -name = "errno" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi 0.3.9", -] - [[package]] name = "errno" version = "0.3.0" @@ -3221,14 +3197,14 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8687c819457e979cc940d09cb16e42a1bf70aa6b60a549de6d3a62a0ee90c69e" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix 0.36.11", - "windows-sys 0.45.0", + "rustix", + "windows-sys 0.48.0", ] [[package]] @@ -3614,12 +3590,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - [[package]] name = "linux-raw-sys" version = "0.3.0" @@ -5557,20 +5527,6 @@ dependencies = [ "semver 0.9.0", ] -[[package]] -name = "rustix" -version = "0.36.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4165c9963ab29e422d6c26fbc1d37f15bace6b2810221f9d925023480fcf0e" -dependencies = [ - "bitflags 1.3.2", - "errno 0.2.8", - "io-lifetimes", - "libc", - "linux-raw-sys 0.1.4", - "windows-sys 0.45.0", -] - [[package]] name = "rustix" version = "0.37.11" @@ -5578,10 +5534,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77" dependencies = [ "bitflags 1.3.2", - "errno 0.3.0", + "errno", "io-lifetimes", "libc", - "linux-raw-sys 0.3.0", + "linux-raw-sys", "windows-sys 0.48.0", ] @@ -7578,7 +7534,7 @@ dependencies = [ "cfg-if 1.0.0", "fastrand", "redox_syscall 0.3.5", - "rustix 0.37.11", + "rustix", "windows-sys 0.45.0", ] @@ -7617,7 +7573,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "rustix 0.37.11", + "rustix", "windows-sys 0.48.0", ] @@ -8185,9 +8141,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -8296,13 +8252,13 @@ dependencies = [ "command-group", "dunce", "itertools", - "log", "pretty_assertions", "serde", "serde_json", "serde_yaml 0.9.19", "tiny-gradient", "tokio-util", + "tracing", "turborepo-lib", "winapi 0.3.9", ] @@ -9059,7 +9015,6 @@ dependencies = [ "directories", "dirs-next", "dunce", - "env_logger 0.10.0", "futures", "glob-match 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "globwatch", @@ -9068,11 +9023,12 @@ dependencies = [ "hostname", "humantime", "indicatif", + "is-terminal", "itertools", "lazy_static", "libc", - "log", "notify 5.1.0", + "owo-colors", "pidlock", "port_scanner", "pretty_assertions", @@ -9100,6 +9056,7 @@ dependencies = [ "tonic-reflection", "tower", "tracing", + "tracing-subscriber", "tracing-test", "turbo-updater", "turbopath", @@ -9143,7 +9100,7 @@ version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "rand 0.8.5", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 9d0049101d176..21c40fca5a137 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -197,7 +197,6 @@ indicatif = "0.17.3" indoc = "2.0.0" itertools = "0.10.5" lazy_static = "1.4.0" -log = "0.4.17" mime = "0.3.16" nohash-hasher = "0.2.0" once_cell = "1.17.1" diff --git a/crates/turborepo-lib/Cargo.toml b/crates/turborepo-lib/Cargo.toml index b1161dd8b29e5..675c103139bab 100644 --- a/crates/turborepo-lib/Cargo.toml +++ b/crates/turborepo-lib/Cargo.toml @@ -45,7 +45,6 @@ dialoguer = { workspace = true, features = ["fuzzy-select"] } directories = "4.0.1" dirs-next = "2.0.0" dunce = { workspace = true } -env_logger = "0.10.0" futures = "0.3.26" glob-match = "0.2.1" globwatch = { path = "../globwatch" } @@ -56,7 +55,6 @@ indicatif = { workspace = true } itertools = "0.10.5" lazy_static = { workspace = true } libc = "0.2.140" -log = { workspace = true } notify = { version = "5.1.0", default-features = false, features = [ "macos_kqueue", ] } @@ -84,6 +82,9 @@ url = "2.3.1" const_format = "0.2.30" go-parse-duration = "0.1.1" +is-terminal = "0.4.7" +owo-colors.workspace = true +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } tracing.workspace = true turbo-updater = { workspace = true } turbopath = { workspace = true } diff --git a/crates/turborepo-lib/src/cli.rs b/crates/turborepo-lib/src/cli.rs index 599ff14b45f65..5f9acdc14c2cc 100644 --- a/crates/turborepo-lib/src/cli.rs +++ b/crates/turborepo-lib/src/cli.rs @@ -9,8 +9,8 @@ use anyhow::{anyhow, Result}; use clap::{ArgAction, CommandFactory, Parser, Subcommand, ValueEnum}; use clap_complete::{generate, Shell}; use dunce::canonicalize as fs_canonicalize; -use log::{debug, error}; use serde::Serialize; +use tracing::{debug, error}; use crate::{ commands::{bin, daemon, link, login, logout, unlink, CommandBase}, diff --git a/crates/turborepo-lib/src/commands/login.rs b/crates/turborepo-lib/src/commands/login.rs index a512c4670d903..5b05820076476 100644 --- a/crates/turborepo-lib/src/commands/login.rs +++ b/crates/turborepo-lib/src/commands/login.rs @@ -5,12 +5,12 @@ use std::sync::Arc; use anyhow::{anyhow, Context, Result}; #[cfg(not(test))] use axum::{extract::Query, response::Redirect, routing::get, Router}; -use log::debug; -#[cfg(not(test))] -use log::warn; use reqwest::Url; use serde::Deserialize; use tokio::sync::OnceCell; +use tracing::debug; +#[cfg(not(test))] +use tracing::warn; use crate::{ commands::{ diff --git a/crates/turborepo-lib/src/commands/logout.rs b/crates/turborepo-lib/src/commands/logout.rs index b3d46b78df0c5..ae2aa6f2a5746 100644 --- a/crates/turborepo-lib/src/commands/logout.rs +++ b/crates/turborepo-lib/src/commands/logout.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use log::error; +use tracing::error; use crate::{commands::CommandBase, ui::GREY}; diff --git a/crates/turborepo-lib/src/daemon/client.rs b/crates/turborepo-lib/src/daemon/client.rs index a407a5fc5a1ac..9442d4ebae7a2 100644 --- a/crates/turborepo-lib/src/daemon/client.rs +++ b/crates/turborepo-lib/src/daemon/client.rs @@ -1,5 +1,6 @@ use thiserror::Error; use tonic::{Code, Status}; +use tracing::info; use self::proto::turbod_client::TurbodClient; use super::connector::{DaemonConnector, DaemonConnectorError}; @@ -33,7 +34,7 @@ impl DaemonClient { /// Stops the daemon and closes the connection, returning /// the connection settings that were used to connect. pub async fn stop(mut self) -> Result { - log::info!("Stopping daemon"); + info!("Stopping daemon"); self.client.shutdown(proto::ShutdownRequest {}).await?; Ok(self.connect_settings) } diff --git a/crates/turborepo-lib/src/daemon/connector.rs b/crates/turborepo-lib/src/daemon/connector.rs index af4a9b87ec8c4..70e2d011678ea 100644 --- a/crates/turborepo-lib/src/daemon/connector.rs +++ b/crates/turborepo-lib/src/daemon/connector.rs @@ -5,12 +5,12 @@ use std::{ }; use command_group::AsyncCommandGroup; -use log::{debug, error}; use notify::{Config, Event, EventKind, Watcher}; use sysinfo::{Pid, ProcessExt, ProcessRefreshKind, RefreshKind, SystemExt}; use thiserror::Error; use tokio::{sync::mpsc, time::timeout}; use tonic::transport::Endpoint; +use tracing::debug; use super::{client::proto::turbod_client::TurbodClient, DaemonClient}; use crate::daemon::DaemonError; @@ -381,6 +381,7 @@ mod test { select, sync::{oneshot::Sender, Mutex}, }; + use tracing::info; use turbopath::AbsoluteSystemPathBuf; use super::*; @@ -568,7 +569,7 @@ mod test { &self, req: tonic::Request, ) -> tonic::Result> { - log::info!("shutdown request: {:?}", req); + info!("shutdown request: {:?}", req); self.shutdown .lock() .await diff --git a/crates/turborepo-lib/src/daemon/endpoint.rs b/crates/turborepo-lib/src/daemon/endpoint.rs index c7ab7ef04779d..ff7d38bd544c4 100644 --- a/crates/turborepo-lib/src/daemon/endpoint.rs +++ b/crates/turborepo-lib/src/daemon/endpoint.rs @@ -8,9 +8,9 @@ use std::{ }; use futures::Stream; -use log::debug; use tokio::io::{AsyncRead, AsyncWrite}; use tonic::transport::server::Connected; +use tracing::debug; use turbopath::{AbsoluteSystemPathBuf, RelativeSystemPathBuf}; #[derive(thiserror::Error, Debug)] diff --git a/crates/turborepo-lib/src/daemon/server.rs b/crates/turborepo-lib/src/daemon/server.rs index 9861969c71956..a463b617b3b99 100644 --- a/crates/turborepo-lib/src/daemon/server.rs +++ b/crates/turborepo-lib/src/daemon/server.rs @@ -22,7 +22,6 @@ use std::{ }; use globwatch::{StopSource, Watcher}; -use log::error; use tokio::{ select, signal::ctrl_c, @@ -33,6 +32,7 @@ use tokio::{ }; use tonic::transport::{NamedService, Server}; use tower::ServiceBuilder; +use tracing::error; use turbopath::{AbsoluteSystemPathBuf, RelativeSystemPathBuf}; use super::{ diff --git a/crates/turborepo-lib/src/formatter.rs b/crates/turborepo-lib/src/formatter.rs new file mode 100644 index 0000000000000..aaebb2c3c644f --- /dev/null +++ b/crates/turborepo-lib/src/formatter.rs @@ -0,0 +1,128 @@ +use std::marker::PhantomData; + +use chrono::Local; +use owo_colors::{ + colors::{Black, Default, Red, Yellow}, + Color, OwoColorize, +}; +use tracing::{field::Visit, Event, Level, Subscriber}; +use tracing_subscriber::{ + fmt::{format::Writer, FmtContext, FormatEvent, FormatFields}, + registry::LookupSpan, +}; + +/// The formatter for TURBOREPO +/// +/// This is a port of the go formatter, which follows a few main rules: +/// - Errors are red +/// - Warnings are yellow +/// - Info is default +/// - Debug and trace are default, but with timestamp and level attached +/// +/// This formatter does not print any information about spans, and does +/// not print any event metadata other than the message set when you +/// call `debug!(...)` or `info!(...)` etc. +pub struct TurboFormatter { + is_ansi: bool, +} + +impl TurboFormatter { + pub fn new_with_ansi(is_ansi: bool) -> Self { + Self { is_ansi } + } +} + +impl FormatEvent for TurboFormatter +where + S: Subscriber + for<'a> LookupSpan<'a>, + N: for<'a> FormatFields<'a> + 'static, +{ + fn format_event( + &self, + _ctx: &FmtContext<'_, S, N>, + mut writer: Writer<'_>, + event: &Event<'_>, + ) -> std::fmt::Result { + let level = event.metadata().level(); + let target = event.metadata().target(); + + match level { + &Level::ERROR => { + write_string::(writer.by_ref(), self.is_ansi, level.as_str()) + .and_then(|_| write_message::(writer, self.is_ansi, event)) + } + &Level::WARN => { + write_string::(writer.by_ref(), self.is_ansi, level.as_str()) + .and_then(|_| write_message::(writer, self.is_ansi, event)) + } + &Level::INFO => write_message::(writer, self.is_ansi, event), + // trace and debug use the same style + _ => { + let now = Local::now(); + write!( + writer, + "{} [{}] {}: ", + // build our own timestamp to match the hashicorp/go-hclog format used by the + // go binary + now.format("%Y-%m-%dT%H:%M:%S.%3f%z"), + level, + target, + ) + .and_then(|_| write_message::(writer, self.is_ansi, event)) + } + } + } +} + +/// A visitor that writes the message field of an event to the given writer. +/// +/// The FG and BG type parameters are the foreground and background colors +/// to use when writing the message. +struct MessageVisitor<'a, FG: Color, BG: Color> { + colorize: bool, + writer: Writer<'a>, + _fg: PhantomData, + _bg: PhantomData, +} + +impl<'a, FG: Color, BG: Color> Visit for MessageVisitor<'a, FG, BG> { + fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) { + if field.name() == "message" { + if self.colorize { + let value = value.fg::().bg::(); + let _ = write!(self.writer, "{:?}", value); + } else { + let _ = write!(self.writer, "{:?}", value); + } + } + } +} + +fn write_string( + mut writer: Writer<'_>, + colorize: bool, + value: &str, +) -> Result<(), std::fmt::Error> { + if colorize { + let value = value.fg::().bg::(); + write!(writer, "{} ", value) + } else { + write!(writer, "{} ", value) + } +} + +/// Writes the message field of an event to the given writer. +fn write_message( + mut writer: Writer<'_>, + colorize: bool, + event: &Event, +) -> Result<(), std::fmt::Error> { + let mut visitor = MessageVisitor:: { + colorize, + writer: writer.by_ref(), + _fg: PhantomData, + _bg: PhantomData, + }; + event.record(&mut visitor); + writeln!(writer) +} diff --git a/crates/turborepo-lib/src/lib.rs b/crates/turborepo-lib/src/lib.rs index baa0d97e9c0a1..adb143c985c18 100644 --- a/crates/turborepo-lib/src/lib.rs +++ b/crates/turborepo-lib/src/lib.rs @@ -6,6 +6,7 @@ mod commands; mod config; mod daemon; mod execution_state; +mod formatter; pub(crate) mod globwatcher; mod package_manager; mod shim; @@ -13,7 +14,7 @@ mod ui; use anyhow::Result; pub use child::spawn_child; -use log::error; +use tracing::error; pub use crate::{cli::Args, execution_state::ExecutionState}; use crate::{commands::CommandBase, package_manager::PackageManager}; diff --git a/crates/turborepo-lib/src/shim.rs b/crates/turborepo-lib/src/shim.rs index 04dde21ac1ed6..3a64e039e0359 100644 --- a/crates/turborepo-lib/src/shim.rs +++ b/crates/turborepo-lib/src/shim.rs @@ -3,7 +3,6 @@ use std::{ env::current_dir, ffi::OsString, fs::{self}, - io::Write, path::{Path, PathBuf}, process, process::Stdio, @@ -11,17 +10,20 @@ use std::{ }; use anyhow::{anyhow, Result}; -use chrono::offset::Local; use const_format::formatcp; use dunce::canonicalize as fs_canonicalize; -use env_logger::{fmt::Color, Builder, Env, WriteStyle}; -use log::{debug, Level, LevelFilter}; +use is_terminal::IsTerminal; use semver::Version; use serde::{Deserialize, Serialize}; use tiny_gradient::{GradientStr, RGB}; +use tracing::{debug, metadata::LevelFilter}; +use tracing_subscriber::EnvFilter; use turbo_updater::check_for_updates; -use crate::{cli, get_version, package_manager::Globs, spawn_child, PackageManager, Payload}; +use crate::{ + cli, formatter::TurboFormatter, get_version, package_manager::Globs, spawn_child, + PackageManager, Payload, +}; // all arguments that result in a stdout that much be directly parsable and // should not be paired with additional output (from the update notifier for @@ -677,70 +679,23 @@ fn is_turbo_binary_path_set() -> bool { env::var("TURBO_BINARY_PATH").is_ok() } -fn init_env_logger(verbosity: usize) { - // configure logger - let level = match verbosity { - 0 => LevelFilter::Warn, - 1 => LevelFilter::Info, - 2 => LevelFilter::Debug, - _ => LevelFilter::Trace, +fn init_subscriber(verbosity: usize) { + let max_level = match verbosity { + 0 => LevelFilter::WARN, + 1 => LevelFilter::INFO, + 2 => LevelFilter::DEBUG, + _ => LevelFilter::TRACE, }; - let mut builder = Builder::new(); - let env = Env::new().filter("TURBO_LOG_VERBOSITY"); - - builder - // set defaults - .filter_level(level) - .write_style(WriteStyle::Auto) - // override from env (if available) - .parse_env(env); - - builder.format(|buf, record| match record.level() { - Level::Error => { - let mut level_style = buf.style(); - let mut log_style = buf.style(); - level_style.set_bg(Color::Red).set_color(Color::Black); - log_style.set_color(Color::Red); - - writeln!( - buf, - "{} {}", - level_style.value(record.level()), - log_style.value(record.args()) - ) - } - Level::Warn => { - let mut level_style = buf.style(); - let mut log_style = buf.style(); - level_style.set_bg(Color::Yellow).set_color(Color::Black); - log_style.set_color(Color::Yellow); - - writeln!( - buf, - "{} {}", - level_style.value(record.level()), - log_style.value(record.args()) - ) - } - Level::Info => writeln!(buf, "{}", record.args()), - // trace and debug use the same style - _ => { - let now = Local::now(); - writeln!( - buf, - "{} [{}] {}: {}", - // build our own timestamp to match the hashicorp/go-hclog format used by the go - // binary - now.format("%Y-%m-%dT%H:%M:%S.%3f%z"), - record.level(), - record.target(), - record.args() - ) - } - }); - - builder.init(); + // respect TURBO_LOG_VERBOSITY env var + // respect verbosity arg + tracing_subscriber::fmt() + .event_format(TurboFormatter::new_with_ansi( + std::io::stdout().is_terminal(), + )) + .with_env_filter(EnvFilter::from_env("TURBO_LOG_VERBOSITY")) + .with_max_level(max_level) + .init(); } fn try_check_for_updates(args: &ShimArgs, current_version: &str) { @@ -775,7 +730,7 @@ fn try_check_for_updates(args: &ShimArgs, current_version: &str) { pub fn run() -> Result { let args = ShimArgs::parse()?; - init_env_logger(args.verbosity); + init_subscriber(args.verbosity); debug!("Global turbo version: {}", get_version()); // If skip_infer is passed, we're probably running local turbo with diff --git a/crates/turborepo/Cargo.toml b/crates/turborepo/Cargo.toml index 3e170740b28ed..93abb30ae2e06 100644 --- a/crates/turborepo/Cargo.toml +++ b/crates/turborepo/Cargo.toml @@ -29,12 +29,12 @@ clap = { workspace = true, features = ["derive"] } clap_complete = { workspace = true } command-group = { version = "2.0.1", features = ["with-tokio"] } dunce = { workspace = true } -log = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_json = { workspace = true } serde_yaml = { workspace = true } tiny-gradient = { workspace = true } tokio-util = { version = "0.7.7", features = ["io"] } +tracing = { workspace = true } turborepo-lib = { workspace = true } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/crates/turborepo/src/main.rs b/crates/turborepo/src/main.rs index c917dd0b50010..676bb0baf2bbc 100644 --- a/crates/turborepo/src/main.rs +++ b/crates/turborepo/src/main.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::Result; use dunce::canonicalize as fs_canonicalize; -use log::{debug, error, trace}; +use tracing::{debug, error, trace}; use turborepo_lib::{spawn_child, ExecutionState, Payload}; fn run_go_binary(execution_state: ExecutionState) -> Result { diff --git a/turborepo-tests/integration/tests/find_turbo/hard_mode.t b/turborepo-tests/integration/tests/find_turbo/hard_mode.t index 5d7ad4788ca0d..8662d988e3faa 100644 --- a/turborepo-tests/integration/tests/find_turbo/hard_mode.t +++ b/turborepo-tests/integration/tests/find_turbo/hard_mode.t @@ -5,7 +5,7 @@ Setup When --skip-infer is used we use the current binary and output no global/local message $ cd $TESTROOT/subdir - $ ${TURBO} --help --skip-infer -vv | head -n 1 + $ ${TURBO} --help --skip-infer -vv | head -n 2 [-0-9:.TWZ+]+ \[DEBUG] turborepo_lib::shim: Global turbo version: .* (re) The build system that makes ship happen