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