@@ -21,21 +21,23 @@ type BoxFuture<T> = std::pin::Pin<Box<dyn std::future::Future<Output = T> + Send
2121pub struct Config {
2222 /// Service name. Overrides `DD_SERVICE`. Ignored when [`tracing`](Self::tracing) is `Some`.
2323 pub service : Option < String > ,
24- /// Deployment environment. Overrides `DD_ENV`. Ignored when [`tracing`](Self::tracing) is `Some`.
24+ /// Deployment environment. Overrides `DD_ENV`. Ignored when [`tracing`](Self::tracing) is
25+ /// `Some`.
2526 pub env : Option < String > ,
2627 /// Service version. Overrides `DD_VERSION`. Ignored when [`tracing`](Self::tracing) is `Some`.
2728 pub version : Option < String > ,
2829 /// Full control over the OTel SDK and Datadog tracer config.
2930 ///
30- /// When `None` (default), Lambda-appropriate defaults are applied and `service`/`env`/`version`
31- /// above are forwarded. When `Some`, the builder is used as-is; `service`/`env`/`version` are
32- /// ignored and you are responsible for setting:
33- /// - `trace_stats_computation_enabled = false` (the Datadog agent handles stats for serverless environments)
34- /// - `trace_writer_synchronous_write = true` (so `force_flush()` blocks until spans reach agent)
31+ /// When `None` (default), Lambda-appropriate defaults are applied and
32+ /// `service`/`env`/`version` above are forwarded. When `Some`, the builder is used as-is;
33+ /// `service`/`env`/`version` are ignored and you are responsible for setting:
34+ /// - `trace_stats_computation_enabled = false` (the Datadog agent handles stats for serverless
35+ /// environments)
36+ /// - `trace_writer_synchronous_write = true` (so `force_flush()` blocks until spans reach
37+ /// agent)
3538 pub tracing : Option < datadog_opentelemetry:: DatadogTracingBuilder > ,
3639}
3740
38-
3941fn build_tracing (
4042 service : Option < String > ,
4143 env : Option < String > ,
@@ -98,23 +100,32 @@ fn build_tracing(
98100pub struct WrappedHandler < F , E , R > {
99101 inner : Arc < F > ,
100102 provider : opentelemetry_sdk:: trace:: SdkTracerProvider ,
101- config : Arc < Config > ,
103+ cold_start : bool ,
102104 _phantom : PhantomData < fn ( E ) -> R > ,
103105}
104106
105107impl < F , E , R > WrappedHandler < F , E , R > {
106108 pub fn new ( handler : F , config : Config ) -> Self {
107- let Config { tracing, service, env, version } = config;
109+ let Config {
110+ tracing,
111+ service,
112+ env,
113+ version,
114+ } = config;
108115 let provider = tracing
109116 . unwrap_or_else ( || build_tracing ( service, env, version) )
110117 . init ( ) ;
111118 Self {
112119 inner : Arc :: new ( handler) ,
113120 provider,
114- config : Arc :: new ( Config :: default ( ) ) ,
121+ cold_start : true ,
115122 _phantom : PhantomData ,
116123 }
117124 }
125+
126+ fn take_cold_start ( & mut self ) -> bool {
127+ std:: mem:: replace ( & mut self . cold_start , false )
128+ }
118129}
119130
120131impl < F , Fut , E , R > Service < LambdaEvent < Value > > for WrappedHandler < F , E , R >
@@ -133,18 +144,58 @@ where
133144 }
134145
135146 fn call ( & mut self , event : LambdaEvent < Value > ) -> Self :: Future {
147+ let cold_start = self . take_cold_start ( ) ;
136148 let inner_handler = Arc :: clone ( & self . inner ) ;
137149 let provider = self . provider . clone ( ) ;
138- let lambda_config = Arc :: clone ( & self . config ) ;
139- let ( lambda_span, inferred_spans) = start_invocation ( & event, & provider, & lambda_config) ;
150+ let ( lambda_span, inferred_spans) = start_invocation ( & event, & provider, cold_start) ;
140151 let typed_payload = match serde_json:: from_value :: < E > ( event. payload ) {
141152 Ok ( payload) => payload,
142153 Err ( err) => {
143- return Box :: pin ( run_handler ( lambda_span, inferred_spans, provider, std:: future:: ready ( Err ( err. into ( ) ) ) ) ) ;
154+ return Box :: pin ( run_handler (
155+ lambda_span,
156+ inferred_spans,
157+ provider,
158+ std:: future:: ready ( Err ( err. into ( ) ) ) ,
159+ ) ) ;
144160 }
145161 } ;
146162 let typed_event = LambdaEvent :: new ( typed_payload, event. context ) ;
147163 let fut = inner_handler ( typed_event) ;
148164 Box :: pin ( async move { run_handler ( lambda_span, inferred_spans, provider, fut) . await } )
149165 }
150166}
167+
168+ #[ cfg( test) ]
169+ mod tests {
170+ use super :: * ;
171+
172+ fn noop_handler (
173+ _: LambdaEvent < Value > ,
174+ ) -> std:: future:: Ready < Result < ( ) , lambda_runtime:: Error > > {
175+ std:: future:: ready ( Ok ( ( ) ) )
176+ }
177+
178+ fn test_handler ( ) -> WrappedHandler <
179+ fn ( LambdaEvent < Value > ) -> std:: future:: Ready < Result < ( ) , lambda_runtime:: Error > > ,
180+ Value ,
181+ ( ) ,
182+ > {
183+ WrappedHandler {
184+ inner : Arc :: new ( noop_handler) ,
185+ provider : opentelemetry_sdk:: trace:: SdkTracerProvider :: builder ( ) . build ( ) ,
186+ cold_start : true ,
187+ _phantom : PhantomData ,
188+ }
189+ }
190+
191+ #[ test]
192+ fn cold_start_is_tracked_per_handler ( ) {
193+ let mut first = test_handler ( ) ;
194+ assert ! ( first. take_cold_start( ) ) ;
195+ assert ! ( !first. take_cold_start( ) ) ;
196+
197+ let mut second = test_handler ( ) ;
198+ assert ! ( second. take_cold_start( ) ) ;
199+ assert ! ( !second. take_cold_start( ) ) ;
200+ }
201+ }
0 commit comments