Skip to main content

context_logger/
value.rs

1//! Value types for the context logger.
2
3use std::sync::Arc;
4
5/// A sized, cloneable wrapper around `Arc<dyn erased_serde::Serialize>` that implements
6/// `serde::Serialize`. This is needed because `log::kv::Value::from_serde` requires `T: Sized`,
7/// but `dyn erased_serde::Serialize` is unsized.
8#[derive(Clone)]
9struct SerdeArc(Arc<dyn erased_serde::Serialize + Send + Sync + 'static>);
10
11impl SerdeArc {
12    fn new<T>(value: T) -> Self
13    where
14        T: serde::Serialize + Send + Sync + 'static,
15    {
16        Self(Arc::new(value))
17    }
18}
19
20impl serde::Serialize for SerdeArc {
21    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
22        erased_serde::serialize(&*self.0, serializer)
23    }
24}
25
26/// Represents a value that can be stored in a log field.
27///
28/// The `LogValue` type is a flexible container designed to hold various kinds of data
29/// that can be associated with a log entry. It supports primitive types, strings, and
30/// more complex types such as those implementing [`std::fmt::Debug`], [`std::fmt::Display`],
31/// [`std::error::Error`], or `serde::Serialize`.
32///
33/// This allows for rich and structured logging, enabling developers to attach meaningful
34/// context to log messages.
35///
36/// # Examples
37///
38/// ```
39/// use context_logger::LogValue;
40///
41/// let value = LogValue::display("example string");
42/// let number = LogValue::from(42);
43/// let debug_value = LogValue::debug(vec![1, 2, 3]);
44/// ```
45#[derive(Clone)]
46pub struct LogValue(LogValueInner);
47
48#[derive(Clone)]
49enum LogValueInner {
50    Null,
51    String(String),
52    Bool(bool),
53    Char(char),
54    I64(i64),
55    U64(u64),
56    F64(f64),
57    I128(i128),
58    U128(u128),
59    Debug(Arc<dyn std::fmt::Debug + Send + Sync + 'static>),
60    Display(Arc<dyn std::fmt::Display + Send + Sync + 'static>),
61    Error(Arc<dyn std::error::Error + Send + Sync + 'static>),
62    Serde(SerdeArc),
63}
64
65impl From<LogValueInner> for LogValue {
66    fn from(inner: LogValueInner) -> Self {
67        Self(inner)
68    }
69}
70
71impl LogValue {
72    /// Creates a null log value.
73    #[allow(clippy::must_use_candidate)]
74    pub fn null() -> Self {
75        LogValueInner::Null.into()
76    }
77
78    /// Creates a log value from a [`serde::Serialize`].
79    pub fn serde<S>(value: S) -> Self
80    where
81        S: serde::Serialize + Send + Sync + 'static,
82    {
83        LogValueInner::Serde(SerdeArc::new(value)).into()
84    }
85
86    /// Creates a log value from a [`std::fmt::Display`].
87    pub fn display<T>(value: T) -> Self
88    where
89        T: std::fmt::Display + Send + Sync + 'static,
90    {
91        LogValueInner::Display(Arc::new(value)).into()
92    }
93
94    /// Creates a log value from a [`std::fmt::Debug`].
95    pub fn debug<T>(value: T) -> Self
96    where
97        T: std::fmt::Debug + Send + Sync + 'static,
98    {
99        LogValueInner::Debug(Arc::new(value)).into()
100    }
101
102    /// Creates a log value from a [`std::error::Error`].
103    pub fn error<T>(value: T) -> Self
104    where
105        T: std::error::Error + Send + Sync + 'static,
106    {
107        LogValueInner::Error(Arc::new(value)).into()
108    }
109
110    /// Converts the log value to a value compatible with the [`log`] crate.
111    #[must_use]
112    pub fn as_log_value(&self) -> log::kv::Value<'_> {
113        match &self.0 {
114            LogValueInner::Null => log::kv::Value::null(),
115            LogValueInner::String(s) => log::kv::Value::from(&**s),
116            LogValueInner::Bool(b) => log::kv::Value::from(*b),
117            LogValueInner::Char(c) => log::kv::Value::from(*c),
118            LogValueInner::I64(i) => log::kv::Value::from(*i),
119            LogValueInner::U64(u) => log::kv::Value::from(*u),
120            LogValueInner::F64(f) => log::kv::Value::from(*f),
121            LogValueInner::I128(i) => log::kv::Value::from(*i),
122            LogValueInner::U128(u) => log::kv::Value::from(*u),
123            LogValueInner::Display(value) => log::kv::Value::from_dyn_display(&**value),
124            LogValueInner::Debug(value) => log::kv::Value::from_dyn_debug(&**value),
125            LogValueInner::Error(value) => log::kv::Value::from_dyn_error(&**value),
126            LogValueInner::Serde(value) => log::kv::Value::from_serde(value),
127        }
128    }
129}
130
131macro_rules! impl_log_value_from_primitive {
132    ($($ty:ty => $arm:ident),*) => {
133        $(
134            impl From<$ty> for LogValue {
135                fn from(value: $ty) -> Self {
136                    LogValue(LogValueInner::$arm(value.into()))
137                }
138            }
139        )*
140    };
141}
142
143impl_log_value_from_primitive!(
144    bool => Bool,
145    char => Char,
146    &str => String,
147    std::borrow::Cow<'_, str> => String,
148    String => String,
149    i8 => I64,
150    i16 => I64,
151    i32 => I64,
152    i64 => I64,
153    u8 => U64,
154    u16 => U64,
155    u32 => U64,
156    u64 => U64,
157    f32 => F64,
158    f64 => F64,
159    i128 => I128,
160    u128 => U128
161);
162
163impl std::fmt::Display for LogValue {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        self.as_log_value().fmt(f)
166    }
167}
168
169impl std::fmt::Debug for LogValue {
170    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
171        self.as_log_value().fmt(f)
172    }
173}