@@ -262,6 +262,53 @@ impl Processor {
262262 }
263263 }
264264
265+ /// Called when the `SnapStart` restore phase starts.
266+ ///
267+ /// This is used to create a `snapstart_restore` span, since this telemetry event does not
268+ /// provide a `request_id`, we try to guess which invocation is the restore similar to init.
269+ pub fn on_platform_restore_start ( & mut self , time : DateTime < Utc > ) {
270+ let start_time: i64 = SystemTime :: from ( time)
271+ . duration_since ( UNIX_EPOCH )
272+ . expect ( "time went backwards" )
273+ . as_nanos ( )
274+ . try_into ( )
275+ . unwrap_or_default ( ) ;
276+
277+ // Get the closest context
278+ let Some ( context) = self . context_buffer . get_closest_mut ( start_time) else {
279+ debug ! ( "Cannot process on platform restore start, no invocation context found" ) ;
280+ return ;
281+ } ;
282+
283+ // Create a SnapStart restore span
284+ let mut snapstart_restore_span = create_empty_span (
285+ String :: from ( "aws.lambda.snapstart_restore" ) ,
286+ & self . resource ,
287+ & self . service ,
288+ ) ;
289+ snapstart_restore_span. span_id = generate_span_id ( ) ;
290+ snapstart_restore_span. start = start_time;
291+ context. snapstart_restore_span = Some ( snapstart_restore_span) ;
292+ }
293+
294+ /// Given the duration of the platform restore report, set the snapstart restore duration.
295+ ///
296+ #[ allow( clippy:: cast_possible_truncation) ]
297+ pub fn on_platform_restore_report ( & mut self , duration_ms : f64 , timestamp : i64 ) {
298+ self . enhanced_metrics
299+ . set_snapstart_restore_duration_metric ( duration_ms, timestamp) ;
300+
301+ let Some ( context) = self . context_buffer . get_closest_mut ( timestamp) else {
302+ debug ! ( "Cannot process on platform restore report, no invocation context found" ) ;
303+ return ;
304+ } ;
305+
306+ if let Some ( snapstart_restore_span) = & mut context. snapstart_restore_span {
307+ // `round` is intentionally meant to be a whole integer
308+ snapstart_restore_span. duration = ( duration_ms * MS_TO_NS ) as i64 ;
309+ }
310+ }
311+
265312 /// Given a `request_id` and the time of the platform start, add the start time to the context buffer.
266313 ///
267314 pub fn on_platform_start ( & mut self , request_id : String , time : DateTime < Utc > ) {
@@ -409,6 +456,14 @@ impl Processor {
409456 cold_start_span. parent_id = context. invocation_span . parent_id ;
410457 }
411458 }
459+
460+ // Handle snapstart restore span if present
461+ if let Some ( snapstart_restore_span) = & mut context. snapstart_restore_span {
462+ if context. invocation_span . trace_id != 0 {
463+ snapstart_restore_span. trace_id = context. invocation_span . trace_id ;
464+ snapstart_restore_span. parent_id = context. invocation_span . parent_id ;
465+ }
466+ }
412467 Some ( context. clone ( ) )
413468 }
414469
@@ -431,7 +486,14 @@ impl Processor {
431486 traces. push ( ws. clone ( ) ) ;
432487 }
433488
434- if let Some ( cold_start_span) = & context. cold_start_span {
489+ // SnapStart includes telemetry events from Init (Cold Start).
490+ // However, these Init events are from when the snapshot was created and
491+ // not when the lambda sandbox is actually created.
492+ // So, if we have a snapstart restore span, use it instead of cold start span.
493+ if let Some ( snapstart_restore_span) = & context. snapstart_restore_span {
494+ body_size += std:: mem:: size_of_val ( snapstart_restore_span) ;
495+ traces. push ( snapstart_restore_span. clone ( ) ) ;
496+ } else if let Some ( cold_start_span) = & context. cold_start_span {
435497 body_size += std:: mem:: size_of_val ( cold_start_span) ;
436498 traces. push ( cold_start_span. clone ( ) ) ;
437499 }
0 commit comments