#![warn(missing_docs)]
#![warn(
rust_2018_compatibility,
rust_2018_idioms,
rust_2021_compatibility,
future_incompatible
)]
#![warn(
// Use `core` and `alloc` instead of `std` wherever possible
clippy::alloc_instead_of_core,
clippy::std_instead_of_core,
clippy::std_instead_of_alloc,
)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod key;
pub use self::key::Key;
use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::{sync::Arc, vec::Vec};
use core::str::FromStr;
use core::{convert, fmt, result};
#[cfg(all(not(feature = "std"), has_std_error))]
use core::error::Error as StdError;
#[cfg(feature = "std")]
use std::error::Error as StdError;
#[macro_export(local_inner_macros)]
macro_rules! o(
($($args:tt)*) => {
$crate::OwnedKV(kv!($($args)*))
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_o(
($($args:tt)*) => {
$crate::OwnedKV(slog_kv!($($args)*))
};
);
#[macro_export(local_inner_macros)]
macro_rules! b(
($($args:tt)*) => {
$crate::BorrowedKV(&kv!($($args)*))
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_b(
($($args:tt)*) => {
$crate::BorrowedKV(&slog_kv!($($args)*))
};
);
#[macro_export(local_inner_macros)]
macro_rules! kv(
(@ $args_ready:expr; $k:expr => %$v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => %$v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #%$v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #%$v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => ?$v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:?}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => ?$v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:?}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #?$v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#?}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #?$v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#?}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #$v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@wrap_error $v) )), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #$v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@wrap_error $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => $v:expr) => {
kv!(@ ($crate::SingleKV::from(($k, $v)), $args_ready); )
};
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
kv!(@ ($crate::SingleKV::from(($k, $v)), $args_ready); $($args)* )
};
(@ $args_ready:expr; $kv:expr) => {
kv!(@ ($kv, $args_ready); )
};
(@ $args_ready:expr; $kv:expr, $($args:tt)* ) => {
kv!(@ ($kv, $args_ready); $($args)* )
};
(@ $args_ready:expr; ) => {
$args_ready
};
(@ $args_ready:expr;, ) => {
$args_ready
};
($($args:tt)*) => {
kv!(@ (); $($args)*)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_kv(
(@ $args_ready:expr; $k:expr => %$v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => %$v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #%$v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #%$v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => ?$v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:?}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => ?$v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:?}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #?$v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#?}", $v))), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #?$v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@format_args "{:#?}", $v))), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => #$v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@wrap_error $v) )), $args_ready); )
};
(@ $args_ready:expr; $k:expr => #$v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, __slog_builtin!(@wrap_error $v) )), $args_ready); $($args)* )
};
(@ $args_ready:expr; $k:expr => $v:expr) => {
slog_kv!(@ ($crate::SingleKV::from(($k, $v)), $args_ready); )
};
(@ $args_ready:expr; $k:expr => $v:expr, $($args:tt)* ) => {
slog_kv!(@ ($crate::SingleKV::from(($k, $v)), $args_ready); $($args)* )
};
(@ $args_ready:expr; $slog_kv:expr) => {
slog_kv!(@ ($slog_kv, $args_ready); )
};
(@ $args_ready:expr; $slog_kv:expr, $($args:tt)* ) => {
slog_kv!(@ ($slog_kv, $args_ready); $($args)* )
};
(@ $args_ready:expr; ) => {
$args_ready
};
(@ $args_ready:expr;, ) => {
$args_ready
};
($($args:tt)*) => {
slog_kv!(@ (); $($args)*)
};
);
#[macro_export(local_inner_macros)]
macro_rules! record_static(
($lvl:expr, $tag:expr,) => { record_static!($lvl, $tag) };
($lvl:expr, $tag:expr) => {{
static LOC : $crate::RecordLocation = $crate::RecordLocation {
file: __slog_builtin!(@file),
line: __slog_builtin!(@line),
column: __slog_builtin!(@column),
function: "",
module: __slog_builtin!(@module_path),
};
$crate::RecordStatic {
location : &LOC,
level: $lvl,
tag : $tag,
}
}};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_record_static(
($lvl:expr, $tag:expr,) => { slog_record_static!($lvl, $tag) };
($lvl:expr, $tag:expr) => {{
static LOC : $crate::RecordLocation = $crate::RecordLocation {
file: __slog_builtin!(@file),
line: __slog_builtin!(@line),
column: __slog_builtin!(@column),
function: "",
module: __slog_builtin!(@module_path),
};
$crate::RecordStatic {
location : &LOC,
level: $lvl,
tag: $tag,
}
}};
);
#[macro_export(local_inner_macros)]
macro_rules! record(
($lvl:expr, $tag:expr, $args:expr, $b:expr,) => {
record!($lvl, $tag, $args, $b)
};
($lvl:expr, $tag:expr, $args:expr, $b:expr) => {{
#[allow(dead_code)]
static RS : $crate::RecordStatic<'static> = record_static!($lvl, $tag);
$crate::Record::new(&RS, $args, $b)
}};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_record(
($lvl:expr, $tag:expr, $args:expr, $b:expr,) => {
slog_record!($lvl, $tag, $args, $b)
};
($lvl:expr, $tag:expr, $args:expr, $b:expr) => {{
static RS : $crate::RecordStatic<'static> = slog_record_static!($lvl,
$tag);
$crate::Record::new(&RS, $args, $b)
}};
);
#[macro_export(local_inner_macros)]
macro_rules! log(
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr) => {
$crate::Logger::log(&$l, &record!($lvl, $tag, &__slog_builtin!(@format_args $msg_fmt, $($fmt)*), b!($($kv)*)))
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr,) => {
log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr;) => {
log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $($args:tt)*) => {
log!(2 @ { $($fmt)* }, { $($kv)* $($args)*}, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr) => {
log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr;) => {
log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr,) => {
log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr; $($args:tt)*) => {
log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr, $($args:tt)*) => {
log!(1 @ { $($fmt)* $k = $v, }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr,) => {
log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr) => {
log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, ; $($args:tt)*) => {
log!(1 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt; $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr; $($args:tt)*) => {
log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $f:tt $($args:tt)*) => {
log!(1 @ { $($fmt)* $f }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
($l:expr, $lvl:expr, $tag:expr, $($args:tt)*) => {
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
log!(1 @ { }, { }, $l, $lvl, $tag, $($args)*)
}
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_log(
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr) => {
$crate::Logger::log(&$l, &slog_record!($lvl, $tag, &__slog_builtin!(@format_args $msg_fmt, $($fmt)*), slog_b!($($kv)*)))
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr,) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr;) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(2 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $($args:tt)*) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* $($args)*}, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr) => {
slog_log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr;) => {
slog_log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr,) => {
slog_log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr; $($args:tt)*) => {
slog_log!(2 @ { $($fmt)* $k = $v }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $k:ident = $v:expr, $($args:tt)*) => {
slog_log!(1 @ { $($fmt)* $k = $v, }, { $($kv)* __slog_builtin!(@stringify $k) => $v, }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr,) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, ; $($args:tt)*) => {
slog_log!(1 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt; $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr; $($args:tt)*) => {
slog_log!(2 @ { $($fmt)* }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
(1 @ { $($fmt:tt)* }, { $($kv:tt)* }, $l:expr, $lvl:expr, $tag:expr, $msg_fmt:expr, $f:tt $($args:tt)*) => {
slog_log!(1 @ { $($fmt)* $f }, { $($kv)* }, $l, $lvl, $tag, $msg_fmt, $($args)*)
};
($l:expr, $lvl:expr, $tag:expr, $($args:tt)*) => {
if $lvl.as_usize() <= $crate::__slog_static_max_level().as_usize() {
slog_log!(1 @ { }, { }, $l, $lvl, $tag, $($args)*)
}
};
);
#[macro_export(local_inner_macros)]
macro_rules! crit(
($l:expr, #$tag:expr, $($args:tt)+) => {
log!($l, $crate::Level::Critical, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
log!($l, $crate::Level::Critical, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_crit(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Critical, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Critical, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! error(
($l:expr, #$tag:expr, $($args:tt)+) => {
log!($l, $crate::Level::Error, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
log!($l, $crate::Level::Error, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_error(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Error, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Error, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! warn(
($l:expr, #$tag:expr, $($args:tt)+) => {
log!($l, $crate::Level::Warning, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
log!($l, $crate::Level::Warning, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_warn(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Warning, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Warning, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! info(
($l:expr, #$tag:expr, $($args:tt)*) => {
log!($l, $crate::Level::Info, $tag, $($args)*)
};
($l:expr, $($args:tt)*) => {
log!($l, $crate::Level::Info, "", $($args)*)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_info(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Info, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Info, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! debug(
($l:expr, #$tag:expr, $($args:tt)+) => {
log!($l, $crate::Level::Debug, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
log!($l, $crate::Level::Debug, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_debug(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Debug, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Debug, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! trace(
($l:expr, #$tag:expr, $($args:tt)+) => {
log!($l, $crate::Level::Trace, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
log!($l, $crate::Level::Trace, "", $($args)+)
};
);
#[macro_export(local_inner_macros)]
macro_rules! slog_trace(
($l:expr, #$tag:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Trace, $tag, $($args)+)
};
($l:expr, $($args:tt)+) => {
slog_log!($l, $crate::Level::Trace, "", $($args)+)
};
($($args:tt)+) => {
slog_log!($crate::Level::Trace, $($args)+)
};
);
#[doc(hidden)]
#[macro_export]
macro_rules! __slog_builtin {
(@format_args $($t:tt)*) => ( format_args!($($t)*) );
(@stringify $($t:tt)*) => ( stringify!($($t)*) );
(@file) => ( file!() );
(@line) => ( line!() );
(@column) => ( column!() );
(@module_path) => ( module_path!() );
(@wrap_error $v:expr) => ({
#[allow(unused_imports)]
use $crate::{ErrorRefKind, ErrorValueKind};
let v = $v;
let w = $crate::ErrorTagWrapper(v);
(&&w).slog_error_kind().wrap(w.0)
});
}
#[derive(Clone)]
#[must_use = "does nothing unless used"]
pub struct Logger<D = Arc<dyn SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>>
where
D: SendSyncUnwindSafeDrain<Ok = (), Err = Never>,
{
drain: D,
list: OwnedKVList,
}
impl<D> Logger<D>
where
D: SendSyncUnwindSafeDrain<Ok = (), Err = Never>,
{
pub fn root<T>(drain: D, values: OwnedKV<T>) -> Logger
where
D: 'static + SendSyncRefUnwindSafeDrain<Err = Never, Ok = ()>,
T: SendSyncRefUnwindSafeKV + 'static,
{
Logger {
drain: Arc::new(drain)
as Arc<dyn SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>,
list: OwnedKVList::root(values),
}
}
pub fn root_typed<T>(drain: D, values: OwnedKV<T>) -> Logger<D>
where
D: 'static + SendSyncUnwindSafeDrain<Err = Never, Ok = ()> + Sized,
T: SendSyncRefUnwindSafeKV + 'static,
{
Logger {
drain,
list: OwnedKVList::root(values),
}
}
#[allow(clippy::wrong_self_convention)]
pub fn new<T>(&self, values: OwnedKV<T>) -> Logger<D>
where
T: SendSyncRefUnwindSafeKV + 'static,
D: Clone,
{
Logger {
drain: self.drain.clone(),
list: OwnedKVList::new(values, self.list.node.clone()),
}
}
#[inline]
pub fn log(&self, record: &Record<'_>) {
let _ = self.drain.log(record, &self.list);
}
pub fn list(&self) -> &OwnedKVList {
&self.list
}
pub fn into_erased(
self,
) -> Logger<Arc<dyn SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>>
where
D: SendRefUnwindSafeDrain + 'static,
{
Logger {
drain: Arc::new(self.drain)
as Arc<dyn SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>,
list: self.list,
}
}
pub fn to_erased(
&self,
) -> Logger<Arc<dyn SendSyncRefUnwindSafeDrain<Ok = (), Err = Never>>>
where
D: SendRefUnwindSafeDrain + 'static + Clone,
{
self.clone().into_erased()
}
}
impl<D> fmt::Debug for Logger<D>
where
D: SendSyncUnwindSafeDrain<Ok = (), Err = Never>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Logger{:?}", self.list)?;
Ok(())
}
}
impl<D> Drain for Logger<D>
where
D: SendSyncUnwindSafeDrain<Ok = (), Err = Never>,
{
type Ok = ();
type Err = Never;
fn log(
&self,
record: &Record<'_>,
values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
#[cfg_attr(
feature = "nothreads",
allow(clippy::arc_with_non_send_sync)
)]
let chained = OwnedKVList {
node: Arc::new(MultiListNode {
next_node: values.node.clone(),
node: self.list.node.clone(),
}),
};
self.drain.log(record, &chained)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.drain.is_enabled(level)
}
}
pub trait Drain {
type Ok;
type Err;
fn log(
&self,
record: &Record<'_>,
values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err>;
#[inline]
fn is_enabled(&self, level: Level) -> bool {
level.as_usize() <= crate::__slog_static_max_level().as_usize()
}
#[inline]
fn is_critical_enabled(&self) -> bool {
self.is_enabled(Level::Critical)
}
#[inline]
fn is_error_enabled(&self) -> bool {
self.is_enabled(Level::Error)
}
#[inline]
fn is_warning_enabled(&self) -> bool {
self.is_enabled(Level::Warning)
}
#[inline]
fn is_info_enabled(&self) -> bool {
self.is_enabled(Level::Info)
}
#[inline]
fn is_debug_enabled(&self) -> bool {
self.is_enabled(Level::Debug)
}
#[inline]
fn is_trace_enabled(&self) -> bool {
self.is_enabled(Level::Trace)
}
fn map<F, R>(self, f: F) -> R
where
Self: Sized,
F: FnOnce(Self) -> R,
{
f(self)
}
fn filter<F>(self, f: F) -> Filter<Self, F>
where
Self: Sized,
F: FilterFn,
{
Filter::new(self, f)
}
fn filter_level(self, level: Level) -> LevelFilter<Self>
where
Self: Sized,
{
LevelFilter(self, level)
}
fn map_err<F, E>(self, f: F) -> MapError<Self, E>
where
Self: Sized,
F: MapErrFn<Self::Err, E>,
{
MapError::new(self, f)
}
fn ignore_res(self) -> IgnoreResult<Self>
where
Self: Sized,
{
IgnoreResult::new(self)
}
fn fuse(self) -> Fuse<Self>
where
Self::Err: fmt::Debug,
Self: Sized,
{
self.map(Fuse)
}
}
impl<'a, D: Drain + 'a> Drain for &'a D {
type Ok = D::Ok;
type Err = D::Err;
#[inline]
fn log(
&self,
record: &Record<'_>,
values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
(**self).log(record, values)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
(**self).is_enabled(level)
}
}
impl<'a, D: Drain + 'a> Drain for &'a mut D {
type Ok = D::Ok;
type Err = D::Err;
#[inline]
fn log(
&self,
record: &Record<'_>,
values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
(**self).log(record, values)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
(**self).is_enabled(level)
}
}
mod maybe {
#[cfg(not(feature = "nothreads"))]
use core::marker;
#[cfg(feature = "std")]
use std::panic;
macro_rules! maybe_bound_trait_def {
($name:ident where $bound:path; if cfg($flag:meta)) => {
#[cfg($flag)]
pub trait $name: $bound {}
#[cfg($flag)]
impl<T: $bound + ?Sized> $name for T {}
#[cfg(not($flag))]
pub trait $name {}
#[cfg(not($flag))]
impl<T: ?Sized> $name for T {}
};
}
maybe_bound_trait_def!(UnwindSafe where panic::UnwindSafe; if cfg(feature="std"));
maybe_bound_trait_def!(RefUnwindSafe where panic::RefUnwindSafe; if cfg(feature="std"));
maybe_bound_trait_def!(Sync where marker::Sync; if cfg(not(feature = "nothreads")));
maybe_bound_trait_def!(Send where marker::Send; if cfg(not(feature = "nothreads")));
}
pub trait SendSyncUnwindSafe:
maybe::Send + maybe::Sync + maybe::UnwindSafe
{
}
impl<T> SendSyncUnwindSafe for T where
T: maybe::Send + maybe::Sync + maybe::UnwindSafe + ?Sized
{
}
pub trait SendSyncUnwindSafeDrain:
Drain + maybe::Send + maybe::Sync + maybe::UnwindSafe
{
}
impl<T> SendSyncUnwindSafeDrain for T where
T: Drain + maybe::Send + maybe::Sync + maybe::UnwindSafe + ?Sized
{
}
pub trait SendSyncRefUnwindSafeDrain:
Drain + maybe::Send + maybe::Sync + maybe::RefUnwindSafe
{
}
impl<T> SendSyncRefUnwindSafeDrain for T where
T: Drain + maybe::Send + maybe::Sync + maybe::RefUnwindSafe + ?Sized
{
}
pub trait MapErrFn<EI, EO>:
'static
+ maybe::Sync
+ maybe::Send
+ maybe::UnwindSafe
+ maybe::RefUnwindSafe
+ Fn(EI) -> EO
{
}
impl<T, EI, EO> MapErrFn<EI, EO> for T where
T: 'static
+ maybe::Sync
+ maybe::Send
+ ?Sized
+ maybe::UnwindSafe
+ maybe::RefUnwindSafe
+ Fn(EI) -> EO
{
}
pub trait FilterFn:
'static
+ maybe::Sync
+ maybe::Send
+ maybe::UnwindSafe
+ maybe::RefUnwindSafe
+ Fn(&Record<'_>) -> bool
{
}
impl<T> FilterFn for T where
T: 'static
+ maybe::Sync
+ maybe::Send
+ ?Sized
+ maybe::UnwindSafe
+ maybe::RefUnwindSafe
+ Fn(&Record<'_>) -> bool
{
}
pub trait SendRefUnwindSafeDrain:
Drain + maybe::Send + maybe::RefUnwindSafe
{
}
impl<T> SendRefUnwindSafeDrain for T where
T: Drain + maybe::Send + maybe::RefUnwindSafe + ?Sized
{
}
impl<D: Drain + ?Sized> Drain for Box<D> {
type Ok = D::Ok;
type Err = D::Err;
fn log(
&self,
record: &Record<'_>,
o: &OwnedKVList,
) -> result::Result<Self::Ok, D::Err> {
(**self).log(record, o)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
(**self).is_enabled(level)
}
}
impl<D: Drain + ?Sized> Drain for Arc<D> {
type Ok = D::Ok;
type Err = D::Err;
fn log(
&self,
record: &Record<'_>,
o: &OwnedKVList,
) -> result::Result<Self::Ok, D::Err> {
(**self).log(record, o)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
(**self).is_enabled(level)
}
}
#[derive(Debug, Copy, Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct Discard;
impl Drain for Discard {
type Ok = ();
type Err = Never;
fn log(
&self,
_: &Record<'_>,
_: &OwnedKVList,
) -> result::Result<(), Never> {
Ok(())
}
#[inline]
fn is_enabled(&self, _level: Level) -> bool {
false
}
}
#[derive(Debug, Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct Filter<D: Drain, F>(pub D, pub F)
where
F: Fn(&Record<'_>) -> bool + 'static + maybe::Send + maybe::Sync;
impl<D: Drain, F> Filter<D, F>
where
F: FilterFn,
{
pub fn new(drain: D, cond: F) -> Self {
Filter(drain, cond)
}
}
impl<D: Drain, F> Drain for Filter<D, F>
where
F: FilterFn,
{
type Ok = Option<D::Ok>;
type Err = D::Err;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
if (self.1)(record) {
Ok(Some(self.0.log(record, logger_values)?))
} else {
Ok(None)
}
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.0.is_enabled(level)
}
}
#[derive(Debug, Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct LevelFilter<D: Drain>(pub D, pub Level);
impl<D: Drain> LevelFilter<D> {
pub fn new(drain: D, level: Level) -> Self {
LevelFilter(drain, level)
}
}
impl<D: Drain> Drain for LevelFilter<D> {
type Ok = Option<D::Ok>;
type Err = D::Err;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
if record.level().is_at_least(self.1) {
Ok(Some(self.0.log(record, logger_values)?))
} else {
Ok(None)
}
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
level.is_at_least(self.1) && self.0.is_enabled(level)
}
}
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct MapError<D: Drain, E> {
drain: D,
map_fn: Box<dyn MapErrFn<D::Err, E, Output = E>>,
}
impl<D: Drain, E> MapError<D, E> {
pub fn new<F>(drain: D, map_fn: F) -> Self
where
F: MapErrFn<<D as Drain>::Err, E>,
{
MapError {
drain,
map_fn: Box::new(map_fn),
}
}
}
impl<D: Drain, E> Drain for MapError<D, E> {
type Ok = D::Ok;
type Err = E;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
self.drain
.log(record, logger_values)
.map_err(|e| (self.map_fn)(e))
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.drain.is_enabled(level)
}
}
#[derive(Debug, Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct Duplicate<D1: Drain, D2: Drain>(pub D1, pub D2);
impl<D1: Drain, D2: Drain> Duplicate<D1, D2> {
pub fn new(drain1: D1, drain2: D2) -> Self {
Duplicate(drain1, drain2)
}
}
impl<D1: Drain, D2: Drain> Drain for Duplicate<D1, D2> {
type Ok = (D1::Ok, D2::Ok);
type Err = (
result::Result<D1::Ok, D1::Err>,
result::Result<D2::Ok, D2::Err>,
);
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
let res1 = self.0.log(record, logger_values);
let res2 = self.1.log(record, logger_values);
match (res1, res2) {
(Ok(o1), Ok(o2)) => Ok((o1, o2)),
(r1, r2) => Err((r1, r2)),
}
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.0.is_enabled(level) || self.1.is_enabled(level)
}
}
#[derive(Debug, Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct Fuse<D: Drain>(pub D)
where
D::Err: fmt::Debug;
impl<D: Drain> Fuse<D>
where
D::Err: fmt::Debug,
{
pub fn new(drain: D) -> Self {
Fuse(drain)
}
}
impl<D: Drain> Drain for Fuse<D>
where
D::Err: fmt::Debug,
{
type Ok = ();
type Err = Never;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Never> {
let _ = self
.0
.log(record, logger_values)
.unwrap_or_else(|e| panic!("slog::Fuse Drain: {:?}", e));
Ok(())
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.0.is_enabled(level)
}
}
#[derive(Clone)]
#[must_use = "does nothing by itself; needs to be attached to Logger"]
pub struct IgnoreResult<D: Drain> {
drain: D,
}
impl<D: Drain> IgnoreResult<D> {
pub fn new(drain: D) -> Self {
IgnoreResult { drain }
}
}
impl<D: Drain> Drain for IgnoreResult<D> {
type Ok = ();
type Err = Never;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<(), Never> {
let _ = self.drain.log(record, logger_values);
Ok(())
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.drain.is_enabled(level)
}
}
#[cfg(feature = "std")]
#[derive(Clone)]
pub enum MutexDrainError<D: Drain> {
Mutex,
Drain(D::Err),
}
#[cfg(feature = "std")]
impl<D> fmt::Debug for MutexDrainError<D>
where
D: Drain,
D::Err: fmt::Debug,
{
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> result::Result<(), fmt::Error> {
match *self {
MutexDrainError::Mutex => write!(f, "MutexDrainError::Mutex"),
MutexDrainError::Drain(ref e) => e.fmt(f),
}
}
}
#[cfg(feature = "std")]
impl<D> StdError for MutexDrainError<D>
where
D: Drain,
D::Err: fmt::Debug + fmt::Display + StdError,
{
#[allow(deprecated)]
fn description(&self) -> &str {
match *self {
MutexDrainError::Mutex => "Mutex acquire failed",
MutexDrainError::Drain(ref e) => e.description(),
}
}
fn cause(&self) -> Option<&dyn StdError> {
match *self {
MutexDrainError::Mutex => None,
MutexDrainError::Drain(ref e) => Some(e),
}
}
}
#[cfg(feature = "std")]
impl<'a, D: Drain> From<std::sync::PoisonError<std::sync::MutexGuard<'a, D>>>
for MutexDrainError<D>
{
fn from(
_: std::sync::PoisonError<std::sync::MutexGuard<'a, D>>,
) -> MutexDrainError<D> {
MutexDrainError::Mutex
}
}
#[cfg(feature = "std")]
impl<D: Drain> fmt::Display for MutexDrainError<D>
where
D::Err: fmt::Display,
{
fn fmt(
&self,
f: &mut fmt::Formatter<'_>,
) -> result::Result<(), fmt::Error> {
match *self {
MutexDrainError::Mutex => write!(f, "MutexError"),
MutexDrainError::Drain(ref e) => write!(f, "{}", e),
}
}
}
#[cfg(feature = "std")]
impl<D: Drain> Drain for std::sync::Mutex<D> {
type Ok = D::Ok;
type Err = MutexDrainError<D>;
fn log(
&self,
record: &Record<'_>,
logger_values: &OwnedKVList,
) -> result::Result<Self::Ok, Self::Err> {
let d = self.lock()?;
d.log(record, logger_values).map_err(MutexDrainError::Drain)
}
#[inline]
fn is_enabled(&self, level: Level) -> bool {
self.lock().ok().map_or(true, |lock| lock.is_enabled(level))
}
}
pub static LOG_LEVEL_NAMES: [&str; 7] = [
"OFF", "CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG", "TRACE",
];
pub static LOG_LEVEL_SHORT_NAMES: [&str; 7] =
["OFF", "CRIT", "ERRO", "WARN", "INFO", "DEBG", "TRCE"];
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum Level {
Critical,
Error,
Warning,
Info,
Debug,
Trace,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
#[must_use = "has no effect unless attached to a drain"]
pub enum FilterLevel {
Off,
Critical,
Error,
Warning,
Info,
Debug,
Trace,
}
impl Level {
pub fn as_short_str(&self) -> &'static str {
LOG_LEVEL_SHORT_NAMES[self.as_usize()]
}
pub fn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[self.as_usize()]
}
#[inline]
pub fn as_usize(&self) -> usize {
match *self {
Level::Critical => 1,
Level::Error => 2,
Level::Warning => 3,
Level::Info => 4,
Level::Debug => 5,
Level::Trace => 6,
}
}
#[inline]
pub fn from_usize(u: usize) -> Option<Level> {
match u {
1 => Some(Level::Critical),
2 => Some(Level::Error),
3 => Some(Level::Warning),
4 => Some(Level::Info),
5 => Some(Level::Debug),
6 => Some(Level::Trace),
_ => None,
}
}
}
impl FilterLevel {
pub fn as_short_str(&self) -> &'static str {
LOG_LEVEL_SHORT_NAMES[self.as_usize()]
}
pub fn as_str(&self) -> &'static str {
LOG_LEVEL_NAMES[self.as_usize()]
}
#[inline]
pub fn as_usize(&self) -> usize {
match *self {
FilterLevel::Off => 0,
FilterLevel::Critical => 1,
FilterLevel::Error => 2,
FilterLevel::Warning => 3,
FilterLevel::Info => 4,
FilterLevel::Debug => 5,
FilterLevel::Trace => 6,
}
}
#[inline]
pub fn from_usize(u: usize) -> Option<FilterLevel> {
match u {
0 => Some(FilterLevel::Off),
1 => Some(FilterLevel::Critical),
2 => Some(FilterLevel::Error),
3 => Some(FilterLevel::Warning),
4 => Some(FilterLevel::Info),
5 => Some(FilterLevel::Debug),
6 => Some(FilterLevel::Trace),
_ => None,
}
}
#[inline]
pub fn max() -> Self {
FilterLevel::Trace
}
#[inline]
pub fn min() -> Self {
FilterLevel::Off
}
pub fn accepts(self, level: Level) -> bool {
self.as_usize() >= level.as_usize()
}
}
impl FromStr for Level {
type Err = ();
fn from_str(name: &str) -> core::result::Result<Level, ()> {
index_of_log_level_name(name)
.and_then(Level::from_usize)
.ok_or(())
}
}
impl FromStr for FilterLevel {
type Err = ();
fn from_str(name: &str) -> core::result::Result<FilterLevel, ()> {
index_of_log_level_name(name)
.and_then(FilterLevel::from_usize)
.ok_or(())
}
}
fn index_of_log_level_name(name: &str) -> Option<usize> {
index_of_str_ignore_case(&LOG_LEVEL_NAMES, name)
.or_else(|| index_of_str_ignore_case(&LOG_LEVEL_SHORT_NAMES, name))
}
fn index_of_str_ignore_case(haystack: &[&str], needle: &str) -> Option<usize> {
if needle.is_empty() {
return None;
}
haystack
.iter()
.map(|hay| &hay[..needle.len().min(hay.len())])
.position(|hay| hay.eq_ignore_ascii_case(needle))
}
impl fmt::Display for Level {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_short_str())
}
}
impl fmt::Display for FilterLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_short_str())
}
}
impl Level {
#[inline]
pub fn is_at_least(&self, level: Self) -> bool {
self.as_usize() <= level.as_usize()
}
}
#[test]
fn level_at_least() {
assert!(Level::Debug.is_at_least(Level::Debug));
assert!(Level::Debug.is_at_least(Level::Trace));
assert!(!Level::Debug.is_at_least(Level::Info));
}
#[test]
fn filter_level_sanity() {
assert!(Level::Critical.as_usize() > FilterLevel::Off.as_usize());
assert!(Level::Critical.as_usize() == FilterLevel::Critical.as_usize());
assert!(Level::Trace.as_usize() == FilterLevel::Trace.as_usize());
}
#[test]
fn level_from_str() {
refute_from_str::<Level>("off");
assert_from_str(Level::Critical, "critical");
assert_from_str(Level::Critical, "crit");
assert_from_str(Level::Error, "error");
assert_from_str(Level::Error, "erro");
assert_from_str(Level::Warning, "warn");
assert_from_str(Level::Info, "info");
assert_from_str(Level::Debug, "debug");
assert_from_str(Level::Debug, "debg");
assert_from_str(Level::Trace, "trace");
assert_from_str(Level::Trace, "trce");
assert_from_str(Level::Info, "Info");
assert_from_str(Level::Info, "INFO");
assert_from_str(Level::Info, "iNfO");
refute_from_str::<Level>("");
assert_from_str(Level::Info, "i");
assert_from_str(Level::Info, "in");
assert_from_str(Level::Info, "inf");
refute_from_str::<Level>("infor");
refute_from_str::<Level>("?");
refute_from_str::<Level>("info ");
refute_from_str::<Level>(" info");
refute_from_str::<Level>("desinfo");
}
#[test]
fn filter_level_from_str() {
assert_from_str(FilterLevel::Off, "off");
assert_from_str(FilterLevel::Critical, "critical");
assert_from_str(FilterLevel::Critical, "crit");
assert_from_str(FilterLevel::Error, "error");
assert_from_str(FilterLevel::Error, "erro");
assert_from_str(FilterLevel::Warning, "warn");
assert_from_str(FilterLevel::Info, "info");
assert_from_str(FilterLevel::Debug, "debug");
assert_from_str(FilterLevel::Debug, "debg");
assert_from_str(FilterLevel::Trace, "trace");
assert_from_str(FilterLevel::Trace, "trce");
assert_from_str(FilterLevel::Info, "Info");
assert_from_str(FilterLevel::Info, "INFO");
assert_from_str(FilterLevel::Info, "iNfO");
refute_from_str::<FilterLevel>("");
assert_from_str(FilterLevel::Info, "i");
assert_from_str(FilterLevel::Info, "in");
assert_from_str(FilterLevel::Info, "inf");
refute_from_str::<FilterLevel>("infor");
refute_from_str::<FilterLevel>("?");
refute_from_str::<FilterLevel>("info ");
refute_from_str::<FilterLevel>(" info");
refute_from_str::<FilterLevel>("desinfo");
}
#[cfg(test)]
fn assert_from_str<T>(expected: T, level_str: &str)
where
T: FromStr + fmt::Debug + PartialEq,
T::Err: fmt::Debug,
{
let result = T::from_str(level_str);
let actual = result.unwrap_or_else(|e| {
panic!("Failed to parse filter level '{}': {:?}", level_str, e)
});
assert_eq!(
expected, actual,
"Invalid filter level parsed from '{}'",
level_str
);
}
#[cfg(test)]
fn refute_from_str<T>(level_str: &str)
where
T: FromStr + fmt::Debug,
{
let result = T::from_str(level_str);
if let Ok(level) = result {
panic!(
"Parsing filter level '{}' succeeded: {:?}",
level_str, level
)
}
}
#[cfg(feature = "std")]
#[test]
fn level_to_string_and_from_str_are_compatible() {
assert_to_string_from_str(Level::Critical);
assert_to_string_from_str(Level::Error);
assert_to_string_from_str(Level::Warning);
assert_to_string_from_str(Level::Info);
assert_to_string_from_str(Level::Debug);
assert_to_string_from_str(Level::Trace);
}
#[cfg(feature = "std")]
#[test]
fn filter_level_to_string_and_from_str_are_compatible() {
assert_to_string_from_str(FilterLevel::Off);
assert_to_string_from_str(FilterLevel::Critical);
assert_to_string_from_str(FilterLevel::Error);
assert_to_string_from_str(FilterLevel::Warning);
assert_to_string_from_str(FilterLevel::Info);
assert_to_string_from_str(FilterLevel::Debug);
assert_to_string_from_str(FilterLevel::Trace);
}
#[cfg(all(test, feature = "std"))]
fn assert_to_string_from_str<T>(expected: T)
where
T: alloc::string::ToString + FromStr + PartialEq + fmt::Debug,
<T as FromStr>::Err: fmt::Debug,
{
let string = expected.to_string();
let actual = T::from_str(&string).unwrap_or_else(|_err| {
panic!("Failed to parse string representation of {:?}", expected)
});
assert_eq!(
expected, actual,
"Invalid value parsed from string representation of {:?}",
actual
);
}
#[test]
fn filter_level_accepts_tests() {
assert!(FilterLevel::Warning.accepts(Level::Error));
assert!(FilterLevel::Warning.accepts(Level::Warning));
assert!(!FilterLevel::Warning.accepts(Level::Info));
assert!(!FilterLevel::Off.accepts(Level::Critical));
}
#[doc(hidden)]
#[derive(Clone, Copy)]
pub struct RecordLocation {
pub file: &'static str,
pub line: u32,
pub column: u32,
pub function: &'static str,
pub module: &'static str,
}
pub struct RecordStatic<'a> {
#[doc(hidden)]
pub location: &'a RecordLocation,
#[doc(hidden)]
pub tag: &'a str,
#[doc(hidden)]
pub level: Level,
}
#[must_use = "does nothing by itself"]
pub struct Record<'a> {
rstatic: &'a RecordStatic<'a>,
msg: &'a fmt::Arguments<'a>,
kv: BorrowedKV<'a>,
}
impl<'a> Record<'a> {
#[inline]
pub fn new(
s: &'a RecordStatic<'a>,
msg: &'a fmt::Arguments<'a>,
kv: BorrowedKV<'a>,
) -> Self {
Record {
rstatic: s,
msg,
kv,
}
}
pub fn msg(&self) -> &fmt::Arguments<'_> {
self.msg
}
pub fn level(&self) -> Level {
self.rstatic.level
}
pub fn line(&self) -> u32 {
self.rstatic.location.line
}
pub fn location(&self) -> &RecordLocation {
self.rstatic.location
}
pub fn column(&self) -> u32 {
self.rstatic.location.column
}
pub fn file(&self) -> &'static str {
self.rstatic.location.file
}
pub fn tag(&self) -> &str {
self.rstatic.tag
}
pub fn module(&self) -> &'static str {
self.rstatic.location.module
}
pub fn function(&self) -> &'static str {
self.rstatic.location.function
}
pub fn kv(&self) -> BorrowedKV<'_> {
BorrowedKV(self.kv.0)
}
}
macro_rules! impl_default_as_fmt{
($(#[$m:meta])* $t:ty => $f:ident) => {
$(#[$m])*
fn $f(&mut self, key : Key, val : $t)
-> Result {
self.emit_arguments(key, &format_args!("{}", val))
}
};
}
#[cfg(feature = "nested-values")]
struct SerializerForward<'a, T: ?Sized>(&'a mut T);
#[cfg(feature = "nested-values")]
impl<'a, T: Serializer + 'a + ?Sized> Serializer for SerializerForward<'a, T> {
fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments<'_>) -> Result {
self.0.emit_arguments(key, val)
}
#[cfg(feature = "nested-values")]
fn emit_serde(&mut self, _key: Key, _value: &dyn SerdeValue) -> Result {
panic!();
}
}
pub trait Serializer {
impl_default_as_fmt! {
usize => emit_usize
}
impl_default_as_fmt! {
isize => emit_isize
}
impl_default_as_fmt! {
bool => emit_bool
}
impl_default_as_fmt! {
char => emit_char
}
impl_default_as_fmt! {
u8 => emit_u8
}
impl_default_as_fmt! {
i8 => emit_i8
}
impl_default_as_fmt! {
u16 => emit_u16
}
impl_default_as_fmt! {
i16 => emit_i16
}
impl_default_as_fmt! {
u32 => emit_u32
}
impl_default_as_fmt! {
i32 => emit_i32
}
impl_default_as_fmt! {
f32 => emit_f32
}
impl_default_as_fmt! {
u64 => emit_u64
}
impl_default_as_fmt! {
i64 => emit_i64
}
impl_default_as_fmt! {
f64 => emit_f64
}
impl_default_as_fmt! {
u128 => emit_u128
}
impl_default_as_fmt! {
i128 => emit_i128
}
impl_default_as_fmt! {
&str => emit_str
}
fn emit_unit(&mut self, key: Key) -> Result {
self.emit_arguments(key, &format_args!("()"))
}
fn emit_none(&mut self, key: Key) -> Result {
self.emit_arguments(key, &format_args!(""))
}
fn emit_bytes(
&mut self,
key: Key,
bytes: &[u8],
kind: BytesKind,
) -> Result {
self.emit_arguments(
key,
&format_args!("{}", BytesAsFmt { bytes, kind }),
)
}
fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments<'_>) -> Result;
#[cfg(feature = "nested-values")]
fn emit_serde(&mut self, key: Key, value: &dyn SerdeValue) -> Result {
value.serialize_fallback(key, &mut SerializerForward(self))
}
#[cfg(has_std_error)]
fn emit_error(
&mut self,
key: Key,
error: &(dyn StdError + 'static),
) -> Result {
self.emit_arguments(key, &format_args!("{}", ErrorAsFmt(error)))
}
}
struct AsFmtSerializer<F>(pub F)
where
F: for<'a> FnMut(Key, fmt::Arguments<'a>) -> Result;
impl<F> Serializer for AsFmtSerializer<F>
where
F: for<'a> FnMut(Key, fmt::Arguments<'a>) -> Result,
{
fn emit_arguments(&mut self, key: Key, val: &fmt::Arguments<'_>) -> Result {
(self.0)(key, *val)
}
}
#[non_exhaustive]
#[derive(Copy, Clone, Debug)]
#[must_use = "does nothing by itself"]
pub enum BytesKind {
Stream,
Value,
PlainValue,
}
impl Default for BytesKind {
#[inline]
fn default() -> BytesKind {
BytesKind::Value
}
}
struct BytesAsFmt<'a> {
bytes: &'a [u8],
kind: BytesKind,
}
impl fmt::Display for BytesAsFmt<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use core::fmt::Write;
let (use_prefix, separate_with_underscore) = match self.kind {
BytesKind::Stream => (true, false),
BytesKind::Value => (true, true),
BytesKind::PlainValue => (false, false),
};
if use_prefix {
f.write_str("0x")?;
}
for (index, byte) in self.bytes.iter().enumerate() {
if separate_with_underscore && (index % 2) == 0 {
f.write_char('_')?;
}
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
#[cfg(has_std_error)]
struct ErrorAsFmt<'a>(pub &'a (dyn StdError + 'static));
#[cfg(has_std_error)]
impl fmt::Display for ErrorAsFmt<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#![allow(deprecated)]
write!(f, "{}", self.0)?;
let mut error = self.0.cause();
while let Some(source) = error {
write!(f, ": {}", source)?;
error = source.cause();
}
Ok(())
}
}
#[cfg(feature = "nested-values")]
pub trait SerdeValue: erased_serde::Serialize + Value {
fn serialize_fallback(
&self,
_key: Key,
_serializer: &mut dyn Serializer,
) -> Result<()> {
#[cfg(feature = "std")]
{
#[derive(Debug)]
struct NestedValuesUnsupportedError {
value_type_name: &'static str,
}
impl fmt::Display for NestedValuesUnsupportedError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Logger does not implement nested-values and {} does not implement serialize_fallback", self.value_type_name)
}
}
impl StdError for NestedValuesUnsupportedError {}
Err(Error::Io(std::io::Error::new(
std::io::ErrorKind::Other,
Box::new(NestedValuesUnsupportedError {
value_type_name: core::any::type_name::<Self>(),
}),
)))
}
#[cfg(not(feature = "std"))]
{
Err(Error::Other)
}
}
fn as_serde(&self) -> &dyn erased_serde::Serialize;
fn to_sendable(&self) -> Box<dyn SerdeValue + Send + 'static>;
}
#[cfg(feature = "nested-values")]
#[derive(Clone)]
#[must_use = "must be passed to logger to actually log"]
pub struct Serde<T>(pub T)
where
T: serde::Serialize + Clone + Send + 'static;
#[cfg(feature = "nested-values")]
impl<T: serde::Serialize + Clone + Send + 'static> serde::Serialize
for Serde<T>
{
#[inline]
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde::Serialize::serialize(&self.0, serializer)
}
}
#[cfg(feature = "nested-values")]
impl<T> SerdeValue for Serde<T>
where
T: serde::Serialize + Clone + Send + 'static,
{
fn as_serde(&self) -> &dyn erased_serde::Serialize {
&self.0
}
fn to_sendable(&self) -> Box<dyn SerdeValue + Send + 'static> {
Box::new(self.clone())
}
}
pub trait Value {
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result;
}
impl<V> Value for &V
where
V: Value + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(*self).serialize(record, key, serializer)
}
}
macro_rules! impl_value_for {
($t:ty, $f:ident) => {
impl Value for $t {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.$f(key, *self)
}
}
};
}
impl_value_for!(usize, emit_usize);
impl_value_for!(isize, emit_isize);
impl_value_for!(bool, emit_bool);
impl_value_for!(char, emit_char);
impl_value_for!(u8, emit_u8);
impl_value_for!(i8, emit_i8);
impl_value_for!(u16, emit_u16);
impl_value_for!(i16, emit_i16);
impl_value_for!(u32, emit_u32);
impl_value_for!(i32, emit_i32);
impl_value_for!(f32, emit_f32);
impl_value_for!(u64, emit_u64);
impl_value_for!(i64, emit_i64);
impl_value_for!(f64, emit_f64);
impl_value_for!(u128, emit_u128);
impl_value_for!(i128, emit_i128);
impl Value for () {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_unit(key)
}
}
impl Value for str {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_str(key, self)
}
}
impl Value for fmt::Arguments<'_> {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_arguments(key, self)
}
}
impl Value for String {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_str(key, self.as_str())
}
}
impl Value for [u8] {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_bytes(key, self, BytesKind::Stream)
}
}
impl Value for Vec<u8> {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_bytes(key, self, BytesKind::Stream)
}
}
impl<T: Value> Value for Option<T> {
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
match *self {
Some(ref s) => s.serialize(record, key, serializer),
None => serializer.emit_none(key),
}
}
}
impl<T> Value for Box<T>
where
T: Value + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, key, serializer)
}
}
impl<T> Value for Arc<T>
where
T: Value + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, key, serializer)
}
}
impl<T> Value for Rc<T>
where
T: Value,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, key, serializer)
}
}
impl<T> Value for core::num::Wrapping<T>
where
T: Value,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
self.0.serialize(record, key, serializer)
}
}
impl<T> Value for Cow<'_, T>
where
T: Value + ToOwned + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, key, serializer)
}
}
#[cfg(feature = "std")]
impl Value for std::path::Display<'_> {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_arguments(key, &format_args!("{}", *self))
}
}
#[cfg(feature = "std")]
impl Value for std::net::SocketAddr {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_arguments(key, &format_args!("{}", self))
}
}
#[cfg(feature = "std")]
impl Value for std::io::Error {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self)
}
}
#[cfg(has_std_error)]
impl Value for dyn StdError + 'static {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self)
}
}
#[cfg(has_std_error)]
impl Value for dyn StdError + Send + 'static {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self)
}
}
#[cfg(has_std_error)]
impl Value for dyn StdError + Send + Sync + 'static {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self)
}
}
#[cfg(feature = "anyhow")]
impl Value for anyhow::Error {
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self.as_ref())
}
}
#[must_use = "must be passed to logger to actually log"]
pub struct FnValue<V: Value, F>(pub F)
where
F: for<'c, 'd> Fn(&'c Record<'d>) -> V;
impl<V: Value, F> Value for FnValue<V, F>
where
F: for<'c, 'd> Fn(&'c Record<'d>) -> V,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
(self.0)(record).serialize(record, key, serializer)
}
}
#[deprecated(note = "Renamed to `PushFnValueSerializer`")]
pub type PushFnSerializer<'a> = PushFnValueSerializer<'a>;
#[must_use = "must be passed to logger to actually log"]
pub struct PushFnValueSerializer<'a> {
record: &'a Record<'a>,
key: Key,
serializer: &'a mut dyn Serializer,
done: bool,
}
impl PushFnValueSerializer<'_> {
#[deprecated(note = "Renamed to `emit`")]
pub fn serialize<'b, S: 'b + Value>(self, s: S) -> Result {
self.emit(s)
}
pub fn emit<'b, S: 'b + Value>(mut self, s: S) -> Result {
self.done = true;
#[cfg_attr(not(feature = "dynamic-keys"), allow(noop_method_call))]
s.serialize(self.record, self.key.clone(), self.serializer)
}
}
impl Drop for PushFnValueSerializer<'_> {
fn drop(&mut self) {
if !self.done {
#[cfg_attr(not(feature = "dynamic-keys"), allow(noop_method_call))]
let _ = self.serializer.emit_unit(self.key.clone());
}
}
}
#[must_use = "must be passed to logger to actually log"]
pub struct PushFnValue<F>(pub F)
where
F: 'static
+ for<'c, 'd> Fn(&'c Record<'d>, PushFnValueSerializer<'c>) -> Result;
impl<F> Value for PushFnValue<F>
where
F: 'static
+ for<'c, 'd> Fn(&'c Record<'d>, PushFnValueSerializer<'c>) -> Result,
{
fn serialize(
&self,
record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
let ser = PushFnValueSerializer {
record,
key,
serializer,
done: false,
};
(self.0)(record, ser)
}
}
#[cfg(has_std_error)]
#[doc(hidden)]
pub struct ErrorTagWrapper<E>(E);
#[cfg(has_std_error)]
#[test]
fn test_error_tag_wrapper() {
#[derive(Debug, Clone, Copy)]
struct MyError(&'static str);
impl core::fmt::Display for MyError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(self.0)
}
}
impl StdError for MyError {}
let e = MyError("everything is on fire");
assert_eq!(
{
#[allow(clippy::needless_borrow)]
(&&ErrorTagWrapper(e)).slog_error_kind()
},
ErrorValueTag
);
let e = &e;
assert_eq!((&&ErrorTagWrapper(e)).slog_error_kind(), ErrorRefTag);
}
#[cfg(has_std_error)]
#[doc(hidden)]
#[derive(Debug, PartialEq, Eq)]
pub struct ErrorValueTag;
#[cfg(has_std_error)]
impl ErrorValueTag {
pub fn wrap<E>(self, e: E) -> ErrorValue<E>
where
E: StdError,
{
ErrorValue(e)
}
}
#[cfg(has_std_error)]
#[doc(hidden)]
pub trait ErrorValueKind {
#[inline]
fn slog_error_kind(&self) -> ErrorValueTag {
ErrorValueTag
}
}
#[cfg(has_std_error)]
impl<E: StdError> ErrorValueKind for ErrorTagWrapper<E> {}
#[cfg(has_std_error)]
#[doc(hidden)]
#[derive(Debug, PartialEq, Eq)]
pub struct ErrorRefTag;
#[cfg(has_std_error)]
impl ErrorRefTag {
pub fn wrap<E>(self, e: &E) -> ErrorRef<'_, E>
where
E: ?Sized + 'static + StdError,
{
ErrorRef(e)
}
}
#[cfg(has_std_error)]
#[doc(hidden)]
pub trait ErrorRefKind {
#[inline]
fn slog_error_kind(self) -> ErrorRefTag
where
Self: Sized,
{
ErrorRefTag
}
}
#[cfg(has_std_error)]
impl<ERef> ErrorRefKind for &&ErrorTagWrapper<ERef>
where
ERef: core::ops::Deref,
ERef::Target: StdError,
{
}
#[cfg(has_std_error)]
#[must_use = "must be passed to logger to actually log"]
pub struct ErrorValue<E: StdError>(pub E);
#[cfg(has_std_error)]
impl<E> Value for ErrorValue<E>
where
E: 'static + StdError,
{
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, &self.0)
}
}
#[cfg(has_std_error)]
#[must_use = "must be passed to logger to actually log"]
pub struct ErrorRef<'a, E: ?Sized + StdError>(pub &'a E);
#[cfg(has_std_error)]
impl<E> Value for ErrorRef<'_, E>
where
E: 'static + StdError,
{
fn serialize(
&self,
_record: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_error(key, self.0)
}
}
#[cfg(feature = "nested-values")]
impl<T> Value for Serde<T>
where
T: serde::Serialize + Clone + Send + 'static,
{
fn serialize(
&self,
_: &Record<'_>,
key: Key,
serializer: &mut dyn Serializer,
) -> Result {
serializer.emit_serde(key, self)
}
}
pub trait KV {
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result;
}
impl<T> KV for &T
where
T: KV,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, serializer)
}
}
pub trait SendSyncRefUnwindSafeKV:
KV + maybe::Send + maybe::Sync + maybe::RefUnwindSafe
{
}
impl<T> SendSyncRefUnwindSafeKV for T where
T: KV + maybe::Send + maybe::Sync + maybe::RefUnwindSafe + ?Sized
{
}
#[must_use = "does nothing by itself"]
pub struct SingleKV<V>(pub Key, pub V)
where
V: Value;
#[cfg(feature = "dynamic-keys")]
impl<V: Value> From<(String, V)> for SingleKV<V> {
fn from(x: (String, V)) -> SingleKV<V> {
SingleKV(Key::from(x.0), x.1)
}
}
#[cfg(feature = "dynamic-keys")]
impl<V: Value> From<(&'static str, V)> for SingleKV<V> {
fn from(x: (&'static str, V)) -> SingleKV<V> {
SingleKV(Key::from(x.0), x.1)
}
}
#[cfg(not(feature = "dynamic-keys"))]
impl<V: Value> From<(&'static str, V)> for SingleKV<V> {
fn from(x: (&'static str, V)) -> SingleKV<V> {
SingleKV(x.0, x.1)
}
}
impl<V> KV for SingleKV<V>
where
V: Value,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
#[cfg_attr(not(feature = "dynamic-keys"), allow(noop_method_call))]
self.1.serialize(record, self.0.clone(), serializer)
}
}
impl KV for () {
fn serialize(
&self,
_record: &Record<'_>,
_serializer: &mut dyn Serializer,
) -> Result {
Ok(())
}
}
impl<T: KV, R: KV> KV for (T, R) {
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.0.serialize(record, serializer)?;
self.1.serialize(record, serializer)
}
}
impl<T> KV for Box<T>
where
T: KV + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, serializer)
}
}
impl<T> KV for Arc<T>
where
T: KV + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
(**self).serialize(record, serializer)
}
}
impl<T> KV for OwnedKV<T>
where
T: SendSyncRefUnwindSafeKV + ?Sized,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.0.serialize(record, serializer)
}
}
impl KV for BorrowedKV<'_> {
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.0.serialize(record, serializer)
}
}
#[must_use = "does nothing unless attached to logger"]
pub struct OwnedKV<T>(
#[doc(hidden)]
pub T,
)
where
T: SendSyncRefUnwindSafeKV + ?Sized;
#[must_use = "does nothing unless attached to logger"]
pub struct BorrowedKV<'a>(
#[doc(hidden)]
pub &'a dyn KV,
);
struct OwnedKVListNode<T>
where
T: SendSyncRefUnwindSafeKV + 'static,
{
next_node: Arc<dyn SendSyncRefUnwindSafeKV + 'static>,
kv: T,
}
struct MultiListNode {
next_node: Arc<dyn SendSyncRefUnwindSafeKV + 'static>,
node: Arc<dyn SendSyncRefUnwindSafeKV + 'static>,
}
#[derive(Clone)]
#[must_use = "does nothing unless attached to logger"]
pub struct OwnedKVList {
node: Arc<dyn SendSyncRefUnwindSafeKV + 'static>,
}
impl<T> KV for OwnedKVListNode<T>
where
T: SendSyncRefUnwindSafeKV + 'static,
{
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.kv.serialize(record, serializer)?;
self.next_node.serialize(record, serializer)?;
Ok(())
}
}
impl KV for MultiListNode {
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.next_node.serialize(record, serializer)?;
self.node.serialize(record, serializer)?;
Ok(())
}
}
impl KV for OwnedKVList {
fn serialize(
&self,
record: &Record<'_>,
serializer: &mut dyn Serializer,
) -> Result {
self.node.serialize(record, serializer)?;
Ok(())
}
}
impl fmt::Debug for OwnedKVList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "(")?;
let mut i = 0;
{
let mut as_str_ser = AsFmtSerializer(|key, _val| {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}", key)?;
i += 1;
Ok(())
});
let record_static = record_static!(Level::Trace, "");
self.node
.serialize(
&Record::new(
&record_static,
&format_args!(""),
BorrowedKV(&STATIC_TERMINATOR_UNIT),
),
&mut as_str_ser,
)
.map_err(|_| fmt::Error)?;
}
write!(f, ")")?;
Ok(())
}
}
impl OwnedKVList {
fn root<T>(values: OwnedKV<T>) -> Self
where
T: SendSyncRefUnwindSafeKV + 'static,
{
OwnedKVList {
node: Arc::new(OwnedKVListNode {
next_node: Arc::new(()),
kv: values.0,
}),
}
}
fn new<T>(
values: OwnedKV<T>,
next_node: Arc<dyn SendSyncRefUnwindSafeKV + 'static>,
) -> Self
where
T: SendSyncRefUnwindSafeKV + 'static,
{
OwnedKVList {
node: Arc::new(OwnedKVListNode {
next_node,
kv: values.0,
}),
}
}
}
impl<T> convert::From<OwnedKV<T>> for OwnedKVList
where
T: SendSyncRefUnwindSafeKV + 'static,
{
fn from(from: OwnedKV<T>) -> Self {
OwnedKVList::root(from)
}
}
#[derive(Debug)]
pub enum Error {
#[cfg(feature = "std")]
Io(std::io::Error),
Fmt(core::fmt::Error),
Other,
}
pub type Result<T = ()> = result::Result<T, Error>;
#[cfg(feature = "std")]
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)
}
}
impl From<core::fmt::Error> for Error {
fn from(_: core::fmt::Error) -> Error {
Error::Other
}
}
#[cfg(feature = "std")]
impl From<Error> for std::io::Error {
fn from(e: Error) -> std::io::Error {
match e {
Error::Io(e) => e,
Error::Fmt(_) => std::io::Error::new(
std::io::ErrorKind::Other,
"formatting error",
),
Error::Other => {
std::io::Error::new(std::io::ErrorKind::Other, "other error")
}
}
}
}
#[cfg(has_std_error)]
impl StdError for Error {
#[allow(deprecated)]
fn description(&self) -> &str {
match *self {
#[cfg(feature = "std")]
Error::Io(ref e) => e.description(),
Error::Fmt(_) => "formatting error",
Error::Other => "serialization error",
}
}
fn cause(&self) -> Option<&dyn StdError> {
match *self {
#[cfg(feature = "std")]
Error::Io(ref e) => Some(e),
Error::Fmt(ref e) => Some(e),
Error::Other => None,
}
}
}
impl core::fmt::Display for Error {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match *self {
#[cfg(feature = "std")]
Error::Io(ref e) => e.fmt(fmt),
Error::Fmt(ref e) => e.fmt(fmt),
Error::Other => fmt.write_str("Other serialization error"),
}
}
}
#[doc(hidden)]
pub type Never = core::convert::Infallible;
#[doc(hidden)]
pub static STATIC_TERMINATOR_UNIT: () = ();
#[allow(clippy::inline_always)]
#[inline(always)]
#[doc(hidden)]
pub fn __slog_static_max_level() -> FilterLevel {
if !cfg!(debug_assertions) {
if cfg!(feature = "release_max_level_off") {
return FilterLevel::Off;
} else if cfg!(feature = "release_max_level_error") {
return FilterLevel::Error;
} else if cfg!(feature = "release_max_level_warn") {
return FilterLevel::Warning;
} else if cfg!(feature = "release_max_level_info") {
return FilterLevel::Info;
} else if cfg!(feature = "release_max_level_debug") {
return FilterLevel::Debug;
} else if cfg!(feature = "release_max_level_trace") {
return FilterLevel::Trace;
}
}
if cfg!(feature = "max_level_off") {
FilterLevel::Off
} else if cfg!(feature = "max_level_error") {
FilterLevel::Error
} else if cfg!(feature = "max_level_warn") {
FilterLevel::Warning
} else if cfg!(feature = "max_level_info") {
FilterLevel::Info
} else if cfg!(feature = "max_level_debug") {
FilterLevel::Debug
} else if cfg!(feature = "max_level_trace") {
FilterLevel::Trace
} else if !cfg!(debug_assertions) {
FilterLevel::Info
} else {
FilterLevel::Debug
}
}
#[deprecated(note = "Renamed to `Value`")]
pub type Serialize = dyn Value;
#[deprecated(note = "Renamed to `PushFnValue`")]
pub type PushLazy<T> = PushFnValue<T>;
#[deprecated(note = "Renamed to `PushFnValueSerializer`")]
pub type ValueSerializer<'a> = PushFnValueSerializer<'a>;
#[deprecated(note = "Renamed to `OwnedKVList`")]
pub type OwnedKeyValueList = OwnedKVList;
#[deprecated(note = "Content of ser module moved to main namespace")]
pub mod ser {
#[allow(deprecated)]
pub use super::{
OwnedKeyValueList, PushLazy, Serialize, Serializer, ValueSerializer,
};
}
#[cfg(test)]
mod tests;