Skip to main content

context_logger/
context.rs

1//! Context builder for structured logging.
2
3use std::borrow::Cow;
4
5use crate::{LogValue, fields::LogFields};
6
7/// A set of fields that can be attached to a logging scope.
8///
9/// Fields are split into two categories:
10///
11/// - **local** - fields belonging only to the current scope. They do not propagate to child scopes.
12/// - **inherited** - fields that automatically flow into all child scopes created within the
13///   current scope.
14///
15/// Nested scopes resolution rules:
16///
17/// - child `inherited` overwrites parent `inherited` by key
18/// - inherited are emitted before local, so "last write wins" consumers see local shadowing
19#[derive(Debug, Default, Clone)]
20pub struct LogContext {
21    /// Fields belonging only to the current scope.
22    pub local: LogFields,
23    /// Fields that automatically flow into all child scopes created within the
24    /// current scope.
25    pub inherited: LogFields,
26}
27
28impl LogContext {
29    /// Creates a new, empty context.
30    #[must_use]
31    pub fn new() -> Self {
32        Self::default()
33    }
34
35    /// Adds a key-value field to the local fields of this context.
36    ///
37    /// See [`LogFields`] for more details about log fields.
38    #[must_use]
39    pub fn with_local_field(
40        mut self,
41        key: impl Into<Cow<'static, str>>,
42        value: impl Into<LogValue>,
43    ) -> Self {
44        self.local = self.local.with(key, value);
45        self
46    }
47
48    /// Adds a key-value pair to the inherited fields of this context.
49    ///
50    /// See [`LogFields`] for more details about log fields.
51    #[must_use]
52    pub fn with_inherited_field(
53        mut self,
54        key: impl Into<Cow<'static, str>>,
55        value: impl Into<LogValue>,
56    ) -> Self {
57        self.inherited = self.inherited.with(key, value);
58        self
59    }
60
61    /// Returns `true` if both local and inherited fields are empty.
62    #[must_use]
63    pub fn is_empty(&self) -> bool {
64        self.local.is_empty() && self.inherited.is_empty()
65    }
66}