11use std:: sync:: Arc ;
22
3- use chrono:: { DateTime , Utc } ;
43use futures_util:: lock:: Mutex ;
54use serde:: { Serialize , Serializer , ser:: SerializeMap } ;
65
6+ // Timestamp abstraction to support both chrono and jiff
7+ #[ cfg( all( feature = "jiff-0_2" , not( feature = "chrono" ) ) ) ]
8+ use jiff:: Timestamp ;
9+ #[ cfg( feature = "chrono" ) ]
10+ use chrono:: { DateTime , Utc } ;
11+
712use crate :: {
813 Response , ServerResult , Value ,
914 extensions:: {
@@ -12,13 +17,56 @@ use crate::{
1217 value,
1318} ;
1419
20+ // Type alias for timestamp type based on enabled features
21+ #[ cfg( all( feature = "jiff-0_2" , not( feature = "chrono" ) ) ) ]
22+ type TimestampType = Timestamp ;
23+ #[ cfg( feature = "chrono" ) ]
24+ type TimestampType = DateTime < Utc > ;
25+
26+ // Helper functions to abstract timestamp operations
27+ #[ cfg( all( feature = "jiff-0_2" , not( feature = "chrono" ) ) ) ]
28+ mod timestamp_ops {
29+ use jiff:: Timestamp ;
30+
31+ pub fn now ( ) -> Timestamp {
32+ Timestamp :: now ( )
33+ }
34+
35+ pub fn to_rfc3339 ( ts : & Timestamp ) -> String {
36+ ts. to_string ( )
37+ }
38+
39+ pub fn duration_nanos ( start : & Timestamp , end : & Timestamp ) -> Option < i64 > {
40+ let duration = end. duration_since ( * start) ;
41+ // SignedDuration::as_nanos() returns i128, convert to i64
42+ duration. as_nanos ( ) . try_into ( ) . ok ( )
43+ }
44+ }
45+
46+ #[ cfg( feature = "chrono" ) ]
47+ mod timestamp_ops {
48+ use chrono:: { DateTime , Utc } ;
49+
50+ pub fn now ( ) -> DateTime < Utc > {
51+ Utc :: now ( )
52+ }
53+
54+ pub fn to_rfc3339 ( ts : & DateTime < Utc > ) -> String {
55+ ts. to_rfc3339 ( )
56+ }
57+
58+ pub fn duration_nanos ( start : & DateTime < Utc > , end : & DateTime < Utc > ) -> Option < i64 > {
59+ ( * end - * start) . num_nanoseconds ( )
60+ }
61+ }
62+
1563struct ResolveState {
1664 path : Vec < String > ,
1765 field_name : String ,
1866 parent_type : String ,
1967 return_type : String ,
20- start_time : DateTime < Utc > ,
21- end_time : DateTime < Utc > ,
68+ start_time : TimestampType ,
69+ end_time : TimestampType ,
2270 start_offset : i64 ,
2371}
2472
@@ -32,7 +80,7 @@ impl Serialize for ResolveState {
3280 map. serialize_entry ( "startOffset" , & self . start_offset ) ?;
3381 map. serialize_entry (
3482 "duration" ,
35- & ( self . end_time - self . start_time ) . num_nanoseconds ( ) ,
83+ & timestamp_ops :: duration_nanos ( & self . start_time , & self . end_time ) ,
3684 ) ?;
3785 map. end ( )
3886 }
@@ -53,17 +101,17 @@ impl ExtensionFactory for ApolloTracing {
53101 fn create ( & self ) -> Arc < dyn Extension > {
54102 Arc :: new ( ApolloTracingExtension {
55103 inner : Mutex :: new ( Inner {
56- start_time : Utc :: now ( ) ,
57- end_time : Utc :: now ( ) ,
104+ start_time : timestamp_ops :: now ( ) ,
105+ end_time : timestamp_ops :: now ( ) ,
58106 resolves : Default :: default ( ) ,
59107 } ) ,
60108 } )
61109 }
62110}
63111
64112struct Inner {
65- start_time : DateTime < Utc > ,
66- end_time : DateTime < Utc > ,
113+ start_time : TimestampType ,
114+ end_time : TimestampType ,
67115 resolves : Vec < ResolveState > ,
68116}
69117
@@ -79,21 +127,21 @@ impl Extension for ApolloTracingExtension {
79127 operation_name : Option < & str > ,
80128 next : NextExecute < ' _ > ,
81129 ) -> Response {
82- self . inner . lock ( ) . await . start_time = Utc :: now ( ) ;
130+ self . inner . lock ( ) . await . start_time = timestamp_ops :: now ( ) ;
83131 let resp = next. run ( ctx, operation_name) . await ;
84132
85133 let mut inner = self . inner . lock ( ) . await ;
86- inner. end_time = Utc :: now ( ) ;
134+ inner. end_time = timestamp_ops :: now ( ) ;
87135 inner
88136 . resolves
89137 . sort_by ( |a, b| a. start_offset . cmp ( & b. start_offset ) ) ;
90138 resp. extension (
91139 "tracing" ,
92140 value ! ( {
93141 "version" : 1 ,
94- "startTime" : inner. start_time. to_rfc3339 ( ) ,
95- "endTime" : inner. end_time. to_rfc3339 ( ) ,
96- "duration" : ( inner. end_time - inner. start_time ) . num_nanoseconds ( ) ,
142+ "startTime" : timestamp_ops :: to_rfc3339 ( & inner. start_time) ,
143+ "endTime" : timestamp_ops :: to_rfc3339 ( & inner. end_time) ,
144+ "duration" : timestamp_ops :: duration_nanos ( & inner. start_time , & inner. end_time ) ,
97145 "execution" : {
98146 "resolvers" : inner. resolves
99147 }
@@ -111,13 +159,13 @@ impl Extension for ApolloTracingExtension {
111159 let field_name = info. path_node . field_name ( ) . to_string ( ) ;
112160 let parent_type = info. parent_type . to_string ( ) ;
113161 let return_type = info. return_type . to_string ( ) ;
114- let start_time = Utc :: now ( ) ;
115- let start_offset = ( start_time - self . inner . lock ( ) . await . start_time )
116- . num_nanoseconds ( )
117- . unwrap ( ) ;
162+ let start_time = timestamp_ops :: now ( ) ;
163+ let query_start_time = self . inner . lock ( ) . await . start_time ;
164+ let start_offset = timestamp_ops :: duration_nanos ( & query_start_time , & start_time )
165+ . unwrap_or ( 0 ) ;
118166
119167 let res = next. run ( ctx, info) . await ;
120- let end_time = Utc :: now ( ) ;
168+ let end_time = timestamp_ops :: now ( ) ;
121169
122170 self . inner . lock ( ) . await . resolves . push ( ResolveState {
123171 path,
0 commit comments