Log which preview features are enabled (#17968)

For https://github.com/astral-sh/uv/issues/17964 /
https://github.com/astral-sh/uv/pull/17965. Logging now gets initialized
earlier to cover more of the startup procedure.

Also decrease the log level for lock acquisition from debug to trace,
that happy path usually isn't relevant.

```
$ cargo run -q pip install tqdm -v
  DEBUG uv 0.10.2+7 (cc6e7a600 2026-02-11)
  DEBUG Searching for default Python interpreter in virtual environments
  DEBUG Found `cpython-3.14.0-linux-x86_64-gnu` at `/home/konsti/projects/uv/.venv/bin/python3` (virtual environment)
  DEBUG Using Python 3.14.0 environment at: .venv
  DEBUG Requirement satisfied: tqdm
  Audited 1 package in 2ms
```

```
$ cargo run -q pip install tqdm -v --preview
  DEBUG uv 0.10.2+7 (cc6e7a600 2026-02-11)
  DEBUG All preview features are enabled
  DEBUG Searching for default Python interpreter in virtual environments
  DEBUG Found `cpython-3.14.0-linux-x86_64-gnu` at `/home/konsti/projects/uv/.venv/bin/python3` (virtual environment)
  DEBUG Using Python 3.14.0 environment at: .venv
  DEBUG Requirement satisfied: tqdm
  Audited 1 package in 2ms
```

```
$ cargo run -q pip install tqdm -v --preview-features target-workspace-discovery
  DEBUG uv 0.10.2+7 (cc6e7a600 2026-02-11)
  DEBUG The following preview features are enabled: target-workspace-discovery
  DEBUG Searching for default Python interpreter in virtual environments
  DEBUG Found `cpython-3.14.0-linux-x86_64-gnu` at `/home/konsti/projects/uv/.venv/bin/python3` (virtual environment)
  DEBUG Using Python 3.14.0 environment at: .venv
  DEBUG Requirement satisfied: tqdm
  Audited 1 package in 1ms
```
This commit is contained in:
konsti
2026-02-12 11:49:49 +01:00
committed by GitHub
parent 41866c96ab
commit 4cd9942391
9 changed files with 56 additions and 53 deletions
Generated
+1
View File
@@ -5843,6 +5843,7 @@ version = "0.10.2"
dependencies = [
"anstream",
"anyhow",
"tracing",
"tracing-subscriber",
"uv-build-backend",
"uv-logging",
+1
View File
@@ -18,6 +18,7 @@ uv-static = { workspace = true }
anstream = { workspace = true }
anyhow = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = ["env-filter"] }
[lints]
+7
View File
@@ -6,6 +6,7 @@ use uv_preview::Preview;
use uv_static::{EnvVars, parse_boolish_environment_variable};
use anyhow::{Context, Result, bail};
use tracing::debug;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
@@ -57,6 +58,12 @@ fn main() -> Result<()> {
} else {
Preview::default()
};
if preview.all_enabled() {
debug!("All preview features are enabled");
} else if preview.any_enabled() {
debug!("The following preview features are enabled: {preview}");
}
match command.as_str() {
"build-sdist" => {
let sdist_directory = PathBuf::from(args.next().context("Missing sdist directory")?);
+4 -4
View File
@@ -147,7 +147,7 @@ impl LockedFile {
let try_lock_exclusive = tokio::task::spawn_blocking(move || (mode.try_lock(&file), file));
let file = match try_lock_exclusive.await? {
(Ok(()), file) => {
debug!("Acquired {mode} lock for `{resource}`");
trace!("Acquired {mode} lock for `{resource}`");
return Ok(Self(file));
}
(Err(err), file) => {
@@ -180,7 +180,7 @@ impl LockedFile {
source: err,
})?;
debug!("Acquired {mode} lock for `{resource}`");
trace!("Acquired {mode} lock for `{resource}`");
Ok(Self(file))
}
@@ -192,7 +192,7 @@ impl LockedFile {
);
match mode.try_lock(&file) {
Ok(()) => {
debug!("Acquired {mode} lock for `{resource}`");
trace!("Acquired {mode} lock for `{resource}`");
Some(Self(file))
}
Err(err) => {
@@ -341,7 +341,7 @@ impl Drop for LockedFile {
self.0.path().display()
);
} else {
debug!("Released lock at `{}`", self.0.path().display());
trace!("Released lock at `{}`", self.0.path().display());
}
}
}
+11 -1
View File
@@ -154,10 +154,20 @@ impl Preview {
Self::new(preview_features)
}
/// Check if a single feature is enabled
/// Check if a single feature is enabled.
pub fn is_enabled(&self, flag: PreviewFeature) -> bool {
self.flags.contains(flag)
}
/// Check if all preview feature rae enabled.
pub fn all_enabled(&self) -> bool {
self.flags.is_all()
}
/// Check if any preview feature is enabled.
pub fn any_enabled(&self) -> bool {
!self.flags.is_empty()
}
}
impl Display for Preview {
+32 -24
View File
@@ -339,6 +339,38 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
&environment,
);
// Set the global flags.
uv_flags::init(EnvironmentFlags::from(&environment))
.map_err(|()| anyhow::anyhow!("Flags are already initialized"))?;
// Configure the `tracing` crate, which controls internal logging.
#[cfg(feature = "tracing-durations-export")]
let (durations_layer, _duration_guard) =
logging::setup_durations(environment.tracing_durations_file.as_ref())?;
#[cfg(not(feature = "tracing-durations-export"))]
let durations_layer = None::<tracing_subscriber::layer::Identity>;
logging::setup_logging(
match globals.verbose {
0 => logging::Level::Off,
1 => logging::Level::DebugUv,
2 => logging::Level::TraceUv,
3.. => logging::Level::TraceAll,
},
durations_layer,
globals.color,
environment.log_context.unwrap_or_default(),
)?;
debug!("uv {}", uv_cli::version::uv_self_version());
if globals.preview.all_enabled() {
debug!("All preview features are enabled");
} else if globals.preview.any_enabled() {
debug!(
"The following preview features are enabled: {}",
globals.preview
);
}
// Adjust open file limits on Unix if the preview feature is enabled.
#[cfg(unix)]
if globals.preview.is_enabled(PreviewFeature::AdjustUlimit) {
@@ -353,10 +385,6 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
// Resolve the cache settings.
let cache_settings = CacheSettings::resolve(*cli.top_level.cache_args, filesystem.as_ref());
// Set the global flags.
uv_flags::init(EnvironmentFlags::from(&environment))
.map_err(|()| anyhow::anyhow!("Flags are already initialized"))?;
// Enforce the required version.
if let Some(required_version) = globals.required_version.as_ref() {
let package_version = uv_pep440::Version::from_str(uv_version::version())?;
@@ -396,24 +424,6 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
}
}
// Configure the `tracing` crate, which controls internal logging.
#[cfg(feature = "tracing-durations-export")]
let (durations_layer, _duration_guard) =
logging::setup_durations(environment.tracing_durations_file.as_ref())?;
#[cfg(not(feature = "tracing-durations-export"))]
let durations_layer = None::<tracing_subscriber::layer::Identity>;
logging::setup_logging(
match globals.verbose {
0 => logging::Level::Off,
1 => logging::Level::DebugUv,
2 => logging::Level::TraceUv,
3.. => logging::Level::TraceAll,
},
durations_layer,
globals.color,
environment.log_context.unwrap_or_default(),
)?;
// Configure the `Printer`, which controls user-facing output in the CLI.
let printer = if globals.quiet == 1 {
Printer::Quiet
@@ -454,8 +464,6 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
// Don't initialize the rayon threadpool yet, this is too costly when we're doing a noop sync.
uv_configuration::RAYON_PARALLELISM.store(globals.concurrency.installs, Ordering::Relaxed);
debug!("uv {}", uv_cli::version::uv_self_version());
// Write out any resolved settings.
macro_rules! show_settings {
($arg:expr) => {
-10
View File
@@ -29,9 +29,7 @@ fn clean_all() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Clearing cache at: [CACHE_DIR]/
DEBUG Released lock at `[CACHE_DIR]/.lock`
Removed [N] files ([SIZE])
");
@@ -60,9 +58,7 @@ async fn clean_force() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Clearing cache at: [CACHE_DIR]/
DEBUG Released lock at `[CACHE_DIR]/.lock`
Removed [N] files ([SIZE])
");
@@ -140,10 +136,8 @@ fn clean_package_pypi() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
DEBUG Removing dangling cache entry: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
// Assert that the `.rkyv` file is removed for `iniconfig`.
@@ -160,10 +154,8 @@ fn clean_package_pypi() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
No unused entries found
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
Ok(())
@@ -219,10 +211,8 @@ fn clean_package_index() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
DEBUG Removing dangling cache entry: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
// Assert that the `.rkyv` file is removed for `iniconfig`.
-12
View File
@@ -35,10 +35,8 @@ fn prune_no_op() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
No unused entries found
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
Ok(())
@@ -76,11 +74,9 @@ fn prune_stale_directory() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling cache bucket: [CACHE_DIR]/simple-v4
Removed 1 directory
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
Ok(())
@@ -138,12 +134,10 @@ fn prune_cached_env() {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling cache environment: [CACHE_DIR]/environments-v2/[ENTRY]
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
}
@@ -185,11 +179,9 @@ fn prune_stale_symlink() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
Removed 44 files ([SIZE])
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
Ok(())
@@ -217,10 +209,8 @@ async fn prune_force() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
No unused entries found
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
// Add a stale directory to the cache.
@@ -407,12 +397,10 @@ fn prune_stale_revision() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired exclusive lock for `[CACHE_DIR]/`
Pruning cache at: [CACHE_DIR]/
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v9/[ENTRY]
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
Removed [N] files ([SIZE])
DEBUG Released lock at `[CACHE_DIR]/.lock`
");
// Uninstall and reinstall the package. We should use the cached version.
-2
View File
@@ -18841,7 +18841,6 @@ fn lock_explicit_default_index() -> Result<()> {
----- stderr -----
DEBUG uv [VERSION] ([COMMIT] DATE)
DEBUG Acquired shared lock for `[CACHE_DIR]/`
DEBUG Found workspace root: `[TEMP_DIR]/`
DEBUG Adding root workspace member: `[TEMP_DIR]/`
DEBUG No Python version file found in workspace: [TEMP_DIR]/
@@ -18866,7 +18865,6 @@ fn lock_explicit_default_index() -> Result<()> {
DEBUG No compatible version found for: project
× No solution found when resolving dependencies:
Because anyio was not found in the package registry and your project depends on anyio, we can conclude that your project's requirements are unsatisfiable.
DEBUG Released lock at `[CACHE_DIR]/.lock`
"#);
let lock = fs_err::read_to_string(context.temp_dir.join("uv.lock")).unwrap();