@@ -18,6 +18,7 @@ use crate::engine::runtime::{get_runtime, is_runtime_shutdown};
1818const SCARF_BASE : & str = "https://cocoindex.gateway.scarf.sh" ;
1919const REQUEST_TIMEOUT : Duration = Duration :: from_secs ( 5 ) ;
2020const DISABLE_ENV : & str = "COCOINDEX_DISABLE_USAGE_TRACKING" ;
21+ const APPLICATION_ENV : & str = "COCOINDEX_APPLICATION_FOR_TRACKING" ;
2122
2223static TELEMETRY : OnceLock < TelemetryContext > = OnceLock :: new ( ) ;
2324
@@ -26,13 +27,16 @@ struct TelemetryContext {
2627 base_url : String ,
2728 platform : String ,
2829 lang : String ,
30+ application : Option < String > ,
2931}
3032
3133#[ derive( Serialize ) ]
3234struct EventPayload < ' a > {
3335 event : & ' a str ,
3436 platform : & ' a str ,
3537 lang : & ' a str ,
38+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
39+ application : Option < & ' a str > ,
3640}
3741
3842/// Initialize telemetry. No-op in debug builds, no-op if
@@ -80,9 +84,16 @@ fn build_context(package_id: String, lang: String) -> Option<TelemetryContext> {
8084 base_url : format ! ( "{SCARF_BASE}/{package_id}" ) ,
8185 platform : current_platform ( ) ,
8286 lang,
87+ application : read_application_env ( ) ,
8388 } )
8489}
8590
91+ fn read_application_env ( ) -> Option < String > {
92+ std:: env:: var ( APPLICATION_ENV )
93+ . ok ( )
94+ . filter ( |v| !v. is_empty ( ) )
95+ }
96+
8697fn current_platform ( ) -> String {
8798 format ! ( "{}-{}" , std:: env:: consts:: ARCH , std:: env:: consts:: OS )
8899}
@@ -103,6 +114,7 @@ async fn send_event(ctx: &TelemetryContext, event: &'static str) {
103114 event,
104115 platform : & ctx. platform ,
105116 lang : & ctx. lang ,
117+ application : ctx. application . as_deref ( ) ,
106118 } ;
107119 let result = ctx
108120 . client
@@ -183,11 +195,21 @@ mod tests {
183195 }
184196
185197 fn make_test_ctx ( base_url : String , lang : String , timeout : Duration ) -> TelemetryContext {
198+ make_test_ctx_with_application ( base_url, lang, timeout, None )
199+ }
200+
201+ fn make_test_ctx_with_application (
202+ base_url : String ,
203+ lang : String ,
204+ timeout : Duration ,
205+ application : Option < String > ,
206+ ) -> TelemetryContext {
186207 TelemetryContext {
187208 client : reqwest:: Client :: builder ( ) . timeout ( timeout) . build ( ) . unwrap ( ) ,
188209 base_url,
189210 platform : current_platform ( ) ,
190211 lang,
212+ application,
191213 }
192214 }
193215
@@ -210,6 +232,24 @@ mod tests {
210232 assert_eq ! ( body[ "event" ] , "app_create" ) ;
211233 assert_eq ! ( body[ "lang" ] , "python3.11" ) ;
212234 assert_eq ! ( body[ "platform" ] , current_platform( ) ) ;
235+ assert ! ( body. get( "application" ) . is_none( ) ) ;
236+ }
237+
238+ #[ tokio:: test]
239+ async fn send_event_includes_application_when_set ( ) {
240+ let ( addr, recorded) = spawn_mock_server ( StatusCode :: OK ) . await ;
241+ let ctx = make_test_ctx_with_application (
242+ format ! ( "http://{addr}/python-1.0.0a1" ) ,
243+ "python3.11" . to_string ( ) ,
244+ Duration :: from_secs ( 5 ) ,
245+ Some ( "my-app" . to_string ( ) ) ,
246+ ) ;
247+
248+ send_event ( & ctx, "app_create" ) . await ;
249+
250+ let recs = recorded. lock ( ) . unwrap ( ) . clone ( ) ;
251+ assert_eq ! ( recs. len( ) , 1 ) ;
252+ assert_eq ! ( recs[ 0 ] . body[ "application" ] , "my-app" ) ;
213253 }
214254
215255 #[ tokio:: test]
0 commit comments