Merge "Upgrade log to 0.4.17"
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 798cd7f..b243187 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,5 +1,6 @@
 {
   "git": {
-    "sha1": "9d4206770dd93f07cb27c3e1f41dc21c45031302"
-  }
-}
+    "sha1": "7fb28c36c7a418912612ab37ab49bd4ca1a3a7f5"
+  },
+  "path_in_vcs": ""
+}
\ No newline at end of file
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 9a8f9aa..18e5c40 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -37,6 +37,8 @@
         rustup update ${{ matrix.rust }} --no-self-update

         rustup default ${{ matrix.rust }}

     - run: cargo test --verbose

+    - run: cargo test --verbose --no-default-features

+    - run: cargo test --verbose --all-features

     - run: cargo test --verbose --features serde

     - run: cargo test --verbose --features std

     - run: cargo test --verbose --features kv_unstable

@@ -74,6 +76,22 @@
       - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_std"

       - run: cargo build --verbose -Z avoid-dev-deps --features "kv_unstable kv_unstable_sval kv_unstable_serde"

 

+  minimalv:

+    name: Minimal versions

+    runs-on: ubuntu-latest

+    steps:

+      - uses: actions/checkout@master

+      - name: Install Rust

+        run: |

+          rustup update nightly --no-self-update

+          rustup default nightly

+      - run: cargo build --verbose -Z minimal-versions --features kv_unstable

+      - run: cargo build --verbose -Z minimal-versions --features "kv_unstable std"

+      - run: cargo build --verbose -Z minimal-versions --features "kv_unstable kv_unstable_sval"

+      - run: cargo build --verbose -Z minimal-versions --features "kv_unstable kv_unstable_serde"

+      - run: cargo build --verbose -Z minimal-versions --features "kv_unstable kv_unstable_std"

+      - run: cargo build --verbose -Z minimal-versions --features "kv_unstable kv_unstable_sval kv_unstable_serde"

+

   msrv:

     name: MSRV

     runs-on: ubuntu-latest

diff --git a/Android.bp b/Android.bp
index 065685f..3c90d98 100644
--- a/Android.bp
+++ b/Android.bp
@@ -40,11 +40,10 @@
 rust_library {
     name: "liblog_rust",
     stem: "liblog",
-    // has rustc warnings
     host_supported: true,
     crate_name: "log",
     cargo_env_compat: true,
-    cargo_pkg_version: "0.4.14",
+    cargo_pkg_version: "0.4.17",
     srcs: ["src/lib.rs"],
     edition: "2015",
     features: ["std"],
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63c3ccd..7d68f89 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,29 @@
 

 ## [Unreleased]

 

+## [0.4.17] - 2022-04-29

+

+* Update `kv_unstable` internal dependencies.

+

+## [0.4.16] - 2022-03-22

+

+* Fix a conflict with unqualified `Option` use in macros.

+

+## [0.4.15] - 2022-02-23

+

+* Silence a warning about the deprecated `spin_loop_hint`.

+* Relax ordering in the atomic `set_max_level` call.

+* Add thumbv4t-none-eabi to targets that don't support atomics

+* Allow levels to be iterated over.

+* Implement `Log` on some common wrapper types.

+* Improvements to test coverage.

+* Improvements to documentation.

+* Add key-value support to the `log!` macros.

+* Tighten `kv_unstable` internal dependencies so they don't bump past their current alpha.

+* Add a simple visit API to `kv_unstable`.

+* Support `NonZero*` integers as values in structured logging

+* Support static strings as keys in structured logging

+

 ## [0.4.14] - 2021-01-27

 

 * Remove the `__private_api_log_lit` special case.

@@ -196,7 +219,10 @@
 

 Look at the [release tags] for information about older releases.

 

-[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.14...HEAD

+[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.17...HEAD

+[0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17

+[0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16

+[0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15

 [0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14

 [0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13

 [0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12

diff --git a/Cargo.toml b/Cargo.toml
index 3cbe5e0..5fed87f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -3,28 +3,36 @@
 # When uploading crates to the registry Cargo will automatically
 # "normalize" Cargo.toml files for maximal compatibility
 # with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies
+# to registry (e.g., crates.io) dependencies.
 #
-# If you believe there's an error in this file please file an
-# issue against the rust-lang/cargo repository. If you're
-# editing this file be aware that the upstream Cargo.toml
-# will likely look very different (and much more reasonable)
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
 
 [package]
 name = "log"
-version = "0.4.14"
+version = "0.4.17"
 authors = ["The Rust Project Developers"]
 build = "build.rs"
-exclude = ["rfcs/**/*", "/.travis.yml", "/appveyor.yml"]
-description = "A lightweight logging facade for Rust\n"
+exclude = ["rfcs/**/*"]
+description = """
+A lightweight logging facade for Rust
+"""
 documentation = "https://docs.rs/log"
 readme = "README.md"
 keywords = ["logging"]
 categories = ["development-tools::debugging"]
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/log"
+
 [package.metadata.docs.rs]
-features = ["std", "serde", "kv_unstable_std", "kv_unstable_sval", "kv_unstable_serde"]
+features = [
+    "std",
+    "serde",
+    "kv_unstable_std",
+    "kv_unstable_sval",
+    "kv_unstable_serde",
+]
 
 [[test]]
 name = "filters"
@@ -35,6 +43,7 @@
 name = "macros"
 path = "tests/macros.rs"
 harness = true
+
 [dependencies.cfg-if]
 version = "1.0"
 
@@ -44,14 +53,18 @@
 default-features = false
 
 [dependencies.sval]
-version = "1.0.0-alpha.5"
+version = "=1.0.0-alpha.5"
 optional = true
 default-features = false
 
 [dependencies.value-bag]
-version = "1.0.0-alpha.6"
+version = "=1.0.0-alpha.9"
 optional = true
 default-features = false
+
+[dev-dependencies.rustversion]
+version = "1.0"
+
 [dev-dependencies.serde]
 version = "1.0"
 features = ["derive"]
@@ -60,18 +73,30 @@
 version = "1.0"
 
 [dev-dependencies.sval]
-version = "1.0.0-alpha.5"
+version = "=1.0.0-alpha.5"
 features = ["derive"]
 
 [dev-dependencies.value-bag]
-version = "1.0.0-alpha.6"
+version = "=1.0.0-alpha.9"
 features = ["test"]
 
 [features]
 kv_unstable = ["value-bag"]
-kv_unstable_serde = ["kv_unstable_std", "value-bag/serde", "serde"]
-kv_unstable_std = ["std", "kv_unstable", "value-bag/error"]
-kv_unstable_sval = ["kv_unstable", "value-bag/sval", "sval"]
+kv_unstable_serde = [
+    "kv_unstable_std",
+    "value-bag/serde",
+    "serde",
+]
+kv_unstable_std = [
+    "std",
+    "kv_unstable",
+    "value-bag/error",
+]
+kv_unstable_sval = [
+    "kv_unstable",
+    "value-bag/sval",
+    "sval",
+]
 max_level_debug = []
 max_level_error = []
 max_level_info = []
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 0d31859..9bac9d7 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
 [package]

 

 name = "log"

-version = "0.4.14" # remember to update html_root_url

+version = "0.4.17" # remember to update html_root_url

 authors = ["The Rust Project Developers"]

 license = "MIT OR Apache-2.0"

 readme = "README.md"

@@ -12,7 +12,7 @@
 """

 categories = ["development-tools::debugging"]

 keywords = ["logging"]

-exclude = ["rfcs/**/*", "/.travis.yml", "/appveyor.yml"]

+exclude = ["rfcs/**/*"]

 build = "build.rs"

 

 [package.metadata.docs.rs]

@@ -55,11 +55,12 @@
 [dependencies]

 cfg-if = "1.0"

 serde = { version = "1.0", optional = true, default-features = false }

-sval = { version = "1.0.0-alpha.5", optional = true, default-features = false }

-value-bag = { version = "1.0.0-alpha.6", optional = true, default-features = false }

+sval = { version = "=1.0.0-alpha.5", optional = true, default-features = false }

+value-bag = { version = "=1.0.0-alpha.9", optional = true, default-features = false }

 

 [dev-dependencies]

+rustversion = "1.0"

 serde = { version = "1.0", features = ["derive"] }

 serde_test = "1.0"

-sval = { version = "1.0.0-alpha.5", features = ["derive"] }

-value-bag = { version = "1.0.0-alpha.6", features = ["test"] }

+sval = { version = "=1.0.0-alpha.5", features = ["derive"] }

+value-bag = { version = "=1.0.0-alpha.9", features = ["test"] }

diff --git a/METADATA b/METADATA
index 86f9298..1078fee 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/log
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
 name: "log"
 description: "A lightweight logging facade for Rust"
 third_party {
@@ -7,13 +11,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://static.crates.io/crates/log/log-0.4.14.crate"
+    value: "https://static.crates.io/crates/log/log-0.4.17.crate"
   }
-  version: "0.4.14"
+  version: "0.4.17"
   license_type: NOTICE
   last_upgrade_date {
-    year: 2021
-    month: 4
-    day: 2
+    year: 2022
+    month: 12
+    day: 12
   }
 }
diff --git a/README.md b/README.md
index 0f87ba7..7fa4353 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@
 

 ## Usage

 

-## In libraries

+### In libraries

 

 Libraries should link only to the `log` crate, and use the provided macros to

 log whatever information will be useful to downstream consumers:

@@ -55,15 +55,15 @@
 }

 ```

 

-## In executables

+### In executables

 

 In order to produce log output, executables have to use a logger implementation compatible with the facade.

 There are many available implementations to choose from, here are some of the most popular ones:

 

 * Simple minimal loggers:

     * [`env_logger`](https://docs.rs/env_logger/*/env_logger/)

-    * [`simple_logger`](https://github.com/borntyping/rust-simple_logger)

-    * [`simplelog`](https://github.com/drakulix/simplelog.rs)

+    * [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/)

+    * [`simplelog`](https://docs.rs/simplelog/*/simplelog/)

     * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/)

     * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/)

     * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/)

@@ -72,11 +72,17 @@
     * [`fern`](https://docs.rs/fern/*/fern/)

 * Adaptors for other facilities:

     * [`syslog`](https://docs.rs/syslog/*/syslog/)

+    * [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/)

     * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/)

     * [`android_log`](https://docs.rs/android_log/*/android_log/)

     * [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/)

+    * [`db_logger`](https://docs.rs/db_logger/*/db_logger/)

 * For WebAssembly binaries:

     * [`console_log`](https://docs.rs/console_log/*/console_log/)

+* For dynamic libraries:

+    * You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries. 

+* Utilities:

+    * [`log_err`](https://docs.rs/log_err/*/log_err/)

 

 Executables should choose a logger implementation and initialize it early in the

 runtime of the program. Logger implementations will typically include a

@@ -84,3 +90,28 @@
 initialized will be ignored.

 

 The executable itself may use the `log` crate to log as well.

+

+## Structured logging

+

+If you enable the `kv_unstable` feature, you can associate structured data with your log records:

+

+```rust

+use log::{info, trace, warn, as_serde, as_error};

+

+pub fn shave_the_yak(yak: &mut Yak) {

+    trace!(target = "yak_events", yak = as_serde!(yak); "Commencing yak shaving");

+

+    loop {

+        match find_a_razor() {

+            Ok(razor) => {

+                info!(razor = razor; "Razor located");

+                yak.shave(razor);

+                break;

+            }

+            Err(err) => {

+                warn!(err = as_error!(err); "Unable to locate a razor, retrying");

+            }

+        }

+    }

+}

+```

diff --git a/build.rs b/build.rs
index 22cfa78..30c7edb 100644
--- a/build.rs
+++ b/build.rs
@@ -33,7 +33,10 @@
 

 fn target_has_atomics(target: &str) -> bool {

     match &target[..] {

-        "msp430-none-elf" | "riscv32i-unknown-none-elf" | "riscv32imc-unknown-none-elf" => false,

+        "thumbv4t-none-eabi"

+        | "msp430-none-elf"

+        | "riscv32i-unknown-none-elf"

+        | "riscv32imc-unknown-none-elf" => false,

         _ => true,

     }

 }

diff --git a/src/kv/error.rs b/src/kv/error.rs
index f68f2da..1adad23 100644
--- a/src/kv/error.rs
+++ b/src/kv/error.rs
@@ -11,6 +11,7 @@
     #[cfg(feature = "std")]

     Boxed(std_support::BoxedError),

     Msg(&'static str),

+    Value(value_bag::Error),

     Fmt,

 }

 

@@ -21,6 +22,24 @@
             inner: Inner::Msg(msg),

         }

     }

+

+    // Not public so we don't leak the `value_bag` API

+    pub(super) fn from_value(err: value_bag::Error) -> Self {

+        Error {

+            inner: Inner::Value(err),

+        }

+    }

+

+    // Not public so we don't leak the `value_bag` API

+    pub(super) fn into_value(self) -> value_bag::Error {

+        match self.inner {

+            Inner::Value(err) => err,

+            #[cfg(feature = "kv_unstable_std")]

+            _ => value_bag::Error::boxed(self),

+            #[cfg(not(feature = "kv_unstable_std"))]

+            _ => value_bag::Error::msg("error inspecting a value"),

+        }

+    }

 }

 

 impl fmt::Display for Error {

@@ -29,6 +48,7 @@
         match &self.inner {

             #[cfg(feature = "std")]

             &Boxed(ref err) => err.fmt(f),

+            &Value(ref err) => err.fmt(f),

             &Msg(ref msg) => msg.fmt(f),

             &Fmt => fmt::Error.fmt(f),

         }

diff --git a/src/kv/value.rs b/src/kv/value.rs
index 942d59e..9730f47 100644
--- a/src/kv/value.rs
+++ b/src/kv/value.rs
@@ -37,6 +37,49 @@
     }

 }

 

+/// Get a value from a type implementing `std::fmt::Debug`.

+#[macro_export]

+macro_rules! as_debug {

+    ($capture:expr) => {

+        $crate::kv::Value::from_debug(&$capture)

+    };

+}

+

+/// Get a value from a type implementing `std::fmt::Display`.

+#[macro_export]

+macro_rules! as_display {

+    ($capture:expr) => {

+        $crate::kv::Value::from_display(&$capture)

+    };

+}

+

+/// Get a value from an error.

+#[cfg(feature = "kv_unstable_std")]

+#[macro_export]

+macro_rules! as_error {

+    ($capture:expr) => {

+        $crate::kv::Value::from_dyn_error(&$capture)

+    };

+}

+

+#[cfg(feature = "kv_unstable_serde")]

+/// Get a value from a type implementing `serde::Serialize`.

+#[macro_export]

+macro_rules! as_serde {

+    ($capture:expr) => {

+        $crate::kv::Value::from_serde(&$capture)

+    };

+}

+

+/// Get a value from a type implementing `sval::value::Value`.

+#[cfg(feature = "kv_unstable_sval")]

+#[macro_export]

+macro_rules! as_sval {

+    ($capture:expr) => {

+        $crate::kv::Value::from_sval(&$capture)

+    };

+}

+

 /// A value in a structured key-value pair.

 ///

 /// # Capturing values

@@ -263,6 +306,78 @@
     pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {

         self.inner.downcast_ref::<T>()

     }

+

+    /// Inspect this value using a simple visitor.

+    pub fn visit(&self, visitor: impl Visit<'v>) -> Result<(), Error> {

+        struct Visitor<V>(V);

+

+        impl<'v, V> value_bag::visit::Visit<'v> for Visitor<V>

+        where

+            V: Visit<'v>,

+        {

+            fn visit_any(&mut self, value: ValueBag) -> Result<(), value_bag::Error> {

+                self.0

+                    .visit_any(Value { inner: value })

+                    .map_err(Error::into_value)

+            }

+

+            fn visit_u64(&mut self, value: u64) -> Result<(), value_bag::Error> {

+                self.0.visit_u64(value).map_err(Error::into_value)

+            }

+

+            fn visit_i64(&mut self, value: i64) -> Result<(), value_bag::Error> {

+                self.0.visit_i64(value).map_err(Error::into_value)

+            }

+

+            fn visit_u128(&mut self, value: u128) -> Result<(), value_bag::Error> {

+                self.0.visit_u128(value).map_err(Error::into_value)

+            }

+

+            fn visit_i128(&mut self, value: i128) -> Result<(), value_bag::Error> {

+                self.0.visit_i128(value).map_err(Error::into_value)

+            }

+

+            fn visit_f64(&mut self, value: f64) -> Result<(), value_bag::Error> {

+                self.0.visit_f64(value).map_err(Error::into_value)

+            }

+

+            fn visit_bool(&mut self, value: bool) -> Result<(), value_bag::Error> {

+                self.0.visit_bool(value).map_err(Error::into_value)

+            }

+

+            fn visit_str(&mut self, value: &str) -> Result<(), value_bag::Error> {

+                self.0.visit_str(value).map_err(Error::into_value)

+            }

+

+            fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), value_bag::Error> {

+                self.0.visit_borrowed_str(value).map_err(Error::into_value)

+            }

+

+            fn visit_char(&mut self, value: char) -> Result<(), value_bag::Error> {

+                self.0.visit_char(value).map_err(Error::into_value)

+            }

+

+            #[cfg(feature = "kv_unstable_std")]

+            fn visit_error(

+                &mut self,

+                err: &(dyn std::error::Error + 'static),

+            ) -> Result<(), value_bag::Error> {

+                self.0.visit_error(err).map_err(Error::into_value)

+            }

+

+            #[cfg(feature = "kv_unstable_std")]

+            fn visit_borrowed_error(

+                &mut self,

+                err: &'v (dyn std::error::Error + 'static),

+            ) -> Result<(), value_bag::Error> {

+                self.0.visit_borrowed_error(err).map_err(Error::into_value)

+            }

+        }

+

+        self.inner

+            .visit(&mut Visitor(visitor))

+            .map_err(Error::from_value)

+    }

 }

 

 impl<'v> fmt::Debug for Value<'v> {

@@ -326,12 +441,62 @@
     }

 }

 

+impl ToValue for u128 {

+    fn to_value(&self) -> Value {

+        Value::from(self)

+    }

+}

+

+impl ToValue for i128 {

+    fn to_value(&self) -> Value {

+        Value::from(self)

+    }

+}

+

+impl ToValue for std::num::NonZeroU128 {

+    fn to_value(&self) -> Value {

+        Value::from(self)

+    }

+}

+

+impl ToValue for std::num::NonZeroI128 {

+    fn to_value(&self) -> Value {

+        Value::from(self)

+    }

+}

+

 impl<'v> From<&'v str> for Value<'v> {

     fn from(value: &'v str) -> Self {

         Value::from_value_bag(value)

     }

 }

 

+impl<'v> From<&'v u128> for Value<'v> {

+    fn from(value: &'v u128) -> Self {

+        Value::from_value_bag(value)

+    }

+}

+

+impl<'v> From<&'v i128> for Value<'v> {

+    fn from(value: &'v i128) -> Self {

+        Value::from_value_bag(value)

+    }

+}

+

+impl<'v> From<&'v std::num::NonZeroU128> for Value<'v> {

+    fn from(v: &'v std::num::NonZeroU128) -> Value<'v> {

+        // SAFETY: `NonZeroU128` and `u128` have the same ABI

+        Value::from_value_bag(unsafe { std::mem::transmute::<&std::num::NonZeroU128, &u128>(v) })

+    }

+}

+

+impl<'v> From<&'v std::num::NonZeroI128> for Value<'v> {

+    fn from(v: &'v std::num::NonZeroI128) -> Value<'v> {

+        // SAFETY: `NonZeroI128` and `i128` have the same ABI

+        Value::from_value_bag(unsafe { std::mem::transmute::<&std::num::NonZeroI128, &i128>(v) })

+    }

+}

+

 impl ToValue for () {

     fn to_value(&self) -> Value {

         Value::from_value_bag(())

@@ -368,6 +533,24 @@
     };

 }

 

+macro_rules! impl_to_value_nonzero_primitive {

+    ($($into_ty:ident,)*) => {

+        $(

+            impl ToValue for std::num::$into_ty {

+                fn to_value(&self) -> Value {

+                    Value::from(self.get())

+                }

+            }

+

+            impl<'v> From<std::num::$into_ty> for Value<'v> {

+                fn from(value: std::num::$into_ty) -> Self {

+                    Value::from(value.get())

+                }

+            }

+        )*

+    };

+}

+

 macro_rules! impl_value_to_primitive {

     ($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => {

         impl<'v> Value<'v> {

@@ -381,8 +564,12 @@
     }

 }

 

-impl_to_value_primitive![

-    usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool,

+impl_to_value_primitive![usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32, f64, char, bool,];

+

+#[rustfmt::skip]

+impl_to_value_nonzero_primitive![

+    NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64,

+    NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64,

 ];

 

 impl_value_to_primitive![

@@ -448,6 +635,142 @@
             self.inner.to_str()

         }

     }

+

+    impl<'v> From<&'v String> for Value<'v> {

+        fn from(v: &'v String) -> Self {

+            Value::from(&**v)

+        }

+    }

+}

+

+/// A visitor for a `Value`.

+pub trait Visit<'v> {

+    /// Visit a `Value`.

+    ///

+    /// This is the only required method on `Visit` and acts as a fallback for any

+    /// more specific methods that aren't overridden.

+    /// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation,

+    /// or serialized using its `sval::Value` or `serde::Serialize` implementation.

+    fn visit_any(&mut self, value: Value) -> Result<(), Error>;

+

+    /// Visit an unsigned integer.

+    fn visit_u64(&mut self, value: u64) -> Result<(), Error> {

+        self.visit_any(value.into())

+    }

+

+    /// Visit a signed integer.

+    fn visit_i64(&mut self, value: i64) -> Result<(), Error> {

+        self.visit_any(value.into())

+    }

+

+    /// Visit a big unsigned integer.

+    fn visit_u128(&mut self, value: u128) -> Result<(), Error> {

+        self.visit_any((&value).into())

+    }

+

+    /// Visit a big signed integer.

+    fn visit_i128(&mut self, value: i128) -> Result<(), Error> {

+        self.visit_any((&value).into())

+    }

+

+    /// Visit a floating point.

+    fn visit_f64(&mut self, value: f64) -> Result<(), Error> {

+        self.visit_any(value.into())

+    }

+

+    /// Visit a boolean.

+    fn visit_bool(&mut self, value: bool) -> Result<(), Error> {

+        self.visit_any(value.into())

+    }

+

+    /// Visit a string.

+    fn visit_str(&mut self, value: &str) -> Result<(), Error> {

+        self.visit_any(value.into())

+    }

+

+    /// Visit a string.

+    fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {

+        self.visit_str(value)

+    }

+

+    /// Visit a Unicode character.

+    fn visit_char(&mut self, value: char) -> Result<(), Error> {

+        let mut b = [0; 4];

+        self.visit_str(&*value.encode_utf8(&mut b))

+    }

+

+    /// Visit an error.

+    #[cfg(feature = "kv_unstable_std")]

+    fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {

+        self.visit_any(Value::from_dyn_error(err))

+    }

+

+    /// Visit an error.

+    #[cfg(feature = "kv_unstable_std")]

+    fn visit_borrowed_error(

+        &mut self,

+        err: &'v (dyn std::error::Error + 'static),

+    ) -> Result<(), Error> {

+        self.visit_any(Value::from_dyn_error(err))

+    }

+}

+

+impl<'a, 'v, T: ?Sized> Visit<'v> for &'a mut T

+where

+    T: Visit<'v>,

+{

+    fn visit_any(&mut self, value: Value) -> Result<(), Error> {

+        (**self).visit_any(value)

+    }

+

+    fn visit_u64(&mut self, value: u64) -> Result<(), Error> {

+        (**self).visit_u64(value)

+    }

+

+    fn visit_i64(&mut self, value: i64) -> Result<(), Error> {

+        (**self).visit_i64(value)

+    }

+

+    fn visit_u128(&mut self, value: u128) -> Result<(), Error> {

+        (**self).visit_u128(value)

+    }

+

+    fn visit_i128(&mut self, value: i128) -> Result<(), Error> {

+        (**self).visit_i128(value)

+    }

+

+    fn visit_f64(&mut self, value: f64) -> Result<(), Error> {

+        (**self).visit_f64(value)

+    }

+

+    fn visit_bool(&mut self, value: bool) -> Result<(), Error> {

+        (**self).visit_bool(value)

+    }

+

+    fn visit_str(&mut self, value: &str) -> Result<(), Error> {

+        (**self).visit_str(value)

+    }

+

+    fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {

+        (**self).visit_borrowed_str(value)

+    }

+

+    fn visit_char(&mut self, value: char) -> Result<(), Error> {

+        (**self).visit_char(value)

+    }

+

+    #[cfg(feature = "kv_unstable_std")]

+    fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {

+        (**self).visit_error(err)

+    }

+

+    #[cfg(feature = "kv_unstable_std")]

+    fn visit_borrowed_error(

+        &mut self,

+        err: &'v (dyn std::error::Error + 'static),

+    ) -> Result<(), Error> {

+        (**self).visit_borrowed_error(err)

+    }

 }

 

 #[cfg(test)]

@@ -469,6 +792,11 @@
             Value::from(32u32),

             Value::from(64u64),

             Value::from(1usize),

+            Value::from(std::num::NonZeroU8::new(8).unwrap()),

+            Value::from(std::num::NonZeroU16::new(16).unwrap()),

+            Value::from(std::num::NonZeroU32::new(32).unwrap()),

+            Value::from(std::num::NonZeroU64::new(64).unwrap()),

+            Value::from(std::num::NonZeroUsize::new(1).unwrap()),

         ]

         .into_iter()

     }

@@ -480,6 +808,11 @@
             Value::from(-32i32),

             Value::from(-64i64),

             Value::from(-1isize),

+            Value::from(std::num::NonZeroI8::new(-8).unwrap()),

+            Value::from(std::num::NonZeroI16::new(-16).unwrap()),

+            Value::from(std::num::NonZeroI32::new(-32).unwrap()),

+            Value::from(std::num::NonZeroI64::new(-64).unwrap()),

+            Value::from(std::num::NonZeroIsize::new(-1).unwrap()),

         ]

         .into_iter()

     }

@@ -652,4 +985,50 @@
         assert!(v.is::<Foo>());

         assert_eq!(42u64, v.downcast_ref::<Foo>().expect("invalid downcast").0);

     }

+

+    #[test]

+    fn test_visit_integer() {

+        struct Extract(Option<u64>);

+

+        impl<'v> Visit<'v> for Extract {

+            fn visit_any(&mut self, value: Value) -> Result<(), Error> {

+                unimplemented!("unexpected value: {:?}", value)

+            }

+

+            fn visit_u64(&mut self, value: u64) -> Result<(), Error> {

+                self.0 = Some(value);

+

+                Ok(())

+            }

+        }

+

+        let mut extract = Extract(None);

+        Value::from(42u64).visit(&mut extract).unwrap();

+

+        assert_eq!(Some(42), extract.0);

+    }

+

+    #[test]

+    fn test_visit_borrowed_str() {

+        struct Extract<'v>(Option<&'v str>);

+

+        impl<'v> Visit<'v> for Extract<'v> {

+            fn visit_any(&mut self, value: Value) -> Result<(), Error> {

+                unimplemented!("unexpected value: {:?}", value)

+            }

+

+            fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {

+                self.0 = Some(value);

+

+                Ok(())

+            }

+        }

+

+        let mut extract = Extract(None);

+

+        let short_lived = String::from("A short-lived string");

+        Value::from(&*short_lived).visit(&mut extract).unwrap();

+

+        assert_eq!(Some("A short-lived string"), extract.0);

+    }

 }

diff --git a/src/lib.rs b/src/lib.rs
index e754268..4ead826 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -24,7 +24,7 @@
 //! though that default may be overridden. Logger implementations typically use

 //! the target to filter requests based on some user configuration.

 //!

-//! # Use

+//! # Usage

 //!

 //! The basic use of the log crate is through the five logging macros: [`error!`],

 //! [`warn!`], [`info!`], [`debug!`] and [`trace!`]

@@ -86,6 +86,42 @@
 //!

 //! The logging system may only be initialized once.

 //!

+//! ## Structured logging

+//!

+//! If you enable the `kv_unstable` feature you can associate structured values

+//! with your log records. If we take the example from before, we can include

+//! some additional context besides what's in the formatted message:

+//!

+//! ```edition2018

+//! # #[macro_use] extern crate serde;

+//! # #[derive(Debug, Serialize)] pub struct Yak(String);

+//! # impl Yak { fn shave(&mut self, _: u32) {} }

+//! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) }

+//! # #[cfg(feature = "kv_unstable_serde")]

+//! # fn main() {

+//! use log::{info, warn, as_serde, as_error};

+//!

+//! pub fn shave_the_yak(yak: &mut Yak) {

+//!     info!(target: "yak_events", yak = as_serde!(yak); "Commencing yak shaving");

+//!

+//!     loop {

+//!         match find_a_razor() {

+//!             Ok(razor) => {

+//!                 info!(razor = razor; "Razor located");

+//!                 yak.shave(razor);

+//!                 break;

+//!             }

+//!             Err(err) => {

+//!                 warn!(err = as_error!(err); "Unable to locate a razor, retrying");

+//!             }

+//!         }

+//!     }

+//! }

+//! # }

+//! # #[cfg(not(feature = "kv_unstable_serde"))]

+//! # fn main() {}

+//! ```

+//!

 //! # Available logging implementations

 //!

 //! In order to produce log output executables have to use

@@ -106,6 +142,14 @@
 //! * Adaptors for other facilities:

 //!     * [syslog]

 //!     * [slog-stdlog]

+//!     * [systemd-journal-logger]

+//!     * [android_log]

+//!     * [win_dbg_logger]

+//!     * [db_logger]

+//! * For WebAssembly binaries:

+//!     * [console_log]

+//! * For dynamic libraries:

+//!     * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries

 //!

 //! # Implementing a Logger

 //!

@@ -262,14 +306,18 @@
 //! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/

 //! [log4rs]: https://docs.rs/log4rs/*/log4rs/

 //! [fern]: https://docs.rs/fern/*/fern/

+//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/

+//! [android_log]: https://docs.rs/android_log/*/android_log/

+//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/

+//! [console_log]: https://docs.rs/console_log/*/console_log/

 

 #![doc(

     html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",

     html_favicon_url = "https://www.rust-lang.org/favicon.ico",

-    html_root_url = "https://docs.rs/log/0.4.14"

+    html_root_url = "https://docs.rs/log/0.4.17"

 )]

 #![warn(missing_docs)]

-#![deny(missing_debug_implementations)]

+#![deny(missing_debug_implementations, unconditional_recursion)]

 #![cfg_attr(all(not(feature = "std"), not(test)), no_std)]

 // When compiled for the rustc compiler itself we want to make sure that this is

 // an unstable crate

@@ -560,6 +608,24 @@
     pub fn as_str(&self) -> &'static str {

         LOG_LEVEL_NAMES[*self as usize]

     }

+

+    /// Iterate through all supported logging levels.

+    ///

+    /// The order of iteration is from more severe to less severe log messages.

+    ///

+    /// # Examples

+    ///

+    /// ```

+    /// use log::Level;

+    ///

+    /// let mut levels = Level::iter();

+    ///

+    /// assert_eq!(Some(Level::Error), levels.next());

+    /// assert_eq!(Some(Level::Trace), levels.last());

+    /// ```

+    pub fn iter() -> impl Iterator<Item = Self> {

+        (1..6).map(|i| Self::from_usize(i).unwrap())

+    }

 }

 

 /// An enum representing the available verbosity level filters of the logger.

@@ -702,6 +768,7 @@
             _ => None,

         }

     }

+

     /// Returns the most verbose logging level filter.

     #[inline]

     pub fn max() -> LevelFilter {

@@ -722,6 +789,24 @@
     pub fn as_str(&self) -> &'static str {

         LOG_LEVEL_NAMES[*self as usize]

     }

+

+    /// Iterate through all supported filtering levels.

+    ///

+    /// The order of iteration is from less to more verbose filtering.

+    ///

+    /// # Examples

+    ///

+    /// ```

+    /// use log::LevelFilter;

+    ///

+    /// let mut levels = LevelFilter::iter();

+    ///

+    /// assert_eq!(Some(LevelFilter::Off), levels.next());

+    /// assert_eq!(Some(LevelFilter::Trace), levels.last());

+    /// ```

+    pub fn iter() -> impl Iterator<Item = Self> {

+        (0..6).map(|i| Self::from_usize(i).unwrap())

+    }

 }

 

 #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]

@@ -880,7 +965,7 @@
         self.line

     }

 

-    /// The structued key-value pairs associated with the message.

+    /// The structured key-value pairs associated with the message.

     #[cfg(feature = "kv_unstable")]

     #[inline]

     pub fn key_values(&self) -> &dyn kv::Source {

@@ -915,7 +1000,6 @@
 ///

 /// # Examples

 ///

-///

 /// ```edition2018

 /// use log::{Level, Record};

 ///

@@ -1189,10 +1273,18 @@
     /// This is used by the `log_enabled!` macro to allow callers to avoid

     /// expensive computation of log message arguments if the message would be

     /// discarded anyway.

+    ///

+    /// # For implementors

+    ///

+    /// This method isn't called automatically by the `log!` macros.

+    /// It's up to an implementation of the `Log` trait to call `enabled` in its own

+    /// `log` method implementation to guarantee that filtering is applied.

     fn enabled(&self, metadata: &Metadata) -> bool;

 

     /// Logs the `Record`.

     ///

+    /// # For implementors

+    ///

     /// Note that `enabled` is *not* necessarily called before this method.

     /// Implementations of `log` should perform all necessary filtering

     /// internally.

@@ -1214,6 +1306,22 @@
     fn flush(&self) {}

 }

 

+impl<T> Log for &'_ T

+where

+    T: ?Sized + Log,

+{

+    fn enabled(&self, metadata: &Metadata) -> bool {

+        (**self).enabled(metadata)

+    }

+

+    fn log(&self, record: &Record) {

+        (**self).log(record)

+    }

+    fn flush(&self) {

+        (**self).flush()

+    }

+}

+

 #[cfg(feature = "std")]

 impl<T> Log for std::boxed::Box<T>

 where

@@ -1231,12 +1339,31 @@
     }

 }

 

+#[cfg(feature = "std")]

+impl<T> Log for std::sync::Arc<T>

+where

+    T: ?Sized + Log,

+{

+    fn enabled(&self, metadata: &Metadata) -> bool {

+        self.as_ref().enabled(metadata)

+    }

+

+    fn log(&self, record: &Record) {

+        self.as_ref().log(record)

+    }

+    fn flush(&self) {

+        self.as_ref().flush()

+    }

+}

+

 /// Sets the global maximum log level.

 ///

 /// Generally, this should only be called by the active logging implementation.

+///

+/// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs.

 #[inline]

 pub fn set_max_level(level: LevelFilter) {

-    MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::SeqCst)

+    MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed)

 }

 

 /// Returns the current maximum log level.

@@ -1362,6 +1489,8 @@
         }

         INITIALIZING => {

             while STATE.load(Ordering::SeqCst) == INITIALIZING {

+                // TODO: replace with `hint::spin_loop` once MSRV is 1.49.0.

+                #[allow(deprecated)]

                 std::sync::atomic::spin_loop_hint();

             }

             Err(SetLoggerError(()))

@@ -1452,11 +1581,19 @@
 

 // WARNING: this is not part of the crate's public API and is subject to change at any time

 #[doc(hidden)]

+#[cfg(not(feature = "kv_unstable"))]

 pub fn __private_api_log(

     args: fmt::Arguments,

     level: Level,

     &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),

+    kvs: Option<&[(&str, &str)]>,

 ) {

+    if kvs.is_some() {

+        panic!(

+            "key-value support is experimental and must be enabled using the `kv_unstable` feature"

+        )

+    }

+

     logger().log(

         &Record::builder()

             .args(args)

@@ -1471,10 +1608,38 @@
 

 // WARNING: this is not part of the crate's public API and is subject to change at any time

 #[doc(hidden)]

+#[cfg(feature = "kv_unstable")]

+pub fn __private_api_log(

+    args: fmt::Arguments,

+    level: Level,

+    &(target, module_path, file, line): &(&str, &'static str, &'static str, u32),

+    kvs: Option<&[(&str, &dyn kv::ToValue)]>,

+) {

+    logger().log(

+        &Record::builder()

+            .args(args)

+            .level(level)

+            .target(target)

+            .module_path_static(Some(module_path))

+            .file_static(Some(file))

+            .line(Some(line))

+            .key_values(&kvs)

+            .build(),

+    );

+}

+

+// WARNING: this is not part of the crate's public API and is subject to change at any time

+#[doc(hidden)]

 pub fn __private_api_enabled(level: Level, target: &str) -> bool {

     logger().enabled(&Metadata::builder().level(level).target(target).build())

 }

 

+// WARNING: this is not part of the crate's public API and is subject to change at any time

+#[doc(hidden)]

+pub mod __private_api {

+    pub use std::option::Option;

+}

+

 /// The statically resolved maximum log level.

 ///

 /// See the crate level documentation for information on how to configure this.

@@ -1772,4 +1937,35 @@
                 .expect("invalid value")

         );

     }

+

+    // Test that the `impl Log for Foo` blocks work

+    // This test mostly operates on a type level, so failures will be compile errors

+    #[test]

+    fn test_foreign_impl() {

+        use super::Log;

+        #[cfg(feature = "std")]

+        use std::sync::Arc;

+

+        fn assert_is_log<T: Log + ?Sized>() {}

+

+        assert_is_log::<&dyn Log>();

+

+        #[cfg(feature = "std")]

+        assert_is_log::<Box<dyn Log>>();

+

+        #[cfg(feature = "std")]

+        assert_is_log::<Arc<dyn Log>>();

+

+        // Assert these statements for all T: Log + ?Sized

+        #[allow(unused)]

+        fn forall<T: Log + ?Sized>() {

+            #[cfg(feature = "std")]

+            assert_is_log::<Box<T>>();

+

+            assert_is_log::<&T>();

+

+            #[cfg(feature = "std")]

+            assert_is_log::<Arc<T>>();

+        }

+    }

 }

diff --git a/src/macros.rs b/src/macros.rs
index a234e04..f214d0d 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -29,6 +29,20 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! log {

+    // log!(target: "my_target", Level::Info; key1 = 42, key2 = true; "a {} event", "log");

+    (target: $target:expr, $lvl:expr, $($key:tt = $value:expr),+; $($arg:tt)+) => ({

+        let lvl = $lvl;

+        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {

+            $crate::__private_api_log(

+                __log_format_args!($($arg)+),

+                lvl,

+                &($target, __log_module_path!(), __log_file!(), __log_line!()),

+                $crate::__private_api::Option::Some(&[$((__log_key!($key), &$value)),+])

+            );

+        }

+    });

+

+    // log!(target: "my_target", Level::Info; "a {} event", "log");

     (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({

         let lvl = $lvl;

         if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {

@@ -36,10 +50,13 @@
                 __log_format_args!($($arg)+),

                 lvl,

                 &($target, __log_module_path!(), __log_file!(), __log_line!()),

+                $crate::__private_api::Option::None,

             );

         }

     });

-    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+))

+

+    // log!(Level::Info, "a log event")

+    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+));

 }

 

 /// Logs a message at the error level.

@@ -58,12 +75,12 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! error {

-    (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Error, $($arg)+)

-    );

-    ($($arg:tt)+) => (

-        log!($crate::Level::Error, $($arg)+)

-    )

+    // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")

+    // error!(target: "my_target", "a {} event", "log")

+    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Error, $($arg)+));

+

+    // error!("a {} event", "log")

+    ($($arg:tt)+) => (log!($crate::Level::Error, $($arg)+))

 }

 

 /// Logs a message at the warn level.

@@ -82,12 +99,12 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! warn {

-    (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Warn, $($arg)+)

-    );

-    ($($arg:tt)+) => (

-        log!($crate::Level::Warn, $($arg)+)

-    )

+    // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")

+    // warn!(target: "my_target", "a {} event", "log")

+    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Warn, $($arg)+));

+

+    // warn!("a {} event", "log")

+    ($($arg:tt)+) => (log!($crate::Level::Warn, $($arg)+))

 }

 

 /// Logs a message at the info level.

@@ -108,12 +125,12 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! info {

-    (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Info, $($arg)+)

-    );

-    ($($arg:tt)+) => (

-        log!($crate::Level::Info, $($arg)+)

-    )

+    // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")

+    // info!(target: "my_target", "a {} event", "log")

+    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Info, $($arg)+));

+

+    // info!("a {} event", "log")

+    ($($arg:tt)+) => (log!($crate::Level::Info, $($arg)+))

 }

 

 /// Logs a message at the debug level.

@@ -133,12 +150,12 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! debug {

-    (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Debug, $($arg)+)

-    );

-    ($($arg:tt)+) => (

-        log!($crate::Level::Debug, $($arg)+)

-    )

+    // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")

+    // debug!(target: "my_target", "a {} event", "log")

+    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Debug, $($arg)+));

+

+    // debug!("a {} event", "log")

+    ($($arg:tt)+) => (log!($crate::Level::Debug, $($arg)+))

 }

 

 /// Logs a message at the trace level.

@@ -160,12 +177,12 @@
 /// ```

 #[macro_export(local_inner_macros)]

 macro_rules! trace {

-    (target: $target:expr, $($arg:tt)+) => (

-        log!(target: $target, $crate::Level::Trace, $($arg)+)

-    );

-    ($($arg:tt)+) => (

-        log!($crate::Level::Trace, $($arg)+)

-    )

+    // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")

+    // trace!(target: "my_target", "a {} event", "log")

+    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Trace, $($arg)+));

+

+    // trace!("a {} event", "log")

+    ($($arg:tt)+) => (log!($crate::Level::Trace, $($arg)+))

 }

 

 /// Determines if a message logged at the specified level in that module will

@@ -248,3 +265,16 @@
         line!()

     };

 }

+

+#[doc(hidden)]

+#[macro_export]

+macro_rules! __log_key {

+    // key1 = 42

+    ($($args:ident)*) => {

+        stringify!($($args)*)

+    };

+    // "key1" = 42

+    ($($args:expr)*) => {

+        $($args)*

+    };

+}