1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! # dcontext-tracing
//!
//! Automatic [dcontext](https://docs.rs/dcontext) scope management via
//! [tracing](https://docs.rs/tracing) spans.
//!
//! This crate provides a [`tracing_subscriber::Layer`] that automatically
//! creates and manages dcontext scopes when tracing spans are entered and
//! exited. This means your context values follow the natural span lifecycle
//! without any manual scope management.
//!
//! ## Quick Start
//!
//! ```rust,no_run
//! use tracing_subscriber::prelude::*;
//!
//! // Zero-config: every span creates a dcontext scope
//! tracing_subscriber::registry()
//! .with(dcontext_tracing::DcontextLayer::new())
//! .init();
//! ```
//!
//! ## Features
//!
//! ### Level 1: Automatic Scoping
//!
//! With zero configuration, `DcontextLayer` creates a new dcontext scope
//! every time a span is entered. Values set inside a span are automatically
//! cleaned up when the span exits, just like tracing's own span lifecycle.
//!
//! ```rust,no_run
//! # use tracing_subscriber::prelude::*;
//! # tracing_subscriber::registry()
//! # .with(dcontext_tracing::DcontextLayer::new())
//! # .init();
//! #
//! // Register context keys, then inside a span:
//! // dcontext::sync_ctx::set_context("user", "alice".to_string());
//! // {
//! // let _span = tracing::info_span!("request").entered();
//! // // New scope created — inherits parent values
//! // dcontext::sync_ctx::set_context("request_id", "abc-123".to_string());
//! // }
//! // Scope reverted — "request_id" gone, "user" remains
//! ```
//!
//! ### Level 2: Field-to-Context Extraction
//!
//! Extract tracing span fields directly into dcontext values using
//! [`TracingField`] metadata:
//!
//! ```rust,no_run
//! use dcontext_tracing::{DcontextLayer, TracingField};
//!
//! #[derive(Clone, Default, Debug, serde::Serialize, serde::Deserialize)]
//! struct RequestId(String);
//!
//! impl std::fmt::Display for RequestId {
//! fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//! write!(f, "{}", self.0)
//! }
//! }
//!
//! let mut builder = dcontext::RegistryBuilder::new();
//! builder.register_with::<RequestId>("request_id", |opts| {
//! opts.with_metadata(
//! TracingField::builder("request_id")
//! .extract_from_str(|s| Some(RequestId(s.to_string())))
//! .enrich_display::<RequestId>() // enables both log + span enrichment
//! .build(),
//! )
//! });
//!
//! // DcontextLayer discovers TracingField metadata automatically.
//! // On span enter:
//! // - Extracts span fields into context (extract direction)
//! // - Records context values into pre-declared Empty span fields (span record direction)
//! // let layer = DcontextLayer::new();
//! ```
//!
//! ### Level 3: Span Info
//!
//! Expose span metadata as a context value:
//!
//! ```rust,no_run
//! use dcontext_tracing::{DcontextLayer, SpanInfo};
//! use tracing_subscriber::Registry;
//!
//! let layer: DcontextLayer<Registry> = DcontextLayer::builder()
//! .include_span_info()
//! .build();
//!
//! // Inside a span:
//! // let info: SpanInfo = dcontext::sync_ctx::get_context("dcontext.span").unwrap_or_default();
//! // info.name, info.target, info.level
//! ```
//!
//! ## How It Works
//!
//! The layer uses a thread-local stack to store dcontext `ScopeGuard`s
//! (which are `!Send` and cannot be stored in tracing's span extensions).
//! On span enter, a new scope is pushed; on span exit, the scope is popped
//! and the guard dropped, reverting context changes made in that scope.
//!
//! This mirrors the approach used by `tracing-opentelemetry` for similar
//! thread-local guard management.
//!
//! ## Async Behavior
//!
//! Tokio async code should use [`AsyncDcontextLayer`], which stores span state
//! in `dcontext::async_ctx` task-local storage so mapped values, span info, and
//! scope chain entries persist across `.await` points in the task.
//!
//! [`SyncDcontextLayer`] (and the legacy [`DcontextLayer`] alias) remain useful
//! for synchronous or explicitly thread-local code. `dcontext::sync_ctx` always uses
//! thread-local storage directly, so no `force_thread_local()` wrapper is needed.
pub
pub use ;
pub use ;
/// Type alias for backward compatibility — `DcontextLayer` is now `SyncDcontextLayer`.
pub type DcontextLayer<S> = ;
/// Type alias for backward compatibility — `DcontextLayerBuilder` is now `SyncDcontextLayerBuilder`.
pub type DcontextLayerBuilder<S> = ;
pub use ;
pub use ;