Skip to main content

context_logger/
context.rs

1//! Context builder for structured logging.
2
3use std::borrow::Cow;
4
5use crate::{LogValue, records::LogRecords};
6
7/// A set of records that can be attached to a logging scope.
8///
9/// Records are split into two categories:
10///
11/// - **local** - records belonging only to the current scope.
12///   They do not propagate to child scopes.
13/// - **inherited** - records that automatically flow into all child scopes created within the 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    /// Records belonging only to the current scope.
22    pub local: LogRecords,
23    /// Records that automatically flow into all child scopes created within the current scope.
24    pub inherited: LogRecords,
25}
26
27impl LogContext {
28    /// Creates a new, empty context.
29    #[must_use]
30    pub fn new() -> Self {
31        Self::default()
32    }
33
34    /// Adds a key-value record to the local records of this context.
35    ///
36    /// See [`LogRecords`] for more details about log records.
37    #[must_use]
38    pub fn with_local_record(
39        mut self,
40        key: impl Into<Cow<'static, str>>,
41        value: impl Into<LogValue>,
42    ) -> Self {
43        self.local = self.local.field(key, value);
44        self
45    }
46
47    /// Adds a key-value record to the inherited records of this context.
48    ///
49    /// See [`LogRecords`] for more details about log records.
50    #[must_use]
51    pub fn with_inherited_record(
52        mut self,
53        key: impl Into<Cow<'static, str>>,
54        value: impl Into<LogValue>,
55    ) -> Self {
56        self.inherited = self.inherited.field(key, value);
57        self
58    }
59
60    /// Returns `true` if both local and inherited records are empty.
61    #[must_use]
62    pub fn is_empty(&self) -> bool {
63        self.local.is_empty() && self.inherited.is_empty()
64    }
65}